This commit is contained in:
2025-05-13 02:03:18 +03:00
parent 72860c7968
commit 90ef6120fd
463 changed files with 380758 additions and 2 deletions
+1
View File
@@ -0,0 +1 @@
/build
+15
View File
@@ -0,0 +1,15 @@
[submodule "Dependencies/LFramework.CMake"]
path = Dependencies/LFramework.CMake
url = https://github.com/L-proger/LFramework.CMake.git
[submodule "Dependencies/LFramework"]
path = Dependencies/LFramework
url = https://github.com/L-proger/LFramework.git
[submodule "Dependencies/SoftGL"]
path = Dependencies/SoftGL
url = https://github.com/L-proger/SoftGL.git
[submodule "Dependencies/LMath"]
path = Dependencies/LMath
url = https://github.com/L-proger/LMath.git
[submodule "Dependencies/LibPad"]
path = Dependencies/LibPad
url = https://github.com/L-proger/LibPad.git
+20
View File
@@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"cwd": "${workspaceRoot}",
"executable": "${command:cmake.launchTargetPath}",
"request": "launch",
"type": "cortex-debug",
"servertype": "jlink",
"device": "STM32H743VG",
"svdFile": "${workspaceRoot}/Platform/STM32H7x3.svd",
//"preLaunchTask": "BuildProject",
}
]
}
+98
View File
@@ -0,0 +1,98 @@
{
"files.associations": {
"stdio.h": "c",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"map": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"typeinfo": "cpp",
"freertos.h": "c",
"task.h": "c",
"stm32f7xx_ll_bus.h": "c",
"numbers": "cpp",
"semaphore": "cpp",
"xstring": "cpp",
"span": "cpp",
"charconv": "cpp",
"list": "cpp",
"set": "cpp",
"unordered_set": "cpp",
"format": "cpp",
"text_encoding": "cpp",
"variant": "cpp",
"ios": "cpp",
"locale": "cpp",
"queue": "cpp",
"stack": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
}
}
+65
View File
@@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.16)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/LFramework.CMake/stm32_gcc.cmake)
project(sandbox CXX C ASM)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Dependencies/LFramework.CMake/stm32)
set(STM32_DEVICE STM32H743VGT6)
add_executable(MicroH7BoardFirmware)
include(H7)
add_subdirectory(Dependencies/SoftGL)
add_subdirectory(Dependencies/LMath)
add_subdirectory(Dependencies/LibPad)
add_subdirectory(Dependencies/LFramework)
add_subdirectory(Platform)
target_link_libraries(MicroH7BoardFirmware
PRIVATE
STM32::H7
SoftGL
LMath
LibPad
LFramework
Platform
LFramework::IO
LFramework::IO::Terminal
)
target_include_directories(MicroH7BoardFirmware
PRIVATE
./
)
target_sources(MicroH7BoardFirmware
PRIVATE
fatfs.h
fatfs.c
SwapChain.h
SwapChain.cpp
main.cpp
ili9325_registers.h
ili9325.h
display_fsmc_interface.h
sdcard.h
sdcard.c
ffconf.h
user_diskio.c
user_diskio.h
UartReader.h
UartReader.cpp
EscController.h
DshotProtocol.h
)
gcc_print_target_size( MicroH7BoardFirmware )
+62
View File
@@ -0,0 +1,62 @@
#pragma once
struct Color16 {
static constexpr std::uint8_t MaxRed = 0x1f;
static constexpr std::uint8_t MaxGreen = 0x3f;
static constexpr std::uint8_t MaxBlue = 0x1f;
constexpr Color16() : value(0){}
constexpr Color16(std::uint16_t v) : value(v){}
static constexpr Color16 red() {
Color16 result;
result.r(MaxRed);
result.g(0);
result.b(0);
return result;
}
static constexpr Color16 green() {
Color16 result;
result.r(0);
result.g(MaxGreen);
result.b(0);
return result;
}
static constexpr Color16 blue() {
Color16 result;
result.r(0);
result.g(0);
result.b(MaxBlue);
return result;
}
static constexpr Color16 white() {
Color16 result;
result.r(MaxRed);
result.g(MaxGreen);
result.b(MaxBlue);
return result;
}
std::uint16_t value;
constexpr std::uint8_t r() const{
return (value & 0xf800) >> 11;
}
constexpr std::uint8_t g() const{
return (value & 0x7e0) >> 5;
}
constexpr std::uint8_t b() const{
return (value & 0x1f);
}
constexpr void r(std::uint8_t v){
value = (value & ~0xf800) | (v << 11);
}
constexpr void g(std::uint8_t v){
value = (value & ~0x7e0) | (v << 5);
}
constexpr void b(std::uint8_t v){
value = (value & ~0x1f) | (v);
}
};
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Sergey Serb
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+1
View File
@@ -0,0 +1 @@
# LFramework.CMake
+10
View File
@@ -0,0 +1,10 @@
find_program(nuget "nuget" REQUIRED)
function(nugetRestore)
execute_process(
COMMAND "${nuget}" "restore" "-PackagesDirectory" "${CMAKE_SOURCE_DIR}/packages"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
#nuget restore -PackagesDirectory ./packages
endfunction()
+40
View File
@@ -0,0 +1,40 @@
set(MCU_ARCH cortex-m7)
set(MCU_FLOAT_ABI softfp)
set(MCU_FPU fpv4-sp-d16)
set(COMMON_COMPILE_FLAGS -mcpu=${MCU_ARCH} -mthumb -mfloat-abi=${MCU_FLOAT_ABI} -mfpu=${MCU_FPU})
set(C_CXX_COMPILE_FLAGS -ffunction-sections -fdata-sections -fsigned-char -g -fmessage-length=0)
if(NOT (TARGET STM32::F7))
add_library(STM32::F7 INTERFACE IMPORTED)
target_compile_options(STM32::F7 INTERFACE
--sysroot="${TOOLCHAIN_SYSROOT}"
${COMMON_COMPILE_FLAGS}
)
#target_compile_options(STM32::F7 INTERFACE $<$<COMPILE_LANGUAGE:ASM>:-x assembler-with-cpp>)
target_compile_options(STM32::F7 INTERFACE $<$<COMPILE_LANGUAGE:C>:${C_CXX_COMPILE_FLAGS}>)
target_compile_options(STM32::F7 INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${C_CXX_COMPILE_FLAGS}>)
target_compile_options(STM32::F7 INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics>)
target_link_options(STM32::F7 INTERFACE
--sysroot="${TOOLCHAIN_SYSROOT}"
${COMMON_COMPILE_FLAGS}
${C_CXX_COMPILE_FLAGS}
LINKER:-gc-sections
)
target_link_options(STM32::F7 INTERFACE $<$<CONFIG:RELEASE>:LINKER:--undefined=vTaskSwitchContext,--undefined=HardFault_HandlerC,-undefined=_realloc_r>)
target_compile_definitions(STM32::F7 INTERFACE
STM32F7
"__weak=__attribute__((weak))"
"__packed=__attribute__((__packed__))"
)
endif()
@@ -0,0 +1,25 @@
add_library(Stm32CmsisCore INTERFACE)
target_include_directories(Stm32CmsisCore
INTERFACE
${STM32_CMSIS_CORE_SOURCE_DIR}/Core/Include
${STM32_CMSIS_CORE_SOURCE_DIR}/RTOS2/Include
)
file(GLOB_RECURSE Stm32CmsisCore_HEADERS "${STM32_CMSIS_CORE_SOURCE_DIR}/Core/Include/*.h" "${STM32_CMSIS_CORE_SOURCE_DIR}/RTOS2/Include/*.h")
#file(GLOB_RECURSE cmsis_device_f7_SOURCES1 "${cmsis_device_f7_SOURCE_DIR}/Src/**/*.c")
target_sources(Stm32CmsisCore
INTERFACE
${Stm32CmsisCore_HEADERS1}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Stm32CmsisCore
REQUIRED_VARS
Stm32CmsisCore_HEADERS
#Stm32CmsisCore_SOURCES
)
@@ -0,0 +1,33 @@
add_library(Stm32CmsisDevice INTERFACE)
target_include_directories(Stm32CmsisDevice
INTERFACE
${STM32_CMSIS_DEVICE_SOURCE_DIR}/Include
)
file(GLOB_RECURSE Stm32CmsisDevice_HEADERS "${STM32_CMSIS_DEVICE_SOURCE_DIR}/Include/*.h")
set(Stm32CmsisDevice_SOURCES
${STM32_CMSIS_DEVICE_SOURCE_DIR}/Source/Templates/system_stm32f7xx.c
${STM32_CMSIS_DEVICE_SOURCE_DIR}/Source/Templates/gcc/startup_stm32f746xx.s
)
target_compile_definitions(Stm32CmsisDevice
INTERFACE
STM32${MCU_FAMILY}${MCU_CORE}${MCU_LINE}xx
)
target_sources(Stm32CmsisDevice
INTERFACE
${Stm32CmsisDevice_HEADERS}
${Stm32CmsisDevice_SOURCES}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Stm32CmsisDevice
REQUIRED_VARS
Stm32CmsisDevice_HEADERS
Stm32CmsisDevice_SOURCES
)
@@ -0,0 +1,37 @@
add_library(Stm32FreeRtos INTERFACE)
target_include_directories(Stm32FreeRtos
INTERFACE
${STM32_FREERTOS_SOURCE_DIR}/Source
${STM32_FREERTOS_SOURCE_DIR}/Source/include
#${STM32_FREERTOS_SOURCE_DIR}/Source/CMSIS_RTOS_V2
${STM32_FREERTOS_SOURCE_DIR}/Source/portable/GCC/ARM_CM7/r0p1
)
file(GLOB_RECURSE Stm32FreeRtos_HEADERS
#"${STM32_FREERTOS_SOURCE_DIR}/Source/CMSIS_RTOS_V2/*.h"
"${STM32_FREERTOS_SOURCE_DIR}/Source/include/**/*.h"
"${STM32_FREERTOS_SOURCE_DIR}/Source/portable/GCC/ARM_CM7/*.h"
)
file(GLOB_RECURSE Stm32FreeRtos_SOURCES
#"${STM32_FREERTOS_SOURCE_DIR}/Source/CMSIS_RTOS_V2/*.c"
"${STM32_FREERTOS_SOURCE_DIR}/Source/portable/GCC/ARM_CM7/*.c"
)
file(GLOB Stm32FreeRtos_SOURCES2 "${STM32_FREERTOS_SOURCE_DIR}/Source/*.c")
list(APPEND Stm32FreeRtos_SOURCES ${Stm32FreeRtos_SOURCES2} ${STM32_FREERTOS_SOURCE_DIR}/Source/portable/MemMang/heap_4.c)
target_sources(Stm32FreeRtos
INTERFACE
${Stm32FreeRtos_HEADERS}
${Stm32FreeRtos_SOURCES}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Stm32FreeRtos
REQUIRED_VARS
Stm32FreeRtos_HEADERS
Stm32FreeRtos_SOURCES
)
+25
View File
@@ -0,0 +1,25 @@
add_library(Stm32Hal INTERFACE)
target_include_directories(Stm32Hal
INTERFACE
${STM32_HAL_SOURCE_DIR}/Inc
${STM32_HAL_SOURCE_DIR}/Inc/Legacy
)
file(GLOB_RECURSE Stm32Hal_HEADERS "${STM32_HAL_SOURCE_DIR}/Inc/*.h")
file(GLOB_RECURSE Stm32Hal_SOURCES "${STM32_HAL_SOURCE_DIR}/Src/*.c")
list(FILTER Stm32Hal_SOURCES EXCLUDE REGEX ".*_template.c$")
target_sources(Stm32Hal
INTERFACE
${Stm32Hal_HEADERS}
${Stm32Hal_SOURCES}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Stm32Hal
REQUIRED_VARS
Stm32Hal_HEADERS
Stm32Hal_SOURCES
)
@@ -0,0 +1,25 @@
add_library(Stm32UsbDevice INTERFACE)
target_include_directories(Stm32UsbDevice
INTERFACE
${STM32_USB_DEVICE_SOURCE_DIR}/Core/Inc
)
file(GLOB_RECURSE Stm32UsbDevice_HEADERS "${STM32_USB_DEVICE_SOURCE_DIR}/Core/Inc/*.h")
file(GLOB_RECURSE Stm32UsbDevice_SOURCES "${STM32_USB_DEVICE_SOURCE_DIR}/Core/Src/*.c")
list(FILTER Stm32UsbDevice_SOURCES EXCLUDE REGEX ".*_template.c$")
list(FILTER Stm32UsbDevice_HEADERS EXCLUDE REGEX ".*_template.h$")
target_sources(Stm32UsbDevice
INTERFACE
${Stm32UsbDevice_HEADERS}
${Stm32UsbDevice_SOURCES}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Stm32UsbDevice
REQUIRED_VARS
Stm32UsbDevice_HEADERS
Stm32UsbDevice_SOURCES
)
+38
View File
@@ -0,0 +1,38 @@
set(MCU_ARCH cortex-m7)
set(MCU_FLOAT_ABI hard)
set(MCU_FPU fpv5-d16)
set(COMMON_COMPILE_FLAGS -mcpu=${MCU_ARCH} -mthumb -mfloat-abi=${MCU_FLOAT_ABI} -mfpu=${MCU_FPU})
set(C_CXX_COMPILE_FLAGS -ffunction-sections -fdata-sections -fsigned-char -g -fmessage-length=0)
if(NOT (TARGET STM32::H7))
add_library(STM32::H7 INTERFACE IMPORTED)
target_compile_options(STM32::H7 INTERFACE
--sysroot="${TOOLCHAIN_SYSROOT}"
${COMMON_COMPILE_FLAGS}
)
#target_compile_options(STM32::H7 INTERFACE $<$<COMPILE_LANGUAGE:ASM>:-x assembler-with-cpp>)
target_compile_options(STM32::H7 INTERFACE $<$<COMPILE_LANGUAGE:C>:${C_CXX_COMPILE_FLAGS}>)
target_compile_options(STM32::H7 INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${C_CXX_COMPILE_FLAGS}>)
target_compile_options(STM32::H7 INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics>)
target_link_options(STM32::H7 INTERFACE
--sysroot="${TOOLCHAIN_SYSROOT}"
${COMMON_COMPILE_FLAGS}
${C_CXX_COMPILE_FLAGS}
LINKER:-gc-sections
)
target_link_options(STM32::H7 INTERFACE $<$<CONFIG:RELEASE>:LINKER:--undefined=vTaskSwitchContext,--undefined=HardFault_HandlerC,-undefined=_realloc_r>)
target_compile_definitions(STM32::H7 INTERFACE
STM32H7
"__weak=__attribute__((weak))"
"__packed=__attribute__((__packed__))"
)
endif()
+152
View File
@@ -0,0 +1,152 @@
if (DEFINED STM32_DEVICE AND NOT STM32_DEVICE STREQUAL "")
string(REGEX MATCH "STM(32|8)(F|L|H|W|U)([0-9])([^A-Z]+)([A-Z])(.)" STM32_DEVICE_ ${STM32_DEVICE}])
set(MCU_FAMILY ${CMAKE_MATCH_2})
set(MCU_CORE ${CMAKE_MATCH_3})
set(MCU_LINE ${CMAKE_MATCH_4})
message("MCU_FAMILY: ${MCU_FAMILY}")
message("MCU_CORE: ${MCU_CORE}")
message("MCU_LINE: ${MCU_LINE}")
set(STM32_FAMILY_EX "${MCU_FAMILY}${MCU_CORE}" )
message("STM32_FAMILY_EX: ${STM32_FAMILY_EX}")
else()
message("STM32_DEVICE not defined")
endif()
set(STM32_FAMILIES F7 )
set(STM32_HAL_DEFAULT_VERSION v1.3.0 )
set(STM32_FREERTOS_DEFAULT_VERSION v10.5.1 )
set(STM32_CMSIS_DEVICE_DEFAULT_VERSION v1.2.8 )
set(STM32_CMSIS_CORE_DEFAULT_VERSION v5.6.0 )
set(STM32_USB_DEVICE_DEFAULT_VERSION v2.11.2 )
set(STM32_USB_HOST_DEFAULT_VERSION v3.5.1 )
include(FetchContent)
FetchContent_Declare(stm32_usb_host
GIT_REPOSITORY https://github.com/STMicroelectronics/stm32_mw_usb_host.git
GIT_TAG ${STM32_USB_HOST_DEFAULT_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
FetchContent_Declare(stm32_usb_device
GIT_REPOSITORY https://github.com/STMicroelectronics/stm32_mw_usb_device.git
GIT_TAG ${STM32_USB_DEVICE_DEFAULT_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
function(FetchStm32UsbDevice)
string(TOLOWER ${STM32_FAMILY_EX} STM32_FAMILY_EX_LOWER_CASE)
FetchContent_MakeAvailable(stm32_usb_device)
set(STM32_USB_DEVICE_SOURCE_DIR ${stm32_usb_device_SOURCE_DIR} PARENT_SCOPE)
endfunction()
function(FetchStm32UsbHost)
string(TOLOWER ${STM32_FAMILY_EX} STM32_FAMILY_EX_LOWER_CASE)
FetchContent_MakeAvailable(stm32_usb_host)
set(STM32_USB_HOST_SOURCE_DIR ${stm32_usb_host_SOURCE_DIR} PARENT_SCOPE)
endfunction()
FetchContent_Declare(stm32_cmsis_core
GIT_REPOSITORY https://github.com/STMicroelectronics/cmsis_core.git
GIT_TAG ${STM32_CMSIS_CORE_DEFAULT_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
set(ARRAY_INDEX 0)
foreach(FAMILY ${STM32_FAMILIES})
string(TOLOWER ${FAMILY} STM_FAMILY_LOWER_CASE)
if (DEFINED STM32_HAL_VERSION AND NOT STM32_HAL_VERSION STREQUAL "")
else()
list(GET STM32_HAL_DEFAULT_VERSION ${ARRAY_INDEX} STM32_HAL_VERSION)
endif()
message("STM32_HAL_VERSION: ${STM32_HAL_VERSION}")
if (DEFINED STM32_FREERTOS_VERSION AND NOT STM32_FREERTOS_VERSION STREQUAL "")
else()
list(GET STM32_FREERTOS_DEFAULT_VERSION ${ARRAY_INDEX} STM32_FREERTOS_VERSION)
endif()
message("STM32_FREERTOS_VERSION: ${STM32_FREERTOS_VERSION}")
if (DEFINED STM32_CMSIS_DEVICE_VERSION AND NOT STM32_CMSIS_DEVICE_VERSION STREQUAL "")
else()
list(GET STM32_CMSIS_DEVICE_DEFAULT_VERSION ${ARRAY_INDEX} STM32_CMSIS_DEVICE_VERSION)
endif()
message("STM32_CMSIS_DEVICE_VERSION: ${STM32_CMSIS_DEVICE_VERSION}")
#CMSIS Device
FetchContent_Declare(stm32_cmsis_device_${STM_FAMILY_LOWER_CASE}
GIT_REPOSITORY https://github.com/STMicroelectronics/cmsis_device_${STM_FAMILY_LOWER_CASE}.git
GIT_TAG ${STM32_CMSIS_DEVICE_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
#Hal
FetchContent_Declare(stm32_hal_${STM_FAMILY_LOWER_CASE}
GIT_REPOSITORY https://github.com/STMicroelectronics/stm32${STM_FAMILY_LOWER_CASE}xx_hal_driver.git
GIT_TAG ${STM32_HAL_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
#FreeRTOS
FetchContent_Declare(stm32_freertos
GIT_REPOSITORY https://github.com/STMicroelectronics/stm32_mw_freertos.git
GIT_TAG ${STM32_FREERTOS_VERSION}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
GIT_PROGRESS TRUE
)
math(EXPR ARRAY_INDEX "${ARRAY_INDEX} + 1")
endforeach()
function(FetchStm32Hal)
string(TOLOWER ${STM32_FAMILY_EX} STM32_FAMILY_EX_LOWER_CASE)
FetchContent_MakeAvailable(stm32_hal_${STM32_FAMILY_EX_LOWER_CASE} )
set(STM32_HAL_SOURCE_DIR ${stm32_hal_${STM32_FAMILY_EX_LOWER_CASE}_SOURCE_DIR} PARENT_SCOPE)
endfunction()
function(FetchStm32FreeRtos)
FetchContent_MakeAvailable(stm32_freertos)
set(STM32_FREERTOS_SOURCE_DIR ${stm32_freertos_SOURCE_DIR} PARENT_SCOPE)
endfunction()
function(FetchStm32CmsisDevice)
string(TOLOWER ${STM32_FAMILY_EX} STM32_FAMILY_EX_LOWER_CASE)
FetchContent_MakeAvailable(stm32_cmsis_device_${STM32_FAMILY_EX})
set(STM32_CMSIS_DEVICE_SOURCE_DIR ${stm32_cmsis_device_${STM32_FAMILY_EX_LOWER_CASE}_SOURCE_DIR} PARENT_SCOPE)
endfunction()
function(FetchStm32CmsisCore)
FetchContent_MakeAvailable(STM32_CMSIS_CORE)
set(STM32_CMSIS_CORE_SOURCE_DIR ${stm32_cmsis_core_SOURCE_DIR} PARENT_SCOPE)
endfunction()
+110
View File
@@ -0,0 +1,110 @@
if(NOT DEFINED TOOLCHAIN_DIR)
if(CMAKE_HOST_UNIX)
file(GLOB TOOLCHAIN_DIRS "/usr/local/gcc-arm-none-eabi-*")
else()
file(GLOB TOOLCHAIN_DIRS "C:/Program Files (x86)/GNU Arm Embedded Toolchain/*" "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/*")
endif()
if(TOOLCHAIN_DIRS)
list(GET TOOLCHAIN_DIRS 0 TOOLCHAIN_DIR)
message("FOUND ARM GCC Toolchain Directory: ${TOOLCHAIN_DIR}")
endif()
endif()
GET_FILENAME_COMPONENT(STM32_CMAKE_DIR ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
list(APPEND CMAKE_MODULE_PATH ${STM32_CMAKE_DIR})
set(EXE_SUFFIX "")
set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSTEM_VERSION 1)
set(TOOLCHAIN_PREFIX "${CMAKE_LIBRARY_ARCHITECTURE}-")
set(TOOLCHAIN_BIN_PATH "${TOOLCHAIN_DIR}/bin")
set(TOOLCHAIN_INC_PATH "${TOOLCHAIN_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/include")
set(TOOLCHAIN_LIB_PATH "${TOOLCHAIN_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}/lib")
set(TOOLCHAIN_SYSROOT "${TOOLCHAIN_DIR}/${CMAKE_LIBRARY_ARCHITECTURE}")
find_program(CMAKE_C_COMPILER NAMES ${TOOLCHAIN_PREFIX}gcc HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_CXX_COMPILER NAMES ${TOOLCHAIN_PREFIX}g++ HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_ASM_COMPILER NAMES ${TOOLCHAIN_PREFIX}gcc HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_CPPFILT NAMES ${TOOLCHAIN_PREFIX}c++filt HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_DEBUGGER NAMES ${TOOLCHAIN_PREFIX}gdb HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_OBJCOPY NAMES ${TOOLCHAIN_PREFIX}objcopy HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_OBJDUMP NAMES ${TOOLCHAIN_PREFIX}objdump HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_SIZE NAMES ${TOOLCHAIN_PREFIX}size HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_AS NAMES ${TOOLCHAIN_PREFIX}as HINTS ${TOOLCHAIN_BIN_PATH})
find_program(CMAKE_AR NAMES ${TOOLCHAIN_PREFIX}ar HINTS ${TOOLCHAIN_BIN_PATH})
set(CMAKE_EXECUTABLE_SUFFIX_C .elf)
set(CMAKE_EXECUTABLE_SUFFIX_CXX .elf)
set(CMAKE_EXECUTABLE_SUFFIX_ASM .elf)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
#set(COMMON_FLAGS "-mcpu=${MCU_ARCH} -mthumb -mfloat-abi=${MCU_FLOAT_ABI} -mfpu=${MCU_FPU} -ffunction-sections -fdata-sections -fsigned-char -g -fmessage-length=0 -D__weak=__attribute__((weak)) -D__packed=__attribute__((__packed__))")
#
#set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -std=c++17 -fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics" CACHE INTERNAL "cxx compiler flags")
#set(CMAKE_C_FLAGS "${COMMON_FLAGS} -std=c11" CACHE INTERNAL "c compiler flags")
#
#set(CMAKE_EXE_LINKER_FLAGS "-Wl,-gc-sections -specs=nosys.specs -specs=nano.specs" CACHE INTERNAL "exe compiler flags")
#SET(CMAKE_ASM_FLAGS "-mthumb -mcpu=${MCU_ARCH} -mfpu=${MCU_FPU} -mfloat-abi=${MCU_FLOAT_ABI} -x assembler-with-cpp" CACHE INTERNAL "asm compiler flags")
#
#
#include(fetch_utils)
if(NOT (TARGET GCC::Specs::NoSys))
add_library(GCC::Specs::NoSys INTERFACE IMPORTED)
target_link_options(GCC::Specs::NoSys INTERFACE
-specs=nosys.specs
)
endif()
if(NOT (TARGET GCC::Specs::Nano))
add_library(GCC::Specs::Nano INTERFACE IMPORTED)
target_link_options(GCC::Specs::Nano INTERFACE
-specs=nano.specs
)
endif()
function(gcc_add_linker_script TARGET VISIBILITY SCRIPT_PATH)
get_filename_component(SCRIPT_PATH "${SCRIPT_PATH}" ABSOLUTE)
target_link_options(${TARGET} ${VISIBILITY} -T "${SCRIPT_PATH}")
endfunction()
function(gcc_generate_bin_file TargetName)
add_custom_command(
TARGET ${TargetName}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Generating flash image ${TargetName}.bin"
COMMAND ${CMAKE_OBJCOPY} -O binary ${TargetName}${CMAKE_EXECUTABLE_SUFFIX_C} ${TargetName}.bin
BYPRODUCTS ${TargetName}.bin
)
endfunction()
function(gcc_print_target_size TargetName)
add_custom_command(
TARGET ${TargetName}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Invoking: GCC Print Size"
COMMAND ${CMAKE_SIZE} ${TargetName}${CMAKE_EXECUTABLE_SUFFIX_C}
)
endfunction()
+32
View File
@@ -0,0 +1,32 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
+5
View File
@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.16)
add_library(LFramework INTERFACE)
target_include_directories(LFramework INTERFACE "Src")
add_subdirectory(Src/LFramework)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Sergey Serb
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2
View File
@@ -0,0 +1,2 @@
# LFramework
C++ general purpose library for my projects
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "Debug.h"
#include "IO/Terminal/Terminal.h"
namespace LFramework::Debug {
class Assert : public LogWriter {
public:
Assert():LogWriter(LogLevel::Fatal){}
~Assert(){
for(;;);
}
};
#define lfAssert(expression) \
do { \
if(!(expression)) { \
LFramework::Debug::Assert() \
<< "Assert: " << #expression << LFramework::Terminal::NewLine \
<< "File: " << __FILE__ << LFramework::Terminal::NewLine; \
} \
}while(false)
}
+70
View File
@@ -0,0 +1,70 @@
/*
* BitField.h
*
* Created on: 14 sept. 2017 ã.
* Author: l-pro
*/
#ifndef LFRAMEWORK_BITFIELD_H_
#define LFRAMEWORK_BITFIELD_H_
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include <limits>
namespace LFramework {
template<typename TBase, typename T>
struct BitFieldValueConverter {
static TBase toBase(T value) {
return static_cast<TBase>(value);
}
static T fromBase(TBase value) {
return static_cast<T>(value);
}
};
template<typename TBase, size_t BitOffset, size_t BitCount = 1, typename T = TBase, typename Converter = BitFieldValueConverter<TBase, T>>
struct BitFieldMember {
static constexpr size_t FieldBitsCount = BitCount;
static constexpr size_t TBitsCount = std::numeric_limits<unsigned char>::digits * sizeof(T);
static_assert(std::numeric_limits<unsigned char>::digits == 8, "Only systems with 8 bit chars are supported for now");
static_assert(std::is_standard_layout_v<TBase>, "Only standard layout types supported in unions (and so in BitFieldMember) without UB");
static_assert(BitOffset + BitCount <= TBitsCount, "Base type bits overflow");
TBase baseValue;
static constexpr TBase LowMask = (static_cast<TBase>((~(TBase{ 0 }))) >> (TBitsCount - BitCount));
static constexpr TBase HiMask = TBase(LowMask << BitOffset);
template<typename TR = T, typename = std::enable_if_t<!std::is_same_v<TR, TBase>>>
volatile BitFieldMember& operator =(TR value) volatile {
baseValue = assign(baseValue, Converter::toBase(value));
return *this;
}
template<typename TR = TBase>
constexpr BitFieldMember& operator =(TR value) {
if constexpr(std::is_same_v<TR, TBase>){
baseValue = assign(baseValue, value);
}else{
baseValue = assign(baseValue, Converter::toBase(value));
}
return *this;
}
constexpr operator T() const {
return Converter::fromBase((baseValue >> BitOffset) & LowMask);
}
static constexpr inline TBase assign(TBase left, TBase right) {
return (left & ~(HiMask)) | ((right & LowMask) << BitOffset);
}
};
static_assert(std::is_standard_layout_v<BitFieldMember<uint32_t, 0, 1>>, "Only standard layout types supported in unions (and so in BitFieldMember) without UB");
}
#endif /* LFRAMEWORK_BITFIELD_H_ */
+55
View File
@@ -0,0 +1,55 @@
/*
* BitFieldTest.cpp
*
* Created on: 14 ñåíò. 2017 ã.
* Author: l-pro
*/
#include "UnitTest/UnitTest.h"
#include "BitField.h"
using namespace LFramework;
union Test8BitField {
constexpr Test8BitField():value(0){}
uint8_t value;
BitFieldMember<uint8_t, 0, 1> bit_0_1;
BitFieldMember<uint8_t, 1, 3> bit_1_3;
BitFieldMember<uint8_t, 4, 4> bit_4_4;
};
TEST(BitField_8bit){
Test8BitField bitfield;
TEST_TRUE(bitfield.value == 0);
bitfield.bit_0_1 = 1;
TEST_TRUE(bitfield.value == 1);
TEST_TRUE(bitfield.bit_0_1 == 1);
bitfield.bit_1_3 = 4;
TEST_TRUE(bitfield.bit_1_3 == 4);
TEST_TRUE(bitfield.value == 9);
bitfield.bit_1_3 = 0;
TEST_TRUE(bitfield.value == 1);
bitfield.bit_4_4 = 1;
TEST_TRUE(bitfield.value == 17);
bitfield.bit_4_4 = 15;
TEST_TRUE(bitfield.value == 241);
bitfield.bit_1_3 = 7;
TEST_TRUE(bitfield.value == 0xff);
bitfield.bit_0_1 = 0;
TEST_TRUE(bitfield.value == 0xfe);
bitfield.bit_4_4 = 0;
TEST_TRUE(bitfield.value == 0x0e);
bitfield.bit_1_3 = 0;
TEST_TRUE(bitfield.value == 0x00);
}
+37
View File
@@ -0,0 +1,37 @@
target_sources(LFramework
INTERFACE
Assert.h
BitField.h
CMakeLists.txt
Debug.h
Guid.h
GuidUtils.h
GuidUtils.cpp
System.h
SystemArmCortexM.h
SystemWindows.h
TupleUtils.h
#BitFieldTest.cpp
Syscalls.cpp
Text/Encoding.h
TypeTraits/FunctionTraits.h
TypeTraits/Integral.h
Reflection/Reflection.h
)
add_subdirectory(USB)
add_subdirectory(UnitTest)
add_subdirectory(Threading)
add_subdirectory(IO)
add_subdirectory(Input)
#add_subdirectory(Time)
#add_subdirectory(MCU)
#add_subdirectory(Macro)
#add_subdirectory(IO)
#add_subdirectory(Input)
#add_subdirectory(Detect)
#add_subdirectory(Containers)
#add_subdirectory(COM)
@@ -0,0 +1,4 @@
target_sources(${PROJECT_NAME}
INTERFACE
ComObject.h
)
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "ComObject.h"
#if defined(__CYGWIN32__)
#define LFRAMEWORK_COM_LIBRARY_CALL __stdcall
#define LFRAMEWORK_COM_LIBRARY_EXPORT __declspec(dllexport)
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
#define LFRAMEWORK_COM_LIBRARY_CALL __stdcall
#define LFRAMEWORK_COM_LIBRARY_EXPORT __declspec(dllexport)
#elif defined(__MACH__)
#define LFRAMEWORK_COM_LIBRARY_CALL
#define LFRAMEWORK_COM_LIBRARY_EXPORT
#elif defined(__linux__) || defined(__ANDROID__)
#define LFRAMEWORK_COM_LIBRARY_CALL
#define LFRAMEWORK_COM_LIBRARY_EXPORT __attribute__ ((visibility ("default")))
#else
#define LFRAMEWORK_COM_LIBRARY_CALL
#define LFRAMEWORK_COM_LIBRARY_EXPORT
#endif
namespace LFramework {
#define LFRAMEWORK_COM_LIBRARY_EXPORT_ENTRY_FUNCTION() \
extern "C" LFRAMEWORK_COM_LIBRARY_EXPORT void LFRAMEWORK_COM_LIBRARY_CALL getInterface(LFramework::ComPtr<LFramework::IUnknown>& result){ \
result = LFramework::ComPtr<ILibrary>::create<Library>(); \
}
}
+602
View File
@@ -0,0 +1,602 @@
#pragma once
#include <LFramework/Detect/DetectOS.h>
#include <LFramework/Guid.h>
#include <LFramework/TypeTraits/FunctionTraits.h>
#include <cstdint>
#include <type_traits>
#include <atomic>
#include <string>
#include <vector>
#include <cstring>
#if (LF_TARGET_OS == LF_OS_WINDOWS) || (LF_TARGET_OS == LF_OS_CYGWIN)
#define LFRAMEWORK_COM_CALL __stdcall
#else
#define LFRAMEWORK_COM_CALL
#endif
namespace LFramework {
using InterfaceID = Guid;
//IUnknown
class IUnknown;
template<class TInterface, class TImplementer>
struct InterfaceRemap {};
template<typename Remap>
struct RemapTraits {
};
template<class TInterface, class TImplementer>
struct RemapTraits<InterfaceRemap<TInterface, TImplementer>> {
using InterfaceType = TInterface;
using ImplementerType = TImplementer;
};
template<class Interface>
struct InterfaceAbi {};
template<class InterfaceAbi>
bool InterfaceAbiInterfaceSupported(const InterfaceID& id) {
if (InterfaceAbi::ID() == id) {
return true;
}
if constexpr (!std::is_same_v<typename InterfaceAbi::Base, void>) {
return InterfaceAbiInterfaceSupported<typename InterfaceAbi::Base>(id);
}
return false;
};
struct RemapChainItemBase {
using InterfaceAbiInterfaceSupportedPtr = bool(*)(const InterfaceID&);
RemapChainItemBase* next = nullptr;
InterfaceAbiInterfaceSupportedPtr isSupported = nullptr;
void* getRemapPtr() {
return reinterpret_cast<std::uint8_t*>(&isSupported) + sizeof(isSupported);
}
};
template<typename TRemap>
struct RemapChainItem : RemapChainItemBase {
RemapChainItem(typename RemapTraits<TRemap>::ImplementerType* implementer) {
remap._implementer = implementer;
this->isSupported = &InterfaceAbiInterfaceSupported<InterfaceAbi<typename RemapTraits<TRemap>::InterfaceType>>;
implementer->registerRemap(this);
}
TRemap remap;
};
template<class Implementer, class FirstInterface, class ... Interfaces>
struct ComRemapList : ComRemapList<Implementer, Interfaces...> {
using Base = ComRemapList<Implementer, Interfaces...>;
ComRemapList(Implementer* _this) : Base(_this), remapContainer{ _this } {}
RemapChainItem<InterfaceRemap<FirstInterface, Implementer>> remapContainer;
};
template<class Implementer, class FirstInterface>
struct ComRemapList<Implementer, FirstInterface> {
ComRemapList(Implementer* _this) : remapContainer{ _this } {}
RemapChainItem<InterfaceRemap<FirstInterface, Implementer>> remapContainer;
};
template<class T>
struct IsInterface : std::conditional_t<std::is_base_of_v<InterfaceAbi<IUnknown>, InterfaceAbi<T>>, std::true_type, std::false_type> {};
template<class...T>
struct IsAllInterfaces : std::conjunction<IsInterface<T>...> {};
template<class TImplementer, class TBase, class ... TInterfaceList>
struct ComImplement : public TBase {
using ComImplement_BaseType = TBase;
using ComImplement_SelfType = ComImplement;
using Implementer = TImplementer;
ComRemapList<TImplementer, TInterfaceList...> _remaps = { reinterpret_cast<TImplementer*>(this) };
};
template<class T, class = void>
struct IsComImplement : std::false_type {};
template<class T>
struct IsComImplement<T, std::void_t<typename T::ComImplement_SelfType>> : std::true_type {};
template<class...T>
struct IsAllComImplement : std::conjunction<IsComImplement<T>...> {};
template<class TInterface, class ... TInterfaceList>
struct HasInterface : std::disjunction<std::is_base_of<InterfaceAbi<TInterface>, InterfaceAbi<TInterfaceList>>...> {};
template<class TImplementer, class TInterface>
class ComDelegate;
template<class T>
struct IsComDelegate : std::false_type {};
template<class TImplementer, class TInterface>
struct IsComDelegate<ComDelegate<TImplementer, TInterface>> : std::true_type {};
enum class Result : uint32_t {
Ok = 0,
NotImplemented = 0x80004001L,
NoInterface = 0x80004002L,
ErrorPointer = 0x80004003L,
UnknownFailure = 0x80004005L,
OutOfMemory = 0x8007000EL,
InvalidArg = 0x80070057L,
Pending = 0x8000000AL,
AsyncOperationNotStarted = 0x80000019L,
RpcTimeout = 0x8001011FL,
RpcDisconnected = 0x80010108L
};
struct ComException : std::exception {
ComException(Result code) : _errorCode(code) {
}
ComException() : ComException(Result::UnknownFailure) {
}
ComException(Result code, std::string message) :_errorCode(code), _message(std::move(message)) {
}
ComException(std::string message) : ComException(Result::UnknownFailure, std::move(message)) {
}
Result code() const {
return _errorCode;
}
char const* what() const noexcept override {
return _message.c_str();
}
const std::string& message() const {
return _message;
}
private:
Result _errorCode;
std::string _message;
};
template<>
struct InterfaceAbi<IUnknown> {
public:
using Base = void;
static constexpr InterfaceID ID() { return { 0x00000000, 0x0000000, 0x000000C0, 0x46000000 }; }
template<class TInterface>
friend class ComPtr;
friend class ComObject;
virtual Result LFRAMEWORK_COM_CALL queryInterface(const InterfaceID& riid, void** ppvObject) = 0;
virtual std::uint32_t LFRAMEWORK_COM_CALL addRef() = 0;
virtual std::uint32_t LFRAMEWORK_COM_CALL release() = 0;
~InterfaceAbi() = delete;
};
template<typename TInterface>
static constexpr InterfaceID getInterfaceId() {
return InterfaceAbi<TInterface>::ID();
}
template<class TImplementer>
struct InterfaceRemap<IUnknown, TImplementer> {
virtual Result LFRAMEWORK_COM_CALL queryInterface(const InterfaceID& riid, void** ppvObject) { return _implementer->queryInterface(riid, ppvObject); }
virtual std::uint32_t LFRAMEWORK_COM_CALL addRef() { return _implementer->addRef(); }
virtual std::uint32_t LFRAMEWORK_COM_CALL release() { return _implementer->release(); }
inline auto implementer() {
if constexpr (IsComDelegate<TImplementer>::value) {
return _implementer->getImplementer();
} else {
return _implementer;
}
}
TImplementer* _implementer;
~InterfaceRemap() = default;
};
template <class TInterface, class TComImplement>
struct IsComImplementSupportsInterface : std::false_type {};
template <class TInterface, class TImplementer, class TBase, class ... TInterfaceList>
struct IsComImplementSupportsInterface<TInterface, ComImplement<TImplementer, TBase, TInterfaceList...>> : HasInterface<TInterface, TInterfaceList...> {};
class RefCountedObject {
public:
virtual ~RefCountedObject() = default;
std::uint32_t addRef() {
return _refCount.fetch_add(1) + 1;
}
std::uint32_t release() {
auto result = _refCount.fetch_sub(1);
if (result == 1) {
delete this;
}
return result - 1;
}
private:
std::atomic<unsigned long> _refCount{};
};
template<class TInterface>
class ComPtr;
class ComObject : public RefCountedObject {
public:
template<typename TRemap>
friend struct RemapChainItem;
ComObject() {
_headRemap.next = &_headRemap;
}
template<typename TInterface>
ComPtr<TInterface> queryInterface() {
void* result = nullptr;
if(queryInterface(InterfaceAbi<TInterface>::ID(), &result) == Result::Ok){
auto abiPtr = reinterpret_cast<InterfaceAbi<TInterface>*>(result);
ComPtr<TInterface> result;
result.attach(abiPtr);
return result;
}
return nullptr;
}
Result queryInterface(const InterfaceID& riid, void** ppvObject) {
if (ppvObject == nullptr) {
return Result::ErrorPointer;
}
findInterface(riid, ppvObject);
if (*ppvObject == nullptr) {
return Result::NoInterface;
} else {
auto obj = (reinterpret_cast<InterfaceAbi<IUnknown>*>(*ppvObject));
obj->addRef();
return Result::Ok;
}
}
private:
void findInterface(const InterfaceID& id, void** result) {
RemapChainItemBase* current = &_headRemap;
do {
if (current->isSupported(id)) {
*result = current->getRemapPtr();
return;
}
current = current->next;
} while (current != &_headRemap);
*result = nullptr;
}
void registerRemap(RemapChainItemBase* remap) {
remap->next = _headRemap.next;
_headRemap.next = remap;
}
RemapChainItem<InterfaceRemap<IUnknown, ComObject>> _headRemap{ this };
};
template<class TImplementer, class TInterface>
constexpr bool IsInterfaceSupported() {
if constexpr(!LFramework::IsInterface<TInterface>::value || !IsComImplement<TImplementer>::value){
return false;
}else{
if constexpr(std::is_same_v<TImplementer, ComObject> && std::is_same_v<TInterface, LFramework::IUnknown>){
return true;
}else{
if constexpr (LFramework::IsComImplementSupportsInterface<TInterface, typename TImplementer::ComImplement_SelfType>::value){
return true;
}else{
return IsInterfaceSupported<typename TImplementer::ComImplement_BaseType, TInterface>();
}
}
}
}
template<class TInterface>
class InterfaceWrapper {
public:
using NotSpecialized = bool;
};
template<class TInterface, class = void>
class HasInterfaceWrapper : public std::true_type {};
template<class TInterface>
class HasInterfaceWrapper<TInterface, std::void_t<typename LFramework::InterfaceWrapper<TInterface>::NotSpecialized>> : public std::false_type {};
template<class TInterface>
class ComPtr {
public:
using InterfacePtr = InterfaceAbi<TInterface>*;
using PublicInterfacePtr = std::conditional_t<HasInterfaceWrapper<TInterface>::value, InterfaceWrapper<TInterface>*, InterfacePtr>;
ComPtr() = default;
ComPtr(InterfacePtr ptr) : _interface(ptr){
if(_interface != nullptr){
_interface->addRef();
}
}
template<class U, class = std::enable_if_t<std::is_base_of_v<InterfaceAbi<TInterface>, InterfaceAbi<U>>>>
ComPtr(ComPtr<U> ptr) : _interface(ptr.get()) {
_interface->addRef();
}
ComPtr(const ComPtr& ptr) : _interface(ptr.get()) {
if(_interface != nullptr){
_interface->addRef();
}
}
template<class U>
ComPtr<U> queryInterface(){
ComPtr<U> result;
if(_interface->queryInterface(InterfaceAbi<U>::ID(), result.put()) == Result::Ok){
return result;
}
return {};
}
~ComPtr() {
reset();
}
PublicInterfacePtr operator ->() {
if constexpr(HasInterfaceWrapper<TInterface>::value){
return reinterpret_cast<PublicInterfacePtr>(&_interface);
}else{
return reinterpret_cast<InterfacePtr>(_interface);
}
}
template<class U, class = std::enable_if_t<std::is_base_of_v<InterfaceAbi<TInterface>, InterfaceAbi<U>>>>
operator ComPtr<U>(){
return ComPtr<U>(_interface);
}
ComPtr operator = (std::nullptr_t) {
reset();
return *this;
}
ComPtr operator = (const ComPtr& other) {
reset();
auto ptr = other._interface;
if (ptr != nullptr) {
ptr->addRef();
}
_interface = ptr;
return *this;
}
bool operator == (const ComPtr& other) const {
return _interface == other._interface;
}
bool operator != (const ComPtr& other) const {
return _interface != other._interface;
}
bool operator == (std::nullptr_t) const {
return _interface == nullptr;
}
bool operator != (std::nullptr_t) const {
return _interface != nullptr;
}
InterfacePtr operator*() {
return _interface;
}
const InterfacePtr operator*() const {
return _interface;
}
operator bool() const {
return (_interface != nullptr);
}
InterfacePtr get() const {
return _interface;
}
void** put() {
return reinterpret_cast<void**>(&_interface);
}
InterfacePtr detach() {
auto result = _interface;
_interface = nullptr;
return result;
}
void attach(InterfacePtr ptr) {
reset();
_interface = ptr;
}
void reset() {
auto ptr = _interface;
if (ptr != nullptr) {
_interface = nullptr;
ptr->release();
}
}
template<class TImplementer, class ... TArgs>
static ComPtr create(TArgs&& ... args) {
if constexpr(IsInterfaceSupported<TImplementer, TInterface>()){
auto obj = new TImplementer(std::forward<TArgs>(args)...);
return obj->template queryInterface<TInterface>();
}else{
static_assert(IsInterfaceSupported<TImplementer, TInterface>(), "Interface not supported");
}
}
private:
InterfacePtr _interface = nullptr;
};
template<class TImplementer, class TInterface>
class ComDelegate : public ComImplement<ComDelegate<TImplementer, TInterface>, ComObject, TInterface> {
public:
using DelegatedImplementer = TImplementer;
typedef void (TImplementer::*DelegateDestroyCallback)();
ComDelegate(TImplementer* implementer, DelegateDestroyCallback destroyCallback)
: _implementer(implementer), _destroyCallback(destroyCallback) {
if constexpr (std::is_base_of_v<RefCountedObject, TImplementer>) {
_implementer->addRef();
}
}
~ComDelegate() {
if (_destroyCallback != nullptr) {
((_implementer)->*(_destroyCallback))();
}
if constexpr (std::is_base_of_v<RefCountedObject, TImplementer>) {
_implementer->release();
}
}
TImplementer* getImplementer() {
return _implementer;
}
private:
DelegateDestroyCallback _destroyCallback;
TImplementer* _implementer;
};
template<class TInterface, class TImplementer>
ComPtr<TInterface> makeComDelegate(TImplementer* implementer, typename ComDelegate<TImplementer, TInterface>::DelegateDestroyCallback delegateDestroyCallback = nullptr) {
return ComPtr<TInterface>::template create<ComDelegate<TImplementer, TInterface>>(implementer, delegateDestroyCallback);
}
class ArrayOutMarshaler {
public:
using SizeType = std::uint32_t;
typedef void* ContextPtr;
typedef void* (LFRAMEWORK_COM_CALL *ContainerResizeCallback)(ContextPtr context, SizeType size);
ContextPtr context;
ContainerResizeCallback callback;
template<typename T>
ArrayOutMarshaler(std::vector<T>& buffer) {
context = &buffer;
callback = &ArrayOutMarshaler::resizeCallback<T>;
}
ArrayOutMarshaler(std::string& buffer) {
context = &buffer;
callback = &ArrayOutMarshaler::resizeCallback;
}
template<typename T>
void operator = (const std::vector<T>& source) {
void* data = callback(context, static_cast<SizeType>(source.size()));
if (data != nullptr && !source.empty()) {
memcpy(data, source.data(), sizeof(T) * source.size());
}
}
void operator = (const std::string& source) {
void* data = callback(context, static_cast<SizeType>(source.size()));
if (data != nullptr && !source.empty()) {
memcpy(data, source.data(), source.size());
}
}
private:
template<typename T>
static void* LFRAMEWORK_COM_CALL resizeCallback(ContextPtr context, SizeType size) {
auto container = reinterpret_cast<std::vector<T>*>(context);
container->resize(size);
return size == 0 ? nullptr : container->data();
}
static void* LFRAMEWORK_COM_CALL resizeCallback(ContextPtr context, SizeType size) {
auto container = reinterpret_cast<std::string*>(context);
container->resize(size);
return size == 0 ? nullptr : container->data();
}
ArrayOutMarshaler() = delete;
};
class ArrayInMarshaler {
public:
using SizeType = std::uint32_t;
const void* data;
SizeType itemsCount;
ArrayInMarshaler(const std::string& source) {
data = source.data();
itemsCount = static_cast<SizeType>(source.size());
}
template<typename T>
ArrayInMarshaler(const std::vector<T>& source) {
data = source.data();
itemsCount = static_cast<SizeType>(source.size());
}
operator std::string() const {
return std::string(reinterpret_cast<const char*>(data), itemsCount);
}
template<typename T>
operator std::vector<T>() const {
std::vector<T> result;
if (itemsCount != 0) {
result.resize(itemsCount);
memcpy(result.data(), data, sizeof(T) * itemsCount);
}
return result;
}
private:
ArrayInMarshaler() = delete;
};
template<>
class InterfaceWrapper<IUnknown> {
public:
template<typename TInterface, typename = typename std::enable_if<std::is_base_of<InterfaceAbi<IUnknown>, InterfaceAbi<TInterface>>::value>::type>
ComPtr<TInterface> queryInterface() {
if (_abi == nullptr) {
return {};
}
ComPtr<TInterface> result{};
reinterpret_cast<InterfaceAbi<IUnknown>*>(_abi)->queryInterface(InterfaceAbi<TInterface>::ID(), reinterpret_cast<void**>(&result));
return result;
}
uint32_t addRef() {
return reinterpret_cast<InterfaceAbi<IUnknown>*>(_abi)->addRef();
}
uint32_t release() {
return reinterpret_cast<InterfaceAbi<IUnknown>*>(_abi)->release();
}
protected:
void* _abi = nullptr;
};
}
@@ -0,0 +1,118 @@
#pragma once
#include <array>
#include <cstdint>
#include <cstring>
template<std::size_t _Capacity>
class ByteFifo {
public:
static constexpr std::size_t Capacity = _Capacity;
bool write(const void* data, std::size_t size){
std::size_t availableSize = getAvailableSize();
if(availableSize >= size){
auto writeOffset = (_begin + _size) % Capacity;
auto distanceToEnd = Capacity - writeOffset;
if(distanceToEnd >= size){
memcpy(_buffer.data() + writeOffset, data, size);
}else{
memcpy(_buffer.data() + writeOffset, data, distanceToEnd);
memcpy(_buffer.data(), reinterpret_cast<const std::uint8_t*>(data) + distanceToEnd, size - distanceToEnd);
}
_size += size;
if(_size >= 100000){
for(;;);
}
return true;
}
return false;
}
bool write(std::uint8_t value){
return write(&value, 1);
}
bool read(void* data, std::uint8_t size) {
if(_size >= 100000){
for(;;);
}
if(_size < size){
return false;
}
auto distanceToEnd = Capacity - _begin;
if(distanceToEnd >= size){
memcpy(data, _buffer.data() + _begin, size);
_begin = (_begin + size) % Capacity;
}else{
memcpy(data, _buffer.data() + _begin, distanceToEnd);
memcpy(reinterpret_cast<std::uint8_t*>(data) + distanceToEnd, _buffer.data(), size - distanceToEnd);
_begin = size - distanceToEnd;
}
if(_size >= 100000){
for(;;);
}
_size -= size;
if(_size >= 100000){
for(;;);
}
return true;
}
std::size_t discard(std::size_t count){
if(count > _size){
count = _size;
}
_begin = (_begin + count) % Capacity;
_size -= count;
if(_size >= 100000){
for(;;);
}
return count;
}
bool peek(void* data, std::size_t size) {
if(_size < size){
return false;
}
auto distanceToEnd = Capacity - _begin;
if(distanceToEnd >= size){
memcpy(data, _buffer.data() + _begin, size);
}else{
memcpy(data, _buffer.data() + _begin, distanceToEnd);
memcpy(reinterpret_cast<std::uint8_t*>(data) + distanceToEnd, _buffer.data(), size - distanceToEnd);
}
return true;
}
bool read(std::uint8_t* value) {
return read(value, 1);
}
std::size_t size() const {
return _size;
}
std::size_t sizeAvailable() const {
return Capacity - _size;
}
bool empty() const {
return _size == 0;
}
void clear() {
_begin = 0;
_size = 0;
}
private:
std::size_t getAvailableSize() const {
return Capacity - _size;
}
std::size_t _size = 0;
std::size_t _begin = 0;
std::array<std::uint8_t, Capacity> _buffer;
};
@@ -0,0 +1,6 @@
target_sources(${PROJECT_NAME}
INTERFACE
ByteFifo.h
LinkedList.h
StaticVector.h
)
@@ -0,0 +1,78 @@
#pragma once
#include <cstdint>
#include <cstddef>
class LinkedList;
class LinkedListItem {
public:
LinkedListItem* next = nullptr;
LinkedListItem* previous = nullptr;
LinkedList* owner = nullptr;
};
class LinkedList {
public:
LinkedList():_size(0){
_head.next = &_head;
_head.previous = &_head;
_head.owner = this;
}
bool pushFront(LinkedListItem* newItem){
if (newItem->owner == nullptr) {
newItem->owner = this;
newItem->next = _head.next;
newItem->previous = &_head;
_head.next->previous = newItem;
_head.next = newItem;
++_size;
return true;
}
return false;
}
bool pushBack(LinkedListItem* newItem) {
if (newItem->owner == nullptr) {
newItem->owner = _head.owner;
newItem->previous = _head.previous;
newItem->next = &_head;
_head.previous->next = newItem;
_head.previous = newItem;
++_size;
return true;
}
return false;
}
size_t size() const {
return _size;
}
void remove(LinkedListItem* item) {
if (item->owner == this) {
item->next->previous = item->previous;
item->previous->next = item->next;
--_size;
item->next = nullptr;
item->previous = nullptr;
item->owner = nullptr;
}
}
template<typename T>
void foreach(T functor) {
auto current = _head.next;
while (current != &_head) {
functor(current);
current = current->next;
}
}
private:
size_t _size;
LinkedListItem _head;
};
@@ -0,0 +1,172 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <type_traits>
#include <new>
#include <algorithm>
#include <initializer_list>
namespace LFramework {
template<class ValueType, size_t Capacity>
class StaticVector {
public:
typedef ValueType& ValueReference;
typedef const ValueReference& ConstValueReference;
StaticVector() = default;
~StaticVector() {
clear();
}
constexpr std::size_t capacity() const {
return Capacity;
}
std::size_t size() const {
return _size;
}
bool empty() const {
return _size == 0;
}
bool full() const {
return _size == Capacity;
}
void clear() {
for(auto it = begin(); it != end(); ++it) {
it->~value_type();
}
_size = 0;
}
ValueType* begin() {
return reinterpret_cast<ValueType*>(&_buffer[0]);
}
const ValueType* begin() const {
return reinterpret_cast<const ValueType*>(&_buffer[0]);
}
ValueType* end() {
return reinterpret_cast<ValueType*>(&_buffer[_size]);
}
const ValueType* end() const {
return reinterpret_cast<const ValueType*>(&_buffer[_size]);
}
ValueReference back() {
return *reinterpret_cast<ValueType*>(&_buffer[_size - 1]);
}
ConstValueReference back() const {
return *reinterpret_cast<const ValueType*>(&_buffer[_size - 1]);
}
template<typename ...Args>
bool emplace_back(Args&&... args) {
if(!full()) {
::new(&_buffer[_size++]) ValueType(std::forward<Args>(args)...);
return true;
}
return false;
}
bool push_back(ConstValueReference value) {
if (!full()) {
::new((void*)&_buffer[_size++]) ValueType(value);
return true;
}
return false;
}
void erase(const std::size_t first, const std::size_t count) {
std::size_t last = first + count;
if ((last <= first) || (last > _size)) {
return;
}
//move items
auto writePtr = reinterpret_cast<ValueType*>(&_buffer[first]);
for(std::size_t i = last; i < _size; ++i){
*writePtr = std::move(*reinterpret_cast<ValueType*>(&_buffer[i]));
++writePtr;
}
//destroy tail
for(std::size_t i = first; i < last; ++i){
writePtr->~value_type();
++writePtr;
}
_size -= (last - first);
}
void erase(const ValueType& value) {
for (std::size_t i = 0; i < _size; ++i) {
if (_buffer[i] == value) {
erase(i, 1);
return;
}
}
}
void erase(const ValueType* itemPtr) {
if(itemPtr < begin()){
return;
}
std::size_t id = itemPtr - begin();
erase(id, 1);
}
void pop_back() {
if (!empty()) {
reinterpret_cast<ValueType*>(&_buffer[--_size])->~value_type();
}
}
ValueReference operator[](std::size_t i) {
return *reinterpret_cast<ValueType*>(&_buffer[i]);
}
ConstValueReference operator[](std::size_t i) const {
return *reinterpret_cast<const ValueType*>(&_buffer[i]);
}
bool contains(ConstValueReference value) {
for (std::size_t i = 0; i < _size; ++i) {
if (_buffer[i] == value) {
return true;
}
}
return false;
}
std::size_t resize(std::size_t newSize) {
if (newSize > Capacity) {
newSize = Capacity;
}
for(std::size_t i = _size; i < newSize; ++i){
::new(reinterpret_cast<ValueType*>(&_buffer[i])) ValueType;
}
for(std::size_t i = newSize; i < _size; ++i){
reinterpret_cast<ValueType*>(&_buffer[i])->~value_type();
}
_size = newSize;
return newSize;
}
private:
typename std::aligned_storage<sizeof(ValueType), alignof(ValueType)>::type _buffer[Capacity];
std::size_t _size = 0;
};
}
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include "IO/Terminal/Terminal.h"
namespace LFramework::Debug {
enum class LogLevel {
Debug,
Info,
Warning,
Critical,
Fatal
};
inline const char* toString(LogLevel category) {
switch (category) {
case LogLevel::Debug:
return "Debug";
case LogLevel::Info:
return "Info";
case LogLevel::Warning:
return "Warning";
case LogLevel::Critical:
return "Critical";
case LogLevel::Fatal:
return "Fatal";
}
return "";
}
class LogWriter {
public:
LogWriter(LogLevel level){
}
template<typename T>
LogWriter& operator << (const T& value) {
Terminal::out << value;
return *this;
}
~LogWriter() {
Terminal::out << Terminal::NewLine;
}
};
inline LogWriter Log() { return LogWriter(LogLevel::Debug); }
inline LogWriter Info() { return LogWriter(LogLevel::Info); }
inline LogWriter Warning() { return LogWriter(LogLevel::Warning); }
inline LogWriter Critical() { return LogWriter(LogLevel::Critical); }
inline LogWriter Fatal() { return LogWriter(LogLevel::Fatal); }
#define lfDebug() LFramework::Debug::Log()
#define lfInfo() LFramework::Debug::Info()
#define lfWarning() LFramework::Debug::Warning()
#define lfCritical() LFramework::Debug::Critical()
#define lfFatal() LFramework::Debug::Fatal()
}
@@ -0,0 +1,6 @@
target_sources(${PROJECT_NAME}
INTERFACE
DetectCPU.h
DetectEndianness.h
DetectOS.h
)
@@ -0,0 +1,87 @@
#ifndef DetectCPU_h__
#define DetectCPU_h__
#define LF_CPU_ARCH_ALPHA 0
#define LF_CPU_ARCH_AMD64 1
#define LF_CPU_ARCH_ARM 2
#define LF_CPU_ARCH_ARM64 3
#define LF_CPU_ARCH_BLACKFIN 4
#define LF_CPU_ARCH_CONVEX 5
#define LF_CPU_ARCH_IX86 6
#define LF_CPU_ARCH_IA64 7
#define LF_CPU_ARCH_MOTOROLA68K 8
#define LF_CPU_ARCH_MIPS 9
#define LF_CPU_ARCH_POWERPC 10
#define LF_CPU_ARCH_SPARC 11
#ifndef LF_CPU_ARCH
#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
#define LF_CPU_ARCH LF_CPU_ARCH_ALPHA
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define LF_CPU_ARCH LF_CPU_ARCH_AMD64
#elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) || defined(__TARGET_ARCH_THUMB) || defined(_ARM) || defined(_M_ARM)|| defined(_M_ARMT) || defined(__arm)
#define LF_CPU_ARCH LF_CPU_ARCH_ARM
#elif defined(__aarch64__)
#define LF_CPU_ARCH LF_CPU_ARCH_ARM64
#elif defined(__bfin) || defined(__BFIN__)
#define LF_CPU_ARCH LF_CPU_ARCH_BLACKFIN
#elif defined(__convex__)
#define LF_CPU_ARCH LF_CPU_ARCH_CONVEX
#elif defined(i386) || defined(__i386) || defined(__i386__) || defined(__IA32__) \
|| defined(_M_I86) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) \
|| defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__) || defined(__386)
#define LF_CPU_ARCH LF_CPU_ARCH_IX86
#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(__ia64) \
|| defined(_M_IA64) || defined(_M_IA64) || defined(__itanium__)
#define LF_CPU_ARCH LF_CPU_ARCH_IA64
#elif defined(__m68k__) || defined(M68000) || defined(__MC68K__)
#define LF_CPU_ARCH LF_CPU_ARCH_MOTOROLA68K
#elif defined(__mips__) || defined(mips) || defined(__mips) || defined(__MIPS__)
#define LF_CPU_ARCH LF_CPU_ARCH_MIPS
#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) \
|| defined(__ppc__) || defined(__ppc64__) || defined(__PPC__) || defined(__PPC64__) \
|| defined(_ARCH_PPC) || defined(_ARCH_PPC64) || defined(_M_PPC) || defined(__ppc)
#define LF_CPU_ARCH LF_CPU_ARCH_POWERPC
#elif defined(__sparc__) || defined(__sparc)
#define LF_CPU_ARCH LF_CPU_ARCH_MIPS
#else
#error "Unknown CPU arch"
#endif
#endif
namespace LFramework {
enum class CpuArchitecture {
Alpha = LF_CPU_ARCH_ALPHA,
AMD64 = LF_CPU_ARCH_AMD64,
ARM = LF_CPU_ARCH_ARM,
ARM64 = LF_CPU_ARCH_ARM64,
Blackfin = LF_CPU_ARCH_BLACKFIN,
Convex = LF_CPU_ARCH_CONVEX,
IX86 = LF_CPU_ARCH_IX86,
IA64 = LF_CPU_ARCH_IA64,
Motorola68K = LF_CPU_ARCH_MOTOROLA68K,
MIPS = LF_CPU_ARCH_MIPS,
PowerPC = LF_CPU_ARCH_POWERPC,
SPARC = LF_CPU_ARCH_SPARC
};
namespace Detect {
static constexpr CpuArchitecture cpuArchitecture() {
return static_cast<CpuArchitecture>(LF_CPU_ARCH);
}
}
}
#endif // DetectCPU_h__
@@ -0,0 +1,63 @@
#ifndef DetectEndianness_h__
#define DetectEndianness_h__
#define LF_ENDIANNESS_UNKNOWN 0
#define LF_ENDIANNESS_LITTLE 1
#define LF_ENDIANNESS_BIG 2
#ifndef LF_ENDIANNESS
#if defined(__BIG_ENDIAN__) || defined(__ARMEB__) || defined(__THUMBEB__) \
|| defined(__AARCH64EB__) || defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) \
|| (defined(__FLOAT_WORD_ORDER__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__))
#define LF_ENDIANNESS LF_ENDIANNESS_BIG
#elif defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__THUMBEL__) \
|| defined(__AARCH64EL__) || defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) \
|| (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) \
|| (defined(__FLOAT_WORD_ORDER__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__))
#define LF_ENDIANNESS LF_ENDIANNESS_LITTLE
#else
#define LF_ENDIANNESS LF_ENDIANNESS_UNKNOWN
#endif
#endif
namespace LFramework {
enum class Endianness {
Unknown = LF_ENDIANNESS_UNKNOWN,
Little = LF_ENDIANNESS_LITTLE,
Big = LF_ENDIANNESS_BIG
};
namespace Detect {
static constexpr Endianness endianness() {
return static_cast<Endianness>(LF_ENDIANNESS);
}
static Endianness endiannessRuntime() {
union {
uint32_t value;
uint8_t data[sizeof(uint32_t)];
} number;
number.data[0] = 0x00;
number.data[1] = 0x01;
number.data[2] = 0x02;
number.data[3] = 0x03;
switch (number.value){
case 0x00010203U: return Endianness::Big;
case 0x03020100U: return Endianness::Little;
default: return Endianness::Unknown;
}
}
}
}
#endif // DetectEndianness_h__
+121
View File
@@ -0,0 +1,121 @@
#pragma once
//OS Types
#define LF_OS_NONE 0
#define LF_OS_WINDOWS 1
#define LF_OS_LINUX 2
#define LF_OS_ANDROID 3
#define LF_OS_FREERTOS 4
//BSD family
#define LF_OS_BSD_DRAGONFLY 5
#define LF_OS_BSD_FREE 6
#define LF_OS_BSD_NET 7
#define LF_OS_BSD_OPEN 8
#define LF_OS_BSD_BSDI 9
//Apple
#define LF_OS_IPHONE 10
#define LF_OS_MAC 11
#define LF_OS_CYGWIN 12
#define LF_OS_LYNX 13
#define LF_OS_MSDOS 14
#define LF_OS_NUCLEUS_RTOS 15
#define LF_OS_OS2 16
#define LF_OS_PALMOS 17
#define LF_OS_SOLARIS 18
//OS Detect
#if !defined(LF_TARGET_OS)
#if defined(_WIN32) || defined(_WIN16) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
#define LF_TARGET_OS LF_OS_WINDOWS
#elif defined(__linux__)
#define LF_TARGET_OS LF_OS_LINUX
#elif defined(__ANDROID__)
#define LF_TARGET_OS LF_OS_ANDROID
//Detect BDS
#elif defined(__DragonFly__)
#define LF_TARGET_OS LF_OS_BSD_DRAGONFLY
#elif defined(__FreeBSD__)
#define LF_TARGET_OS LF_OS_BSD_FREE
#elif defined(__NetBSD__)
#define LF_TARGET_OS LF_OS_BSD_NET
#elif defined(__OpenBSD__)
#define LF_TARGET_OS LF_OS_BSD_OPEN
#elif defined(__bsdi__)
#define LF_TARGET_OS LF_OS_BSD_BSDI
//Detect Apple
#elif defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#if (TARGET_IPHONE_SIMULATOR == 1) || (TARGET_OS_IPHONE == 1)
#define LF_TARGET_OS LF_OS_IPHONE
#elif TARGET_OS_MAC == 1
#define LF_TARGET_OS LF_OS_MAC
#else
#error "Unknown Apple OS"
#endif
#elif defined(__CYGWIN__)
#define LF_TARGET_OS LF_OS_CYGWIN
#elif defined(__Lynx__)
#define LF_TARGET_OS LF_OS_LYNX
//detect MS-DOS
#elif defined(MSDOS) || defined(__MSDOS__) || defined(_MSDOS) || defined(__DOS__)
#define LF_TARGET_OS LF_OS_MSDOS
#elif defined(__nucleus__)
#define LF_TARGET_OS LF_OS_NUCLEUS_RTOS
#elif defined(OS2) || defined(_OS2) || defined(__OS2__) || defined(__TOS_OS2__)
#define LF_TARGET_OS LF_OS_OS2
#elif defined(__palmos__)
#define LF_TARGET_OS LF_OS_PALMOS
#elif defined(sun) || defined(__sun)
#define LF_TARGET_OS LF_OS_SOLARIS
#else
#error "OS auto detect fail!"
#endif
#endif
namespace LFramework {
enum class OSType {
None = LF_OS_NONE,
Windows = LF_OS_WINDOWS,
Linux = LF_OS_LINUX,
Android = LF_OS_ANDROID,
FreeRTOS = LF_OS_FREERTOS,
BSDDragonfly = LF_OS_BSD_DRAGONFLY,
BSDFree = LF_OS_BSD_FREE,
BSDNet = LF_OS_BSD_NET,
BSDOpen = LF_OS_BSD_OPEN,
BSDI = LF_OS_BSD_BSDI,
AppleIPhone = LF_OS_IPHONE,
AppleMacOSX = LF_OS_MAC,
Cygwin = LF_OS_CYGWIN,
Lynx = LF_OS_LYNX,
MSDOS = LF_OS_MSDOS,
NucleusRTOS = LF_OS_NUCLEUS_RTOS,
OS2 = LF_OS_OS2,
PlamOS = LF_OS_PALMOS,
Solaris = LF_OS_SOLARIS
};
namespace Detect {
static constexpr inline OSType operatingSystem() {
return static_cast<OSType>(LF_TARGET_OS);
}
}
}
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <cstdint>
namespace LFramework {
struct Guid {
std::uint32_t data1;
std::uint32_t data2_3;
std::uint32_t data4_0;
std::uint32_t data4_1;
//std::uint16_t data2;
//std::uint16_t data3;
//std::uint8_t data4[8];
Guid() = default;
constexpr Guid(std::uint32_t data1, std::uint32_t data2_3, std::uint32_t data4_0, std::uint32_t data4_1) : data1(data1), data2_3(data2_3), data4_0(data4_0), data4_1(data4_1) {}
constexpr bool operator ==(const Guid& rhs) const {
return
(data1 == rhs.data1) &&
(data2_3 == rhs.data2_3) &&
(data4_0 == rhs.data4_0) &&
(data4_1 == rhs.data4_1);
}
constexpr bool operator !=(const Guid& rhs) const {
return !(this->operator ==(rhs));
}
bool isZero() const {
return (data1 == 0) && (data2_3 == 0) && (data4_0 == 0) && (data4_1 == 0);
}
Guid& operator =(const Guid& right) {
data1 = right.data1;
data2_3 = right.data2_3;
data4_0 = right.data4_0;
data4_1 = right.data4_1;
return *this;
}
};
}
+36
View File
@@ -0,0 +1,36 @@
#ifdef WIN32
#include <LFramework/GuidUtils.h>
#include <LFramework/Text/Encoding.h>
#include <Windows.h>
#include <stdexcept>
namespace LFramework::GuidUtils {
LFramework::Guid newGuid() {
LFramework::Guid result;
if (CoCreateGuid((GUID*)&result) != S_OK) {
throw std::runtime_error("Failed to create GUID");
}
return result;
}
LFramework::Guid fromString(const char* str) {
LFramework::Guid iid;
if (IIDFromString(LFramework::Text::Encoding::u8StringToWString(str).c_str(), (GUID*)&iid) != S_OK) {
throw std::runtime_error("Failed to parse GUID");
}
return iid;
}
std::string toString(const LFramework::Guid& guid) {
LPOLESTR guid_str = nullptr;
if (StringFromIID(*((const GUID*)&guid), &guid_str) != S_OK) {
throw std::runtime_error("Failed to convert GUID to string");
}
std::wstring result(guid_str);
CoTaskMemFree(guid_str);
return LFramework::Text::Encoding::wStringToU8String(result);
}
}
#endif
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <string>
#include <LFramework/Guid.h>
namespace LFramework::GuidUtils {
LFramework::Guid newGuid();
LFramework::Guid fromString(const char* str);
std::string toString(const LFramework::Guid& guid);
}
@@ -0,0 +1,12 @@
add_library(LFrameworkIo INTERFACE )
add_library(LFramework::IO ALIAS LFrameworkIo )
target_sources(LFrameworkIo
INTERFACE
Stream.h
StreamWriter.h
StreamWriter.cpp
)
add_subdirectory(Terminal)
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#include <cstdint>
#include <cstring>
namespace LFramework {
template<typename T>
class OutputStream {
public:
};
enum class AdjustField {
Left,
Right,
Internal
};
template<typename TChar>
class OutputStreamFormat {
public:
size_t fillWidth = 0;
TChar fillChar{};
AdjustField adjust = AdjustField::Right;
};
template<>
class OutputStream<char> {
public:
OutputStreamFormat<char> format;
virtual ~OutputStream() = default;
virtual int write(const char* data, int length) = 0;
};
}
@@ -0,0 +1,25 @@
#include "StreamWriter.h"
namespace LFramework {
OutputStream<char>& operator <<(OutputStream<char>& stream, const char* value){
auto len = strlen(value);
OutputStreamFormatter::fieldBegin(stream, len);
stream.write(value, static_cast<int>(len));
OutputStreamFormatter::fieldEnd(stream, len);
return stream;
}
OutputStream<char>& operator <<(OutputStream<char>& stream, char value){
OutputStreamFormatter::fieldBegin(stream, 1);
stream.write(&value, 1);
OutputStreamFormatter::fieldEnd(stream, 1);
return stream;
}
OutputStream<char>& operator <<(OutputStream<char>& stream, bool value){
return stream << (value ? "true" : "false");
}
}
+178
View File
@@ -0,0 +1,178 @@
#pragma once
#include "Stream.h"
#include "../TypeTraits/Integral.h"
namespace LFramework {
template<typename T, typename = ::std::enable_if_t<::std::is_integral_v<T>>>
struct DecimalFormat {
DecimalFormat(T value) :value(value) {}
T value;
};
template<typename T, bool UpperCase = false, size_t MinWidth = 0, typename = ::std::enable_if_t<::std::is_integral_v<T>>>
struct HexFormat {
HexFormat(T value) :value(value) {}
T value;
};
template<bool UpperCase = false, size_t MinWidth = 0, typename T>
HexFormat<T, UpperCase, MinWidth> hex(T value) {
return HexFormat<T, UpperCase, MinWidth>(value);
}
class OutputStreamFormatter {
public:
static void writeFiller(OutputStream<char>& stream, size_t itemSize){
auto fillSize = stream.format.fillWidth - itemSize;
for(size_t i = 0; i < fillSize; ++i){
stream.write(&stream.format.fillChar, 1);
}
stream.format.fillWidth = 0;
}
static void fieldBegin(OutputStream<char>& stream, size_t itemSize){
if(stream.format.adjust == AdjustField::Right || stream.format.adjust == AdjustField::Internal){
if(itemSize < stream.format.fillWidth){
writeFiller(stream, itemSize);
}
stream.format.fillWidth = 0;
}
}
static void fieldEnd(OutputStream<char>& stream, size_t itemSize){
if(stream.format.adjust == AdjustField::Left){
if(itemSize < stream.format.fillWidth){
writeFiller(stream, itemSize);
}
stream.format.fillWidth = 0;
}
}
};
template<typename T>
size_t outputStreamWriteInteger (OutputStream<char>& stream, DecimalFormat<T> formatter){
auto v = formatter.value;
static constexpr size_t BufferSize = TypeTraits::Integral::maxDigitsCount<T>() + (::std::is_signed_v<T> ? 1 : 0); //Add space for sign
char result[BufferSize];
size_t writePos = BufferSize - 1;
if constexpr(::std::is_signed_v<T>) {
//print negative numbers
if (v < 0) {
do {
auto next = v / 10;
result[writePos--] = static_cast<char>('0' - (v - (next * 10)));
v = next;
} while (v != 0);
result[writePos] = '-';
auto fieldSize = BufferSize - writePos;
if(fieldSize < stream.format.fillWidth){
if(stream.format.adjust == AdjustField::Internal){
stream.write(&result[writePos], 1);
OutputStreamFormatter::writeFiller(stream, fieldSize);
stream.write(&result[writePos + 1], fieldSize - 1);
}else {
OutputStreamFormatter::fieldBegin(stream, fieldSize);
stream.write(&result[writePos], fieldSize);
OutputStreamFormatter::fieldEnd(stream, fieldSize);
}
}else{
stream.write(&result[writePos], fieldSize);
}
return fieldSize;
}
}
//print positive numbers
do {
result[writePos--] = static_cast<char>('0' + (v % 10));
v /= 10;
} while (v != 0);
auto fieldSize = BufferSize - writePos - 1;
OutputStreamFormatter::fieldBegin(stream, fieldSize);
stream.write(&result[writePos + 1], fieldSize);
OutputStreamFormatter::fieldEnd(stream, fieldSize);
return fieldSize;
}
template<typename T, bool UpperCase, size_t MinWidth>
OutputStream<char>& operator <<(OutputStream<char>& stream, const HexFormat<T, UpperCase, MinWidth>& formatter){
auto v = static_cast<typename std::make_unsigned<T>::type>(formatter.value);
const auto bufferSize = sizeof(T) * 2;
char buffer[bufferSize];
size_t end = bufferSize;
char a = 'a';
if constexpr(UpperCase) {
a = 'A';
}
for(size_t i = 0; i < bufferSize; ++i) {
auto digit = v & 0xf;
if (digit < 10) {
buffer[end - 1] = static_cast<char>('0' + digit);
}
else {
buffer[end - 1] = static_cast<char>(a + (digit - 10));
}
v >>= 4;
--end;
if(v == 0 && (i + 1) >= MinWidth) {
break;
}
}
const auto dataSize = bufferSize - end;
OutputStreamFormatter::fieldBegin(stream, dataSize);
stream.write(&buffer[end], dataSize);
OutputStreamFormatter::fieldEnd(stream, dataSize);
return stream;
}
OutputStream<char>& operator <<(OutputStream<char>& stream, const char* value);
OutputStream<char>& operator <<(OutputStream<char>& stream, char value);
OutputStream<char>& operator <<(OutputStream<char>& stream, bool value);
template<typename T>
OutputStream<char>& operator <<(OutputStream<char>& stream, DecimalFormat<T> formatter){
outputStreamWriteInteger(stream, formatter);
return stream;
}
template<typename T, typename = std::enable_if_t<
std::is_integral_v<T> &&
std::is_arithmetic_v<T> &&
!std::is_same_v<T, bool> &&
!std::is_same_v<T, char>
>>
OutputStream<char>& operator <<(OutputStream<char>& stream, T value){
return stream << DecimalFormat<T>(value);
}
}
@@ -0,0 +1,13 @@
add_library(LFrameworkIoTerminal INTERFACE )
add_library(LFramework::IO::Terminal ALIAS LFrameworkIoTerminal )
target_sources(LFrameworkIoTerminal
INTERFACE
Terminal.h
TerminalAnsi.h
TerminalStream.h
Terminal.cpp
TerminalStreamCout.cpp
TerminalStreamUartStm32.cpp
)
@@ -0,0 +1,5 @@
#include "Terminal.h"
namespace LFramework::Terminal {
Stream out;
}
@@ -0,0 +1,8 @@
#pragma once
#include "TerminalStream.h"
namespace LFramework::Terminal {
static const char* NewLine = "\r\n";
extern Stream out;
}
@@ -0,0 +1,142 @@
#pragma once
#include <type_traits>
#define LF_TERMINAL_ANSI_ESC "\033"
#define LF_TERMINAL_ANSI_SS2 LF_TERMINAL_ANSI_ESC"N"
#define LF_TERMINAL_ANSI_SS3 LF_TERMINAL_ANSI_ESC"O"
#define LF_TERMINAL_ANSI_DCS LF_TERMINAL_ANSI_ESC"P"
#define LF_TERMINAL_ANSI_CSI LF_TERMINAL_ANSI_ESC"["
#define LF_TERMINAL_ANSI_ST LF_TERMINAL_ANSI_ESC"\\"
#define LF_TERMINAL_ANSI_OSC LF_TERMINAL_ANSI_ESC"]"
#define LF_TERMINAL_ANSI_SOS LF_TERMINAL_ANSI_ESC"X"
#define LF_TERMINAL_ANSI_PM LF_TERMINAL_ANSI_ESC"^"
#define LF_TERMINAL_ANSI_APC LF_TERMINAL_ANSI_ESC"_"
#define LF_TERMINAL_ANSI_RIS LF_TERMINAL_ANSI_ESC"c"
#if defined(LF__TERMINAL_ANSI_CODES_ENABLE)
#define LF_TERMINAL_ANSI_CODE(__id, __suffix) LF_TERMINAL_ANSI_CSI #__id #__suffix
#else
#define LF_TERMINAL_ANSI_CODE(__id, __suffix) ""
#endif
#define LF_TERMINAL_ANSI_GRAPHICS_CODE(__id) LF_TERMINAL_ANSI_CODE(__id, m)
#define LF_TERMINAL_ANSI_CODE_DEFINE(__codeName, __id) inline const char (& __codeName ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_GRAPHICS_CODE(__id))>>::value] { return LF_TERMINAL_ANSI_GRAPHICS_CODE(__id); }
namespace LFramework::Terminal::Ansi {
namespace Color {
LF_TERMINAL_ANSI_CODE_DEFINE(Black, 30)
LF_TERMINAL_ANSI_CODE_DEFINE(Red, 31)
LF_TERMINAL_ANSI_CODE_DEFINE(Green, 32)
LF_TERMINAL_ANSI_CODE_DEFINE(Yellow, 33)
LF_TERMINAL_ANSI_CODE_DEFINE(Blue, 34)
LF_TERMINAL_ANSI_CODE_DEFINE(Magenta, 35)
LF_TERMINAL_ANSI_CODE_DEFINE(Cyan, 36)
LF_TERMINAL_ANSI_CODE_DEFINE(LightGray, 37)
LF_TERMINAL_ANSI_CODE_DEFINE(DarkGray, 90)
LF_TERMINAL_ANSI_CODE_DEFINE(LightRed, 91)
LF_TERMINAL_ANSI_CODE_DEFINE(LightGreen, 92)
LF_TERMINAL_ANSI_CODE_DEFINE(LightYellow, 93)
LF_TERMINAL_ANSI_CODE_DEFINE(LightBlue, 94)
LF_TERMINAL_ANSI_CODE_DEFINE(LightMagenta, 95)
LF_TERMINAL_ANSI_CODE_DEFINE(LightCyan, 96)
LF_TERMINAL_ANSI_CODE_DEFINE(White, 97)
//Background
namespace BG {
LF_TERMINAL_ANSI_CODE_DEFINE(Black, 40)
LF_TERMINAL_ANSI_CODE_DEFINE(Red, 41)
LF_TERMINAL_ANSI_CODE_DEFINE(Green, 42)
LF_TERMINAL_ANSI_CODE_DEFINE(Yellow, 43)
LF_TERMINAL_ANSI_CODE_DEFINE(Blue, 44)
LF_TERMINAL_ANSI_CODE_DEFINE(Magenta, 45)
LF_TERMINAL_ANSI_CODE_DEFINE(Cyan, 46)
LF_TERMINAL_ANSI_CODE_DEFINE(LightGray, 47)
LF_TERMINAL_ANSI_CODE_DEFINE(DarkGray, 100)
LF_TERMINAL_ANSI_CODE_DEFINE(LightRed, 101)
LF_TERMINAL_ANSI_CODE_DEFINE(LightGreen, 102)
LF_TERMINAL_ANSI_CODE_DEFINE(LightYellow, 103)
LF_TERMINAL_ANSI_CODE_DEFINE(LightBlue, 104)
LF_TERMINAL_ANSI_CODE_DEFINE(LightMagenta, 105)
LF_TERMINAL_ANSI_CODE_DEFINE(LightCyan, 106)
LF_TERMINAL_ANSI_CODE_DEFINE(White, 107)
}
}
namespace Format {
LF_TERMINAL_ANSI_CODE_DEFINE(BoldSet, 1)
LF_TERMINAL_ANSI_CODE_DEFINE(BoldReset, 21)
LF_TERMINAL_ANSI_CODE_DEFINE(UnderlinedSet, 4)
LF_TERMINAL_ANSI_CODE_DEFINE(UnderlinedReset, 24)
LF_TERMINAL_ANSI_CODE_DEFINE(BlinkSet, 5)
LF_TERMINAL_ANSI_CODE_DEFINE(BlinkReset, 25)
LF_TERMINAL_ANSI_CODE_DEFINE(ReverseSet, 7)
LF_TERMINAL_ANSI_CODE_DEFINE(ReverseReset, 27)
LF_TERMINAL_ANSI_CODE_DEFINE(ResetAll, 0)
LF_TERMINAL_ANSI_CODE_DEFINE(Framed, 51)
LF_TERMINAL_ANSI_CODE_DEFINE(Encircled, 52)
LF_TERMINAL_ANSI_CODE_DEFINE(Overlined, 53)
LF_TERMINAL_ANSI_CODE_DEFINE(ClearFramedEncircled, 54)
LF_TERMINAL_ANSI_CODE_DEFINE(ClearOverlined, 55)
}
namespace Cursor {
inline const char (& EnableBlinking ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"?12h")>>::value] {
return LF_TERMINAL_ANSI_CSI"?12h";
}
inline const char (& DisableBlinking ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"?12l")>>::value] {
return LF_TERMINAL_ANSI_CSI"?12l";
}
inline const char (& Show ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"?25h")>>::value] {
return LF_TERMINAL_ANSI_CSI"?25h";
}
inline const char (& Hide ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"?25l")>>::value] {
return LF_TERMINAL_ANSI_CSI"?25l";
}
inline const char (& MoveHome ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"H")>>::value] {
return LF_TERMINAL_ANSI_CSI"H";
}
inline const char (& SavePosition ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"s")>>::value] {
return LF_TERMINAL_ANSI_CSI"s";
}
inline const char (& RestorePosition ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"u")>>::value] {
return LF_TERMINAL_ANSI_CSI"u";
}
}
namespace TextEdit {
inline const char (& EraseLineCurToBeg ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"K")>>::value] {
return LF_TERMINAL_ANSI_CSI"K";
}
inline const char (& EraseLineBegToCur ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"1K")>>::value] {
return LF_TERMINAL_ANSI_CSI"1K";
}
inline const char (& EraseLine ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"2K")>>::value] {
return LF_TERMINAL_ANSI_CSI"2K";
}
}
namespace Viewport {
inline const char (& ClearScreenAfterCursor ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"0J")>>::value] {
return LF_TERMINAL_ANSI_CSI"0J";
}
inline const char (& ClearScreenBeforeCursor ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"1J")>>::value] {
return LF_TERMINAL_ANSI_CSI"1J";
}
inline const char (& ClearScreen ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"2J")>>::value] {
return LF_TERMINAL_ANSI_CSI"2J";
}
inline const char (& ClearScreenAndScrollback ())[std::extent<std::remove_reference_t<decltype(LF_TERMINAL_ANSI_CSI"3J")>>::value] {
return LF_TERMINAL_ANSI_CSI"3J";
}
}
}
@@ -0,0 +1,11 @@
#pragma once
#include "../StreamWriter.h"
namespace LFramework::Terminal {
class Stream : public OutputStream<char>{
public:
int write(const char* data, int length) override final;
};
}
@@ -0,0 +1,16 @@
#include "TerminalStream.h"
#ifdef LF_TERMINAL_STREAM_COUT
#include <iostream>
namespace LFramework::Terminal {
int LFramework::Terminal::Stream::write(const char* data, int length) {
std::cout.write(data, length);
std::cout.flush();
return length;
}
}
#endif
@@ -0,0 +1,31 @@
#include "TerminalStream.h"
#ifdef LF_TERMINAL_STREAM_USART_STM32
#ifdef STM32F7
#include <stm32f7xx_hal.h>
#include <stm32f7xx_ll_usart.h>
#elif STM32H7
#include <stm32h7xx_hal.h>
#include <stm32h7xx_ll_usart.h>
#endif
namespace LFramework::Terminal {
int LFramework::Terminal::Stream::write(const char* data, int length) {
for(int i = 0; i < length; ++i){
while (!LL_USART_IsActiveFlag_TXE(LF_TERMINAL_STREAM_USART)) {}
LL_USART_TransmitData8(LF_TERMINAL_STREAM_USART, *data);
++data;
}
//if(HAL_OK == HAL_UART_Transmit(&huart1, reinterpret_cast<uint8_t*>(const_cast<char*>(data)), length, HAL_MAX_DELAY)){
// return length;
//}
return length;
}
}
#endif
@@ -0,0 +1,14 @@
add_library(LFrameworkInput INTERFACE )
add_library(LFramework::Input ALIAS LFrameworkInput )
target_sources(LFrameworkInput
INTERFACE
Input.h
Keyboard.h
KeysStateManager.h
Mouse.h
Input.cpp
Keyboard.cpp
Mouse.cpp
)
+150
View File
@@ -0,0 +1,150 @@
#ifdef _WIN32
#include "Input.h"
#include <assert.h>
#include <iostream>
#include <string>
#include <algorithm>
Input::Input() {
auto hInst = GetModuleHandle(NULL);
register_input_window_class(hInst);
_input_window = CreateWindow(_class_name, TEXT("RawInputWindow"), WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInst, NULL);
if (_input_window == NULL) {
std::cout << "Failed to create input window!" << std::endl;
}
SetWindowLongPtr(_input_window, GWLP_USERDATA, (LONG_PTR)this);
ShowWindow(_input_window, SW_HIDE);
UpdateWindow(_input_window);
enumerate_devices();
RAWINPUTDEVICE Rid[2];
Rid[0].usUsagePage = 0x01; //HID mouse
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = _input_window;
Rid[1].usUsagePage = 0x01; //HID keyboard
Rid[1].usUsage = 0x06;
Rid[1].dwFlags = RIDEV_INPUTSINK;
Rid[1].hwndTarget = _input_window;
if (RegisterRawInputDevices(Rid, 2, sizeof(Rid[0])) == FALSE) {
std::cout << "Failed to register raw input devices!" << std::endl;
}
}
std::shared_ptr<Input> Input::Instance() {
static std::shared_ptr<Input> instance(new Input());
return instance;
}
const std::vector<std::shared_ptr<Mouse>>& Input::mice() const{
return _mice;
}
void Input::strobe(){
MSG msg = { 0 };
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
for(auto mouse : _mice){
mouse->Strobe();
}
for(auto kb : _keyboards){
kb->Strobe();
}
}
void Input::enumerate_devices() {
_mice.clear();
UINT numDevices;
GetRawInputDeviceList(NULL, &numDevices, sizeof(RAWINPUTDEVICELIST));
if (numDevices == 0) return;
std::vector<RAWINPUTDEVICELIST> deviceList(numDevices);
GetRawInputDeviceList(&deviceList[0], &numDevices, sizeof(RAWINPUTDEVICELIST));
std::vector<wchar_t> deviceNameData;
std::wstring deviceName;
for (UINT i = 0; i < numDevices; ++i) {
const RAWINPUTDEVICELIST& device = deviceList[i];
if (device.dwType == RIM_TYPEMOUSE) {
_mice.push_back(std::make_shared<Mouse>(device.hDevice));
} else if (device.dwType == RIM_TYPEKEYBOARD) {
_keyboards.push_back(std::make_shared<Keyboard>(device.hDevice));
} else {
std::cout << "HID device" << std::endl;
}
}
}
ATOM Input::register_input_window_class(HINSTANCE hinstance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = &Input::wnd_proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hinstance;
wcex.hIcon = LoadIcon(wcex.hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = _class_name;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
return RegisterClassEx(&wcex);
}
const std::vector<std::shared_ptr<Keyboard>>& Input::keyboards() const
{
return _keyboards;
}
LRESULT CALLBACK Input::wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
auto input = (Input*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_INPUT: {
UINT dwSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) {
OutputDebugString(TEXT("GetRawInputData does not return correct size !\n"));
}
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEKEYBOARD) {
auto device = std::find_if(input->_keyboards.begin(), input->_keyboards.end(), [raw](std::shared_ptr<Keyboard> m) {return m->GetHandle() == raw->header.hDevice; });
if (device != input->_keyboards.end()) {
(*device)->ApplyInput(*raw);
}
} else if (raw->header.dwType == RIM_TYPEMOUSE) {
auto device = std::find_if(input->_mice.begin(), input->_mice.end(), [raw](std::shared_ptr<Mouse> m) {return m->GetHandle() == raw->header.hDevice; });
if(device != input->_mice.end()){
(*device)->ApplyInput(*raw);
}
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
#endif
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <memory>
#include <Windows.h>
#include <vector>
#include "Mouse.h"
#include "Keyboard.h"
class Input {
public:
Input();
static std::shared_ptr<Input> Instance();
const std::vector<std::shared_ptr<Mouse>>& mice() const;
const std::vector<std::shared_ptr<Keyboard>>& keyboards() const;
void strobe();
private:
void enumerate_devices();
ATOM register_input_window_class(HINSTANCE hinstance);
static LRESULT CALLBACK wnd_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HWND _input_window;
const TCHAR* _class_name = TEXT("RawInputWindow");
std::vector<std::shared_ptr<Mouse>> _mice;
std::vector<std::shared_ptr<Keyboard>> _keyboards;
};
@@ -0,0 +1,53 @@
#ifdef _WIN32
#include "Keyboard.h"
#include <iostream>
Keyboard::Keyboard(HANDLE hdevice) :_hdevice(hdevice) {
UINT dataSize;
GetRawInputDeviceInfo(hdevice, RIDI_DEVICENAME, nullptr, &dataSize);
if (dataSize) {
std::wstring name_data;
name_data.resize(dataSize);
UINT result = GetRawInputDeviceInfo(hdevice, RIDI_DEVICENAME, &name_data[0], &dataSize);
if (result != UINT_MAX) {
_name = name_data;
}
}
RID_DEVICE_INFO deviceInfo;
deviceInfo.cbSize = sizeof deviceInfo;
dataSize = sizeof deviceInfo;
UINT result = GetRawInputDeviceInfo(hdevice, RIDI_DEVICEINFO, &deviceInfo, &dataSize);
_function_keys_count = deviceInfo.keyboard.dwNumberOfFunctionKeys;
_keys_count = deviceInfo.keyboard.dwNumberOfKeysTotal;
_indicators_count = deviceInfo.keyboard.dwNumberOfIndicators;
}
void Keyboard::Strobe() {
_keys_manager.strobe();
}
HANDLE Keyboard::GetHandle() const {
return _hdevice;
}
bool Keyboard::GetKeyState(uint32_t key_index) const {
return _keys_manager._key_states[key_index];
}
bool Keyboard::GetKeyPressed(uint32_t key_index) const {
return _keys_manager._key_pressed[key_index];
}
bool Keyboard::GetKeyReleased(uint32_t key_index) const {
return _keys_manager._key_released[key_index];
}
void Keyboard::ApplyInput(RAWINPUT input) {
if (input.data.keyboard.Flags == RI_KEY_BREAK)
_keys_manager._key_states[input.data.keyboard.VKey] = false;
else
_keys_manager._key_states[input.data.keyboard.VKey] = true;
}
#endif
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <Windows.h>
#include <cstdint>
#include <string>
#include "KeysStateManager.h"
class Keyboard {
public:
friend class Input;
Keyboard(HANDLE hdevice);
HANDLE GetHandle() const;
bool GetKeyState(uint32_t key_index) const;
bool GetKeyPressed(uint32_t key_index) const;
bool GetKeyReleased(uint32_t key_index) const;
private:
void Strobe();
void ApplyInput(RAWINPUT input);
HANDLE _hdevice;
std::wstring _name;
uint32_t _function_keys_count;
uint32_t _keys_count;
uint32_t _indicators_count;
KeysStateManager<0xff, Keyboard> _keys_manager;
};
@@ -0,0 +1,50 @@
#ifndef KeysStateManager_h__
#define KeysStateManager_h__
template<uint32_t Count, typename Owner>
class KeysStateManager {
public:
friend Owner;
KeysStateManager()
{
for (uint32_t i = 0; i < Count; ++i) {
_key_states[i] = _key_pressed[i] = _key_released[i] = _key_states_previous[i] = false;
}
}
void strobe();
private:
bool _key_states[Count];
bool _key_states_previous[Count];
bool _key_pressed[Count];
bool _key_released[Count];
};
template <uint32_t Count, typename Owner>
void KeysStateManager<Count, Owner>::strobe(){
for (uint32_t i = 0; i < Count; ++i) {
if (_key_states[i]) { //if now pressed
if (_key_states_previous[i]) {//if was pressed
_key_pressed[i] = false;
} else {
_key_pressed[i] = true;
}
} else {
_key_pressed[i] = false;
}
if (!_key_states[i]) { //not pressed
if (_key_states_previous[i]) {//if was pressed
_key_released[i] = true;
} else {
_key_released[i] = false;
}
} else {
_key_released[i] = false;
}
_key_states_previous[i] = _key_states[i];
}
}
#endif // KeysStateManager_h__
+80
View File
@@ -0,0 +1,80 @@
#ifdef _WIN32
#include "Mouse.h"
#include <iostream>
Mouse::Mouse(HANDLE handle) :_handle(handle){
_deltax = _deltay = _deltax_integral = _deltay_integral = 0;
UINT dataSize;
GetRawInputDeviceInfo(_handle, RIDI_DEVICENAME, nullptr, &dataSize);
if (dataSize) {
_name.resize(dataSize);
UINT result = GetRawInputDeviceInfo(_handle, RIDI_DEVICENAME, &_name[0], &dataSize);
if (result != UINT_MAX) {
_name.assign(_name.begin(), _name.end());
}
}
RID_DEVICE_INFO deviceInfo;
deviceInfo.cbSize = sizeof deviceInfo;
dataSize = sizeof deviceInfo;
UINT result = GetRawInputDeviceInfo(_handle, RIDI_DEVICEINFO, &deviceInfo, &dataSize);
if (result != UINT_MAX) {
_buttons_count = deviceInfo.mouse.dwNumberOfButtons;
_has_horizontal_wheel = deviceInfo.mouse.fHasHorizontalWheel == TRUE;
}
}
HANDLE Mouse::GetHandle() const{
return _handle;
}
bool Mouse::GetKeyState(uint32_t key_index) const{
return _keys_manager._key_states[key_index];
}
bool Mouse::GetKeyPressed(uint32_t key_index) const{
return _keys_manager._key_pressed[key_index];
}
bool Mouse::GetKeyReleased(uint32_t key_index) const{
return _keys_manager._key_released[key_index];
}
void Mouse::Strobe() {
_deltax = _deltax_integral;
_deltax_integral = 0;
_deltay = _deltay_integral;
_deltay_integral = 0;
_keys_manager.strobe();
}
int32_t Mouse::GetDx() const{
return _deltax;
}
int32_t Mouse::GetDy() const{
return _deltay;
}
void Mouse::ApplyInput(RAWINPUT input) {
//input.data.mouse.lLastX
_deltax_integral += input.data.mouse.lLastX;
_deltay_integral += input.data.mouse.lLastY;
RAWMOUSE data = input.data.mouse;
for (uint32_t i = 0; i < maxButtonsCount; ++i){
if((data.ulButtons & (1 << (i << 1))) != 0){
_keys_manager._key_states[i] = true;
}
if ((data.ulButtons & (2 << (i << 1))) != 0) {
_keys_manager._key_states[i] = false;
}
}
}
#endif
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <Windows.h>
#include <cstdint>
#include "KeysStateManager.h"
#include <string>
class Mouse {
public:
static constexpr uint32_t maxButtonsCount = 5;
friend class Input;
Mouse(HANDLE handle);
HANDLE GetHandle() const;
bool GetKeyState(uint32_t key_index) const;
bool GetKeyPressed(uint32_t key_index) const;
bool GetKeyReleased(uint32_t key_index) const;
int32_t GetDx() const;
int32_t GetDy() const;
private:
void Strobe();
void ApplyInput(RAWINPUT input);
LONG _deltax_integral;
LONG _deltay_integral;
LONG _deltax;
LONG _deltay;
KeysStateManager<maxButtonsCount, Mouse> _keys_manager;
HANDLE _handle;
std::wstring _name;
uint32_t _buttons_count;
bool _has_horizontal_wheel;
};
@@ -0,0 +1,7 @@
target_sources(${PROJECT_NAME}
INTERFACE
Mcu.h
)
add_subdirectory(DMA)
add_subdirectory(stm32)
add_subdirectory(USBDevice)
@@ -0,0 +1,4 @@
target_sources(${PROJECT_NAME}
INTERFACE
DMA.h
)
+32
View File
@@ -0,0 +1,32 @@
/*
* DMA.h
*
* Created on: 25 ñåíò. 2017 ã.
* Author: l-pro
*/
#ifndef LFRAMEWORK_MCU_DMA_DMA_H_
#define LFRAMEWORK_MCU_DMA_DMA_H_
namespace EmbeddedFramework {
class DMA{
};
template<int Number, int Channel>
class DmaIrqHandler{
};
template<int Number, int Channel>
class DmaCallback {
public:
/*static void error();
static void complete();
static void halfComplete();*/
};
#endif /* LFRAMEWORK_MCU_DMA_DMA_H_ */
+42
View File
@@ -0,0 +1,42 @@
/*
* Mcu.h
*
* Created on: 19 July. 2017 ã.
* Author: l-pro
*/
#ifndef MCUFRAMEWORK_MCU_H_
#define MCUFRAMEWORK_MCU_H_
#include "LFrameworkConfig.h"
#include <cstddef>
#ifndef CMSIS_DEVICE_FILE
#error "CMSIS_DEVICE_FILE path not defined in McuConfig.h"
#else
#include CMSIS_DEVICE_FILE
#endif
namespace LFramework {
namespace Mcu {
inline size_t getCurrentInterruptHandlerIndex(){
return __get_IPSR();
}
inline bool isHandlingInterrupt() {
return getCurrentInterruptHandlerIndex() != 0;
}
inline bool isDebuggerAttached() {
return (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) != 0;
}
inline void setBreakpoint() {
if(isDebuggerAttached){
__BKPT(0);
}
}
}
}
#endif /* MCUFRAMEWORK_MCU_H_ */
@@ -0,0 +1 @@
add_subdirectory(PHY)
@@ -0,0 +1,9 @@
target_sources(${PROJECT_NAME}
INTERFACE
Stm32FsPhy.h
UsbDeviceSoftPhy.h
UsbInternalFsDeviceDriver.h
)
@@ -0,0 +1,51 @@
#ifndef Stm32FsPhy_h__
#define Stm32FsPhy_h__
namespace LFramework {
template<typename Child>
class Stm32FsPhy {
public:
/*void UsbDevice::start() {
HAL_PCD_Start(_pcd);
}*/
//UsbDevice(PCD_HandleTypeDef* pcd);
/*void initPHY() {
_pcd->Instance = USB_OTG_FS;
_pcd->Init.dev_endpoints = 1;
_pcd->Init.speed = PCD_SPEED_FULL;
_pcd->Init.dma_enable = DISABLE;
_pcd->Init.Sof_enable = DISABLE;
_pcd->Init.ep0_mps = 64;
_pcd->Init.phy_itface = PCD_PHY_EMBEDDED;
_pcd->Init.low_power_enable = DISABLE;
_pcd->Init.lpm_enable = DISABLE;
_pcd->Init.vbus_sensing_enable = DISABLE;
_pcd->Init.use_dedicated_ep1 = DISABLE;
//_pcd->Init.battery_charging_enable = DISABLE;
HAL_PCD_Init(_pcd);
//HAL_PCD_SetRxFiFo(&USBD_PCD, 0x80);
//HAL_PCD_SetTxFiFo(&USBD_PCD, 0, 0x20);
//HAL_PCD_SetTxFiFo(&USBD_PCD, 1, 0x40);
HAL_PCD_SetRxFiFo(_pcd, 0x80);
HAL_PCD_SetTxFiFo(_pcd, 0, 0x40);
HAL_PCD_SetTxFiFo(_pcd, 1, 0x80);
}*/
void connect() {
//HAL_PCD_DevConnect(_pcd);
}
void disconnect() {
//HAL_PCD_DevDisconnect(_pcd);
}
//PCD_HandleTypeDef* _pcd;
};
}
#endif // Stm32FsPhy_h__
@@ -0,0 +1,211 @@
#ifndef UsbDeviceSoftPhy_h__
#define UsbDeviceSoftPhy_h__
#include <iostream>
#include <vector>
#include <queue>
namespace LFramework {
namespace USB {
static const char* StageStrings[] = { "WaitForConnection", "Reset1", "GetDeviceDescriptor", "Reset2" };
class SoftEndpoint {
public:
bool isIn = false;
bool isOpen = false;
uint8_t maxPacketSize = 0;
bool receiving = false;
std::queue<std::vector<uint8_t>> packets;
};
template<typename Device>
class UsbDeviceSoftPhy {
public:
static constexpr uint8_t MaxEndpointsCount = 16;
static constexpr uint8_t MaxPacketSize = 64;
void connect() {
_connected = true;
}
void start() {
if (_running) {
return;
}
_running = true;
setStage(Stage::WaitForConnection);
_usbThread = std::thread(std::bind(&UsbDeviceSoftPhy::threadHandler, this));
}
void stop() {
if (_running) {
_running = false;
_usbThread.join;
}
}
enum class Stage {
WaitForConnection,
Reset1,
GetDeviceDescriptor,
Reset2,
StageCount
};
UsbDeviceSoftPhy() {
_stageHandlers[static_cast<int>(Stage::WaitForConnection)] = &UsbDeviceSoftPhy::stageWaitForConnection;
_stageHandlers[static_cast<int>(Stage::Reset1)] = &UsbDeviceSoftPhy::stageReset1;
_stageHandlers[static_cast<int>(Stage::GetDeviceDescriptor)] = &UsbDeviceSoftPhy::stageGetDeviceDescriptor;
_stageHandlers[static_cast<int>(Stage::Reset2)] = &UsbDeviceSoftPhy::stageReset2;
}
Device* asDevice() {
return static_cast<Device*>(this);
}
static bool isValidPacketSize(uint8_t maxPacketSize, EndpointAddress endpointAddress) {
return true;
}
bool openEndpoint(EndpointAddress address, uint8_t maxPacketSize, EndpointType type) {
if(!isValidPacketSize(maxPacketSize, address)) {
std::cout << "Failed to open endpoint with address " << address.value << std::endl;
return false;
}
SoftEndpoint& endpoint = address.isIn() ? _inEndpoints[address.index()] : _outEndpoints[address.index()];
endpoint.maxPacketSize = maxPacketSize;
endpoint.isOpen = true;
std::cout << "Open endpoint with address " << (int)address.value << std::endl;
return true;
}
void closeEndpoint(EndpointAddress address) {
SoftEndpoint& endpoint = address.isIn() ? _inEndpoints[address.index()] : _outEndpoints[address.index()];
endpoint.isOpen = false;
endpoint.packets.clear();
}
void beginReceive(EndpointAddress address, void* buffer, uint8_t size) {
auto& ep = _outEndpoints[address.index()];
ep.receiving = true;
}
void beginTransmit(EndpointAddress address, void* buffer, uint8_t size) {
auto& ep = _inEndpoints[address.index()];
size = (std::min)(size, ep.maxPacketSize);
std::vector<uint8_t> packet;
if(size != 0) {
packet.insert(packet.end(), (uint8_t*)buffer, (uint8_t*)buffer + size);
}
ep.packets.push(packet);
}
private:
void setStage(Stage stage) {
std::cout << "Change stage from " << StageStrings[(int)_currentStage] << " to " << StageStrings[(int)stage] << std::endl;
_currentStage = stage;
if(_currentStage == Stage::WaitForConnection) {
for(auto& ep : _inEndpoints) {
ep.isOpen = false;
ep.receiving = false;
ep.packets = {};
}
for (auto& ep : _outEndpoints) {
ep.isOpen = false;
ep.receiving = false;
ep.packets = {};
}
}
}
SoftEndpoint _inEndpoints[MaxEndpointsCount];
SoftEndpoint _outEndpoints[MaxEndpointsCount];
Stage _currentStage = Stage::WaitForConnection;
void stageWaitForConnection() {
if (_connected) {
std::cout << "Device connected" << std::endl;
setStage(Stage::Reset1);
}
}
void stageReset1() {
std::cout << "Device reset1 begin" << std::endl;
asDevice()->onReset();
std::cout << "Device reset1 end" << std::endl;
setStage(Stage::GetDeviceDescriptor);
}
std::vector<uint8_t> controlIn(SetupPacket setup) {
/*SetupPacket setup;
setup.bmRequestType.Direction = RequestDirection::DeviceToHost;
setup.bmRequestType.Recipient = RequestRecipient::Device;
setup.bmRequestType.Type = RequestType::Standard;*/
asDevice()->onSetup(&setup);
std::vector<uint8_t> rxBuffer;
auto& ep = _inEndpoints[0];
for (;;) {
if(ep.isOpen) {
if(!ep.packets.empty()) {
auto packet = ep.packets.front();
ep.packets.pop();
if(packet.empty()) {
return rxBuffer;
}else {
rxBuffer.insert(rxBuffer.end(), packet.begin(), packet.end());
}
}
}
Sleep(1);
}
}
void stageGetDeviceDescriptor() {
SetupPacket setup;
setup.bmRequestType.Direction = RequestDirection::DeviceToHost;
setup.bmRequestType.Recipient = RequestRecipient::Device;
setup.bmRequestType.Type = RequestType::Standard;
setup.bRequest = SetupRequest::GetDescriptor;
setup.wIndex = 0;
setup.wValue = ((uint8_t)DescriptorType::DeviceDescriptor << 8) | 0;
setup.wLength = sizeof(DeviceDescriptor);
auto descriptorData = controlIn(setup);
for (;;);
}
void stageReset2() {
}
void threadHandler() {
while (_running) {
(this->*_stageHandlers[static_cast<int>(_currentStage)])();
Sleep(1);
}
}
std::array<void(UsbDeviceSoftPhy::*)(), static_cast<int>(Stage::StageCount)> _stageHandlers;
std::thread _usbThread;
bool _connected = false;
bool _running = false;
};
}
}
#endif // UsbDeviceSoftPhy_h__
@@ -0,0 +1,19 @@
/*
* UsbInternalFsDeviceDriver.h
*
* Created on: 1 îêò. 2017 ã.
* Author: l-pro
*/
#ifndef LFRAMEWORK_MCU_USBDEVICE_USBINTERNALFSDEVICEDRIVER_H_
#define LFRAMEWORK_MCU_USBDEVICE_USBINTERNALFSDEVICEDRIVER_H_
namespace LFramework {
namespace USB {
}
}
#endif /* LFRAMEWORK_MCU_USBDEVICE_USBINTERNALFSDEVICEDRIVER_H_ */
@@ -0,0 +1,8 @@
target_sources(${PROJECT_NAME}
INTERFACE
HalLibrary.h
HardFaultHandler.h
HardFaultHandler.cpp
)
@@ -0,0 +1,15 @@
/*
* HalLibrary.h
*
* Created on: 17 ñåíò. 2017 ã.
* Author: l-pro
*/
#ifndef LFRAMEWORK_MCU_STM32_HALLIBRARY_H_
#define LFRAMEWORK_MCU_STM32_HALLIBRARY_H_
#endif /* LFRAMEWORK_MCU_STM32_HALLIBRARY_H_ */
@@ -0,0 +1,41 @@
#ifndef _WIN32
#include <LFramework/Debug.h>
#include <LFramework/IO/StreamWriter.h>
extern "C" {
void HardFaultHandlerExtended(unsigned int * hardfault_args){
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
stacked_r0 = ((unsigned int)hardfault_args[0]);
stacked_r1 = ((unsigned int)hardfault_args[1]);
stacked_r2 = ((unsigned int)hardfault_args[2]);
stacked_r3 = ((unsigned int)hardfault_args[3]);
stacked_r12 = ((unsigned int)hardfault_args[4]);
stacked_lr = ((unsigned int)hardfault_args[5]);
stacked_pc = ((unsigned int)hardfault_args[6]);
stacked_psr = ((unsigned int)hardfault_args[7]);
lfFatal() << "----------";
lfFatal() << "Hard fault";
lfFatal() << "----------";
lfFatal() << "stacked_lr: 0x" << LFramework::HexFormat(stacked_lr) ;
lfFatal() << "stacked_pc: 0x" << LFramework::HexFormat(stacked_pc) ;
while(true){
asm("nop");
}
}
}
#endif
@@ -0,0 +1,14 @@
#pragma once
#define HARD_FAULT_HANDLER \
__asm( ".syntax unified\n" \
"MOVS R0, #4 \n" \
"MOV R1, LR \n" \
"TST R0, R1 \n" \
"BEQ _MSP \n" \
"MRS R0, PSP \n" \
"B HardFaultHandlerExtended \n" \
"_MSP: \n" \
"MRS R0, MSP \n" \
"B HardFaultHandlerExtended \n" \
".syntax divided\n") ;
@@ -0,0 +1,4 @@
target_sources(${PROJECT_NAME}
INTERFACE
ForEach.h
)
+76
View File
@@ -0,0 +1,76 @@
#ifndef ForEach_h__
#define ForEach_h__
#define UNPACK(...) __VA_ARGS__
//Count of commas == max args count (32)
#define CNT_PREFIX__CNT_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
#define COUNTER_SEQUENCE 32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
#define ARGS_CNT2(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31, N, ...) N
#define ARGS_CNT1(__ARGS) ARGS_CNT2 __ARGS
#define ARGS_CNT(...) UNPACK(ARGS_CNT1((CNT_PREFIX_ ## __VA_ARGS__ ## _CNT_POSTFIX, COUNTER_SEQUENCE)))
#define CONCAT(arg1, arg2) CONCAT1(arg1, arg2)
#define CONCAT1(arg1, arg2) CONCAT2(arg1, arg2)
#define CONCAT2(arg1, arg2) arg1##arg2
#define FOR_EACH_0(macro, runner, ...)
#define FOR_EACH_1(macro, runner, x) runner(macro, 0, LAST, x)
#define FOR_EACH_2(macro, runner, x, ...) runner(macro, 1, NOT_LAST, x) UNPACK(FOR_EACH_1(macro, runner, __VA_ARGS__))
#define FOR_EACH_3(macro, runner, x, ...) runner(macro, 2, NOT_LAST, x) UNPACK(FOR_EACH_2(macro, runner, __VA_ARGS__))
#define FOR_EACH_4(macro, runner, x, ...) runner(macro, 3, NOT_LAST, x) UNPACK(FOR_EACH_3(macro, runner, __VA_ARGS__))
#define FOR_EACH_5(macro, runner, x, ...) runner(macro, 4, NOT_LAST, x) UNPACK(FOR_EACH_4(macro, runner, __VA_ARGS__))
#define FOR_EACH_6(macro, runner, x, ...) runner(macro, 5, NOT_LAST, x) UNPACK(FOR_EACH_5(macro, runner, __VA_ARGS__))
#define FOR_EACH_7(macro, runner, x, ...) runner(macro, 6, NOT_LAST, x) UNPACK(FOR_EACH_6(macro, runner, __VA_ARGS__))
#define FOR_EACH_8(macro, runner, x, ...) runner(macro, 7, NOT_LAST, x) UNPACK(FOR_EACH_7(macro, runner, __VA_ARGS__))
#define FOR_EACH_9(macro, runner, x, ...) runner(macro, 8, NOT_LAST, x) UNPACK(FOR_EACH_8(macro, runner, __VA_ARGS__))
#define FOR_EACH_10(macro, runner, x, ...) runner(macro, 9, NOT_LAST, x) UNPACK(FOR_EACH_9(macro, runner, __VA_ARGS__))
#define FOR_EACH_11(macro, runner, x, ...) runner(macro, 10, NOT_LAST, x) UNPACK(FOR_EACH_10(macro, runner, __VA_ARGS__))
#define FOR_EACH_12(macro, runner, x, ...) runner(macro, 11, NOT_LAST, x) UNPACK(FOR_EACH_11(macro, runner, __VA_ARGS__))
#define FOR_EACH_13(macro, runner, x, ...) runner(macro, 12, NOT_LAST, x) UNPACK(FOR_EACH_12(macro, runner, __VA_ARGS__))
#define FOR_EACH_14(macro, runner, x, ...) runner(macro, 13, NOT_LAST, x) UNPACK(FOR_EACH_13(macro, runner, __VA_ARGS__))
#define FOR_EACH_15(macro, runner, x, ...) runner(macro, 14, NOT_LAST, x) UNPACK(FOR_EACH_14(macro, runner, __VA_ARGS__))
#define FOR_EACH_16(macro, runner, x, ...) runner(macro, 15, NOT_LAST, x) UNPACK(FOR_EACH_15(macro, runner, __VA_ARGS__))
#define FOR_EACH_17(macro, runner, x, ...) runner(macro, 16, NOT_LAST, x) UNPACK(FOR_EACH_16(macro, runner, __VA_ARGS__))
#define FOR_EACH_18(macro, runner, x, ...) runner(macro, 17, NOT_LAST, x) UNPACK(FOR_EACH_17(macro, runner, __VA_ARGS__))
#define FOR_EACH_19(macro, runner, x, ...) runner(macro, 18, NOT_LAST, x) UNPACK(FOR_EACH_18(macro, runner, __VA_ARGS__))
#define FOR_EACH_20(macro, runner, x, ...) runner(macro, 19, NOT_LAST, x) UNPACK(FOR_EACH_19(macro, runner, __VA_ARGS__))
#define FOR_EACH_21(macro, runner, x, ...) runner(macro, 20, NOT_LAST, x) UNPACK(FOR_EACH_20(macro, runner, __VA_ARGS__))
#define FOR_EACH_22(macro, runner, x, ...) runner(macro, 21, NOT_LAST, x) UNPACK(FOR_EACH_21(macro, runner, __VA_ARGS__))
#define FOR_EACH_23(macro, runner, x, ...) runner(macro, 22, NOT_LAST, x) UNPACK(FOR_EACH_22(macro, runner, __VA_ARGS__))
#define FOR_EACH_24(macro, runner, x, ...) runner(macro, 23, NOT_LAST, x) UNPACK(FOR_EACH_23(macro, runner, __VA_ARGS__))
#define FOR_EACH_25(macro, runner, x, ...) runner(macro, 24, NOT_LAST, x) UNPACK(FOR_EACH_24(macro, runner, __VA_ARGS__))
#define FOR_EACH_26(macro, runner, x, ...) runner(macro, 25, NOT_LAST, x) UNPACK(FOR_EACH_25(macro, runner, __VA_ARGS__))
#define FOR_EACH_27(macro, runner, x, ...) runner(macro, 26, NOT_LAST, x) UNPACK(FOR_EACH_26(macro, runner, __VA_ARGS__))
#define FOR_EACH_28(macro, runner, x, ...) runner(macro, 27, NOT_LAST, x) UNPACK(FOR_EACH_27(macro, runner, __VA_ARGS__))
#define FOR_EACH_29(macro, runner, x, ...) runner(macro, 28, NOT_LAST, x) UNPACK(FOR_EACH_28(macro, runner, __VA_ARGS__))
#define FOR_EACH_30(macro, runner, x, ...) runner(macro, 29, NOT_LAST, x) UNPACK(FOR_EACH_29(macro, runner, __VA_ARGS__))
#define FOR_EACH_31(macro, runner, x, ...) runner(macro, 30, NOT_LAST, x) UNPACK(FOR_EACH_30(macro, runner, __VA_ARGS__))
#define FOR_EACH_32(macro, runner, x, ...) runner(macro, 31, NOT_LAST, x) UNPACK(FOR_EACH_31(macro, runner, __VA_ARGS__))
#define FOREACH_SIMPLE_RUNNER(macro, id, isLast, x) macro(x)
#define FOREACH_INDEXED_RUNNER(macro, id, isLast, x) macro(id, x)
#define FOREACH_SIMPLE_RUNNER_ISLAST(macro, id, isLast, x) macro(isLast, x)
#define FOR_EACH1_R(macro, runner, N, ...) UNPACK(CONCAT(FOR_EACH_, N)(macro, runner, __VA_ARGS__))
#define FOR_EACH_R(macro, runner, ...) UNPACK(FOR_EACH1_R(macro, runner, ARGS_CNT(__VA_ARGS__), __VA_ARGS__))
#define FOR_EACH(macro, ...) FOR_EACH_R(macro, FOREACH_SIMPLE_RUNNER, __VA_ARGS__)
#define FOR_EACH_N(macro, ...) FOR_EACH_R(macro, FOREACH_INDEXED_RUNNER, __VA_ARGS__)
#define FOR_EACH_L(macro, ...) FOR_EACH_R(macro, FOREACH_SIMPLE_RUNNER_ISLAST, __VA_ARGS__)
static_assert(ARGS_CNT() == 0, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a) == 1, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a, a) == 2, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a, a, a, a) == 4, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a, a, a, a, a, a, a, a) == 8, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a) == 16, "ARGS_CNT test fail");
static_assert(ARGS_CNT(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a) == 32, "ARGS_CNT test fail");
#endif // ForEach_h__
@@ -0,0 +1,71 @@
#include "../Macro/ForEach.h"
#define COMMA_LAST(x) x
#define COMMA_NOT_LAST(x) x ,
#define JOIN_IMPL(last, x) COMMA_##last(x)
#define JOIN2(...) UNPACK(FOR_EACH_L(JOIN_IMPL, __VA_ARGS__))
#define JOIN(...) UNPACK( JOIN2 (__VA_ARGS__) )
template<typename T>
struct Reflect {
};
#define GEN_FIELD2(type_, name_) type_ name_;
#define GEN_FIELD(field_) GEN_FIELD2 field_
#define GEN_FIELD_GETTER2(id_, type_, name_) if constexpr(ID == FieldsCount - 1 - id_) return object. name_;
#define GEN_FIELD_GETTER1(id_, ...) UNPACK(GEN_FIELD_GETTER2(id_, __VA_ARGS__))
#define GEN_FIELD_GETTER(id_, ...) GEN_FIELD_GETTER1(id_, UNPACK __VA_ARGS__ )
#define DEFINE_STRUCT_RTTI(structName_, publicFields_) \
template<> struct Reflect<structName_> { \
static const char* Name() {return #structName_; } \
static constexpr size_t FieldsCount = ARGS_CNT(UNPACK publicFields_) ; \
template<size_t ID> static auto& getField(structName_& object){ \
FOR_EACH_N(GEN_FIELD_GETTER, UNPACK publicFields_) ; \
} \
};
#define DEFINE_STRUCT_TYPE(structName_, publicFields_) struct structName_ { FOR_EACH(GEN_FIELD, UNPACK publicFields_) };
#define DEFINE_STRUCT(structName_, publicFields_) \
DEFINE_STRUCT_TYPE(structName_, publicFields_) \
DEFINE_STRUCT_RTTI(structName_, publicFields_)
#define UNPACK_TEMPLATE_PARAMS1(last_, type_, name_) COMMA_##last_(type_ name_)
#define UNPACK_TEMPLATE_PARAM1(last, ...) UNPACK( UNPACK_TEMPLATE_PARAMS1(last, __VA_ARGS__ ))
#define UNPACK_TEMPLATE_PARAM(last, x) UNPACK_TEMPLATE_PARAM1(last, UNPACK x)
#define UNPACK_TEMPLATE_ARGS1(last_, type_, name_) COMMA_##last_(name_)
#define UNPACK_TEMPLATE_ARG1(last, ...) UNPACK( UNPACK_TEMPLATE_ARGS1(last, __VA_ARGS__ ))
#define UNPACK_TEMPLATE_ARG(last, x) UNPACK_TEMPLATE_ARG1(last, UNPACK x)
#define UNPACK_TEMPLATE_PARAMS(...) UNPACK (FOR_EACH_L(UNPACK_TEMPLATE_PARAM, __VA_ARGS__) )
#define UNPACK_TEMPLATE_ARGS(...) UNPACK (FOR_EACH_L(UNPACK_TEMPLATE_ARG, __VA_ARGS__) )
#define DEFINE_TEMPLATE_STRUCT_RTTI(templateParams_, structName_, publicFields_) \
template< UNPACK_TEMPLATE_PARAMS templateParams_ > struct Reflect<structName_< UNPACK_TEMPLATE_ARGS templateParams_ > > { \
static const char* Name() {return #structName_; } \
static constexpr size_t FieldsCount = ARGS_CNT(UNPACK publicFields_) ; \
template<size_t ID> static auto& getField(structName_ < UNPACK_TEMPLATE_ARGS templateParams_ > & object){ \
FOR_EACH_N(GEN_FIELD_GETTER, UNPACK publicFields_) ; \
} \
};
#define DEFINE_TEMPLATE_STRUCT_TYPE(templateParams_, structName_, publicFields_) template< UNPACK_TEMPLATE_PARAMS templateParams_ > struct structName_ { FOR_EACH(GEN_FIELD, UNPACK publicFields_) };
#define DEFINE_TEMPLATE_STRUCT(templateParams_, structName_, publicFields_) \
DEFINE_TEMPLATE_STRUCT_TYPE(templateParams_, structName_, publicFields_) \
DEFINE_TEMPLATE_STRUCT_RTTI(templateParams_, structName_, publicFields_)
+167
View File
@@ -0,0 +1,167 @@
#include "Detect/DetectOS.h"
#include "Assert.h"
#if defined(LF_NEWLIB_TO_RTOS_MALLOC)
#include "FreeRTOS.h"
#endif
#if defined(LF_SYSCALLS_STUBS) || defined(LF_NEWLIB_TO_RTOS_MALLOC)
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "Debug.h"
#include "System.h"
#include <malloc.h>
#endif//Todo check right files for different configuration
extern "C" {
#if defined(LF_SYSCALLS_STUBS)
//extern int errno;
//register char * stack_ptr asm("sp");
#ifndef __errno_r
#include <sys/reent.h>
#define __errno_r(reent) reent->_errno
#endif
caddr_t _sbrk(int incr) {
static_cast<void>(incr);
//std::terminate(); //Do not use newlib memory management
for(;;);
return nullptr;
}
int _write_r(struct _reent* r, int file, char* ptr, int len){
static_cast<void>(r);
static_cast<void>(ptr);
if(stdout->_file != file && stderr->_file != file){
for(;;);//Assert: unknown file descriptor
}
#if defined(AF_TERMINAL_STDIO)
Terminal::write(ptr, len);
#endif
return len;
}
int _read_r(struct _reent *r, int file, char * ptr, int len)
{
(void)r;
(void)file;
(void)ptr;
(void)len;
__errno_r(r) = EINVAL;
return -1;
}
int _lseek_r(struct _reent *r, int file, int ptr, int dir){
(void)r;
(void)file;
(void)ptr;
(void)dir;
return 0;
}
int _close_r(struct _reent *r, int file){
(void)r;
(void)file;
return 0;
}
int _open_r ( struct _reent *ptr, const char *file, int flags, int mode ){
static_cast<void>(ptr);
static_cast<void>(file);
static_cast<void>(flags);
static_cast<void>(mode);
int fd = -1;
return fd;
}
int _fstat_r(struct _reent *r, int file, struct stat * st){
(void)r;
(void)file;
memset(st, 0, sizeof(*st));
st->st_mode = S_IFCHR;
return 0;
}
int _isatty_r(struct _reent *r, int fd){
(void)r;
(void)fd;
return 1;
}
int _kill (int a, int b){
(void)a;
(void)b;
return 0;
}
int _getpid(int a){
(void)a;
return 0;
}
#endif
//memory management
#if LF_TARGET_OS == LF_OS_FREERTOS || defined(LF_SYSCALLS_STUBS)
void __assert_func(const char * file, int line, const char * func, const char * error){
lfDebug() << "libc assert";
lfDebug() << "File: " << file;
//lfDebug() << "Line: " << line;
lfDebug() << "Function: " << func;
lfDebug() << "Expression: " << error;
for(;;);
}
void _exit(int status){
lfDebug() << "_exit called";
for(;;);
}
#endif
#if defined(LF_NEWLIB_TO_RTOS_MALLOC)
void* _realloc_r(struct _reent *re, void* oldAddr, size_t newSize) {
static_cast<void>(re);
static_cast<void>(oldAddr);
static_cast<void>(newSize);
lfAssert(false); //No mechanism is currently available to correctly reallocate memory, so just don't allow it for now
return nullptr;
}
void* _calloc_r(struct _reent *re, size_t num, size_t size) {
static_cast<void>(re);
void* result = pvPortMalloc(num*size);
if(result){
//calloc should zero-initialize allocated memory
uint8_t* bytes = (uint8_t*)result;
for(size_t i = 0; i < (num * size); ++i){
bytes[i] = 0;
}
}
return result;
}
void* _malloc_r(struct _reent *re, size_t size) {
static_cast<void>(re);
return pvPortMalloc(size);
}
void _free_r(struct _reent *re, void* ptr) {
static_cast<void>(re);
vPortFree(ptr);
}
#endif
} //extern "C"
+16
View File
@@ -0,0 +1,16 @@
#ifndef System_h__
#define System_h__
#include <cstddef>
#include "Detect/DetectOS.h"
#if LF_TARGET_OS == LF_OS_FREERTOS
#include "SystemArmCortexM.h"
#elif LF_TARGET_OS == LF_OS_WINDOWS
#include "SystemWindows.h"
#endif
#endif // System_h__
@@ -0,0 +1,32 @@
#pragma once
#include <cstdint>
#include <cstddef>
#ifndef CMSIS_DEVICE_FILE
#error "CMSIS_DEVICE_FILE path not defined in McuConfig.h"
#else
#include CMSIS_DEVICE_FILE
#endif
namespace LFramework {
namespace System {
inline size_t getCurrentInterruptHandlerIndex() {
return __get_IPSR();
}
inline bool isHandlingInterrupt() {
return getCurrentInterruptHandlerIndex() != 0;
}
inline bool isDebuggerAttached() {
return (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk) != 0;
}
inline void setBreakpoint() {
if (isDebuggerAttached) {
__BKPT(0);
}
}
}
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef SystemWindows_h__
#define SystemWindows_h__
#include <Windows.h>
namespace LFramework {
namespace System {
inline size_t getCurrentInterruptHandlerIndex() {
return 0;
}
inline bool isHandlingInterrupt() {
return false;
}
inline bool isDebuggerAttached() {
return IsDebuggerPresent() == TRUE;
}
inline void setBreakpoint() {
if (isDebuggerAttached()) {
DebugBreak();
}
}
}
}
#endif // SystemWindows_h__
+87
View File
@@ -0,0 +1,87 @@
#pragma once
#include <codecvt>
#include <string>
namespace LFramework::Text {
class Encoding {
public:
#if defined(_MSC_VER) && _MSC_VER >= 1900
// https://social.msdn.microsoft.com/Forums/en-US/8f40dcd8-c67f-4eba-9134-a19b9178e481/vs-2015-rc-linker-stdcodecvt-error?forum=vcgeneral
#define _MSVC_CONVERT_WORKAROUND
#endif
#if defined(_MSVC_CONVERT_WORKAROUND)
static inline std::wstring_convert<std::codecvt_utf8<int32_t>, int32_t> s_u32Converter;
static inline std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> s_u16Converter;
#else
static inline std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> s_u32Converter;
static inline std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> s_u16Converter;
#endif
static std::wstring u8StringToWString(const std::string& src) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
return converter.from_bytes(src);
}
static std::string wStringToU8String(const std::wstring& src) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
return convert.to_bytes(src);
}
static std::u32string u16StringToU32String(const std::u16string& u16String)
{
std::string temp{ u16StringToU8String(u16String) };
return u8StringToU32String(temp);
}
static std::string u16StringToU8String(const std::u16string& u16String)
{
#if defined(_MSVC_CONVERT_WORKAROUND)
using workaround_str = std::basic_string<int16_t, std::char_traits<int16_t>, std::allocator<int16_t> >;
workaround_str workaround(reinterpret_cast<const int16_t*>(u16String.c_str()));
return s_u16Converter.to_bytes(workaround);
#else
return s_u16Converter.to_bytes(u16String);
#endif
}
static std::string u32StringToU8String(const std::u32string& u32String)
{
#if defined(_MSVC_CONVERT_WORKAROUND)
using workaround_str = std::basic_string<int32_t, std::char_traits<int32_t>, std::allocator<int32_t> >;
workaround_str workaround(reinterpret_cast<const int32_t*>(u32String.c_str()));
return s_u32Converter.to_bytes(workaround);
#else
return s_u32Converter.to_bytes(u32String);
#endif
}
static std::u16string u8StringToU16String(const std::string& u8String)
{
#if defined(_MSVC_CONVERT_WORKAROUND)
auto&& workaround = s_u16Converter.from_bytes(u8String);
return std::u16string(reinterpret_cast<const char16_t*>(workaround.c_str()));
#else
return s_u16Converter.from_bytes(u8String);
#endif
}
static std::u32string u8StringToU32String(const std::string& u8String)
{
#if defined(_MSVC_CONVERT_WORKAROUND)
auto&& workaround = s_u32Converter.from_bytes(u8String);
return std::u32string(reinterpret_cast<const char32_t*>(workaround.c_str()));
#else
return s_u32Converter.from_bytes(u8String);
#endif
}
};
}
#ifdef _MSVC_CONVERT_WORKAROUND
#undef _MSVC_CONVERT_WORKAROUND
#endif
@@ -0,0 +1,21 @@
add_library(LFrameworkThreading INTERFACE )
add_library(LFramework::Threading ALIAS LFrameworkThreading )
target_sources(LFrameworkThreading
INTERFACE
CriticalSection.h
CriticalSectionFreeRTOS.h
CriticalSectionStd.h
Semaphore.h
SemaphoreFreeRTOS.h
SemaphoreStd.h
Thread.h
ThreadFreeRTOS.h
ThreadPlatform.h
ThreadStd.h
CriticalSectionStd.cpp
SemaphoreStdTest.cpp
Thread.cpp
ThreadTest.cpp
)
@@ -0,0 +1,10 @@
#pragma once
#include <LFramework/Detect/DetectOS.h>
#if LF_TARGET_OS == LF_OS_FREERTOS
#include "CriticalSectionFreeRTOS.h"
#elif (LF_TARGET_OS == LF_OS_WINDOWS) || (LF_TARGET_OS == LF_OS_LINUX)
#include "CriticalSectionStd.h"
#endif
@@ -0,0 +1,53 @@
#pragma once
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f746xx.h"
namespace LFramework::Threading {
class CriticalSection {
public:
CriticalSection() {
_status = lock();
}
~CriticalSection() {
unlock();
}
void unlock() {
unlock(_status);
}
static size_t getCurrentInterruptNumber() {
return __get_IPSR();
}
static bool isInterruptHandling() {
return getCurrentInterruptNumber() != 0;
}
static uint32_t lock() {
if (isInterruptHandling()) {
return taskENTER_CRITICAL_FROM_ISR();
}
else {
taskENTER_CRITICAL();
}
return 0;
}
static void unlock(uint32_t irqStatus) {
if (isInterruptHandling()) {
taskEXIT_CRITICAL_FROM_ISR(irqStatus);
}
else {
taskEXIT_CRITICAL();
}
}
private:
uint32_t _status = 0;
};
}
@@ -0,0 +1,7 @@
#include <LFramework/Detect/DetectOS.h>
#if (LF_TARGET_OS == LF_OS_WINDOWS) || (LF_TARGET_OS == LF_OS_LINUX)
#include <LFramework/Threading/CriticalSectionStd.h>
std::recursive_mutex LFramework::Threading::CriticalSection::_lock;
#endif
@@ -0,0 +1,31 @@
#pragma once
#include <cstdint>
#include <mutex>
namespace LFramework::Threading {
class CriticalSection {
public:
CriticalSection() {
lock();
}
~CriticalSection() {
unlock(0);
}
static uint32_t lock() {
_lock.lock();
return 0;
}
static void unlock(int ) {
_lock.unlock();
}
private:
static std::recursive_mutex _lock;
};
}
@@ -0,0 +1,10 @@
#pragma once
#include <LFramework/Detect/DetectOS.h>
#if LF_TARGET_OS == LF_OS_FREERTOS
#include "SemaphoreFreeRTOS.h"
#elif (LF_TARGET_OS == LF_OS_WINDOWS) || (LF_TARGET_OS == LF_OS_LINUX)
#include "SemaphoreStd.h"
#endif
@@ -0,0 +1,73 @@
#pragma once
#include "../MCU/Mcu.h"
#include <cassert>
#include <cstdint>
#include "FreeRTOS.h"
#include "portable.h"
#include "queue.h"
#include "semphr.h"
namespace LFramework::Threading {
class Semaphore {
public:
~Semaphore(){
vSemaphoreDelete(_handle);
}
size_t messagesWaiting() const {
return (size_t)uxQueueMessagesWaiting(_handle);
}
bool take(TickType_t wait = portMAX_DELAY) {
if (LFramework::Mcu::isHandlingInterrupt()) {
portBASE_TYPE taskWoken = pdFALSE;
if (xSemaphoreTakeFromISR(_handle, &taskWoken) != pdTRUE) {
return false;
}
portEND_SWITCHING_ISR(taskWoken);
return true;
} else {
return xSemaphoreTake(_handle, wait) == pdTRUE;
}
}
bool give() {
if (LFramework::Mcu::isHandlingInterrupt()) {
portBASE_TYPE taskWoken = pdFALSE;
if (xSemaphoreGiveFromISR(_handle, &taskWoken) != pdTRUE) {
return false;
}
portEND_SWITCHING_ISR(taskWoken);
return true;
} else {
return xSemaphoreGive(_handle) == pdTRUE;
}
}
protected:
SemaphoreHandle_t _handle;
};
class BinarySemaphore : public Semaphore{
public:
BinarySemaphore(){
_handle = xSemaphoreCreateBinary();
assert(_handle != nullptr);
}
};
class CountingSemaphore : public Semaphore{
public:
CountingSemaphore(UBaseType_t maxCount, UBaseType_t initialCount){
_handle = xSemaphoreCreateCounting(maxCount, initialCount);
assert(_handle != nullptr);
}
};
}
@@ -0,0 +1,85 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <atomic>
namespace LFramework::Threading {
class CountingSemaphore {
public:
static constexpr std::size_t InfiniteTimeout = -1;
CountingSemaphore(std::size_t maxCount, std::size_t initialCount) :_maxCount(maxCount), _count(initialCount) {
}
bool take() {
std::unique_lock<std::mutex> lk(_mutex);
_conditional.wait(lk, [this] { return _count > 0; });
--_count;
return true;
}
bool take(std::size_t milliseconds) {
std::unique_lock<std::mutex> lk(_mutex);
if (_conditional.wait_for(lk, ::std::chrono::milliseconds(milliseconds), [this] { return _count > 0; })) {
--_count;
return true;
}
return false;
}
bool tryTake() {
std::lock_guard<::std::mutex> lk(_mutex);
if (_count > 0) {
--_count;
return true;
}
else {
return false;
}
}
bool give(std::size_t count) {
if(count == 0){
return true;
}
std::lock_guard<::std::mutex> lk(_mutex);
if ((_count + count) <= _maxCount) {
_count += count;
if(count > 1){
_conditional.notify_all();
}else{
_conditional.notify_one();
}
return true;
}
return false;
}
bool give() {
std::lock_guard<::std::mutex> lk(_mutex);
if (_count < _maxCount) {
++_count;
_conditional.notify_one();
return true;
}
return false;
}
std::size_t messagesWaiting() const {
return _count.load(std::memory_order_relaxed);
}
private:
std::size_t _maxCount = -1;
std::atomic<std::size_t> _count = 0;
std::mutex _mutex;
std::condition_variable _conditional;
};
class BinarySemaphore : public CountingSemaphore {
public:
BinarySemaphore(bool startWithValue = false) : CountingSemaphore(1, startWithValue ? 1 : 0){ }
};
}
@@ -0,0 +1,57 @@
#include "../UnitTest/UnitTest.h"
#ifdef LF_THREADING
#include "SemaphoreStd.h"
#include "Thread.h"
#include <vector>
using namespace LFramework;
TEST(SemaphoreStd_SyncUsage) {
Semaphore s0;
TEST_TRUE(s0.available() == 0);
s0.give();
TEST_TRUE(s0.available() == 1);
s0.give(9);
TEST_TRUE(s0.available() == 10);
s0.take(0);
TEST_TRUE(s0.available() == 10);
s0.take();
TEST_TRUE(s0.available() == 9);
s0.take(9);
TEST_TRUE(s0.available() == 0);
}
TEST(SemaphoreStd_AsyncUsage) {
static constexpr size_t initialCount = 25;
Semaphore resources(initialCount);
Thread consumerThread0 = Thread("", 0, ThreadPriority::Normal, [&resources]() {
for(size_t i = 0; i < 100; ++i) {
resources.take();
ThisThread::sleepForMs(1);
}
});
Thread consumerThread1 = Thread("", 0, ThreadPriority::Normal, [&resources]() {
for (size_t i = 0; i < 10; ++i) {
resources.take(10);
ThisThread::sleepForMs(2);
}
});
for(size_t i = 0; i < (200 - initialCount); i += 5) {
resources.give(5);
}
consumerThread0.join();
consumerThread1.join();
}
#endif
@@ -0,0 +1,77 @@
#include <LFramework/Threading/Thread.h>
#include <LFramework/Threading/ThreadFreeRTOS.h>
#include <LFramework/Threading/ThreadStd.h>
namespace LFramework::Threading {
Thread::Thread(const char* name, size_t stackSize, ThreadPriority priority, std::function<void()>&& func) {
_impl = new Thread::Impl(name, stackSize, priority, std::move(func));
}
Thread::Thread() noexcept = default;
Thread::Thread(Thread&& other) noexcept{
moveTask(other);
}
Thread::~Thread() {
assert(!joinable());
//_impl.reset();
}
bool Thread::joinable() const noexcept {
return _impl != nullptr;
}
void Thread::join() {
assert(joinable());
assert(ThisThread::getId() != getId()); //Can't join self
_impl->join();
delete _impl;
_impl = nullptr;
}
void Thread::swap(Thread& other) {
std::swap(_impl, other._impl);
}
/*Thread::NativeHandleType Thread::nativeHandle() const {
assert(joinable());
return _impl->getNativeHandle();
}*/
Thread::ID Thread::getId() const noexcept {
if (_impl != nullptr) {
return _impl->getId();
}
return Thread::ID{};
}
ThreadPriority Thread::getPriority() const {
assert(joinable());
return _impl->getPriority();
}
void Thread::setPriority(ThreadPriority priority) const {
assert(joinable());
_impl->setPriority(priority);
}
void Thread::suspend() {
assert(joinable());
_impl->suspend();
}
void Thread::resume() {
assert(joinable());
_impl->resume();
}
Thread& Thread::operator = (Thread&& other) noexcept {
return moveTask(other);
}
const char* Thread::getName() const {
assert(joinable());
return _impl->getName();
}
Thread& Thread::moveTask(Thread& other) {
assert(!joinable());
_impl = std::move(other._impl);
other._impl = nullptr;
return *this;
}
} //LFramework
@@ -0,0 +1,66 @@
#pragma once
#include <cstddef>
#include <cassert>
#include <functional>
#include <memory>
#include <LFramework/Threading/ThreadPlatform.h>
namespace LFramework::Threading {
enum class ThreadPriority{
Idle,
Low,
BelowNormal,
Normal,
AboveNormal,
High,
Realtime,
Error
};
class Thread {
public:
using ID = ThreadID;
explicit Thread(const char* name, size_t stackSize, ThreadPriority priority, std::function<void()>&& func);
~Thread();
Thread() noexcept;
Thread(const Thread&) = delete;
Thread(Thread&& other) noexcept;
Thread& operator = (const Thread&) = delete;
Thread& operator = (Thread&& other) noexcept;
void swap(Thread& other);
bool joinable() const noexcept;
void join();
//TODO: detach
ID getId() const noexcept;
//NativeHandleType nativeHandle() const noexcept;
const char* getName() const;
ThreadPriority getPriority() const;
void setPriority(ThreadPriority priority) const;
void suspend();
void resume();
private:
class Impl;
Thread& moveTask(Thread& other);
Impl* _impl = nullptr;
};
namespace ThisThread {
Thread::ID getId();
ThreadPriority getPriority();
void setPriority(ThreadPriority priority);
void sleepForMs(size_t milliseconds);
}
}
@@ -0,0 +1,92 @@
#pragma once
#include <LFramework/Threading/Thread.h>
#include "../Detect/DetectOS.h"
#if LF_TARGET_OS == LF_OS_FREERTOS
#include <LFramework/Threading/SemaphoreFreeRTOS.h>
#include "task.h"
#endif
namespace LFramework::Threading {
#if LF_TARGET_OS == LF_OS_FREERTOS
static Thread::ID makeThreadId(TaskHandle_t handle) {
return reinterpret_cast<Thread::ID>(handle);
}
static ThreadPriority makeThreadPriority(portBASE_TYPE osPriority) {
return static_cast<ThreadPriority>(osPriority);
}
static portBASE_TYPE makeOsPriority(ThreadPriority priority) {
return static_cast<portBASE_TYPE>(priority);
}
class Thread::Impl {
public:
explicit Impl(const char* name, size_t stackSize, ThreadPriority priority, std::function<void()>&& body) :_body(std::move(body)) {
xTaskCreate(&Impl::staticTaskHandler, name, stackSize, this, (UBaseType_t)priority, &_rtosTaskHandle);
}
void join(){
_joinSemaphore.take();
}
Thread::ID getId() const {
return makeThreadId(_rtosTaskHandle);
}
TaskHandle_t getNativeHandle() const {
return _rtosTaskHandle;
}
const char* getName() const {
return pcTaskGetTaskName(_rtosTaskHandle);
}
void suspend() {
vTaskSuspend(_rtosTaskHandle);
}
void resume() {
vTaskResume(_rtosTaskHandle);
}
ThreadPriority getPriority() const {
return makeThreadPriority(uxTaskPriorityGet(_rtosTaskHandle));
}
void setPriority(ThreadPriority priority) const {
vTaskPrioritySet(_rtosTaskHandle, makeOsPriority(priority));
}
private:
static void staticTaskHandler(void* param) {
Impl* _this = (Impl*)param;
_this->taskHandler();
}
void taskHandler() {
_body();
assert(_joinSemaphore.give());
vTaskDelete(xTaskGetCurrentTaskHandle());
}
TaskHandle_t _rtosTaskHandle = nullptr;
std::function<void()> _body;
Threading::BinarySemaphore _joinSemaphore;
};
namespace ThisThread {
Thread::ID getId() {
return makeThreadId(xTaskGetCurrentTaskHandle());
}
ThreadPriority getPriority() {
return makeThreadPriority(uxTaskPriorityGet(xTaskGetCurrentTaskHandle()));
}
void setPriority(ThreadPriority priority) {
vTaskPrioritySet(xTaskGetCurrentTaskHandle(), makeOsPriority(priority));
}
void sleepForMs(size_t milliseconds){
vTaskDelay(milliseconds);
}
}
#endif
}
@@ -0,0 +1,17 @@
#pragma once
#include "../Detect/DetectOS.h"
#if LF_TARGET_OS == LF_OS_FREERTOS
#include "FreeRTOS.h"
#include "task.h"
namespace LFramework::Threading {
using ThreadID = TaskHandle_t;
}
#else
#include <thread>
namespace LFramework::Threading {
using ThreadID = std::thread::id;
}
#endif
@@ -0,0 +1,60 @@
#pragma once
#if defined(LF_THREAD_STD)
#include <LFramework/Threading/Thread.h>
#include <thread>
#include <string>
#include <chrono>
namespace LFramework::Threading {
class Thread::Impl {
public:
explicit Impl(const char* name, size_t stackSize, ThreadPriority priority, std::function<void()>&& body):_name(name){
_thread = std::thread(body);
}
void join() {
_thread.join();
}
Thread::ID getId() const {
return _thread.get_id();
}
const char* getName() const {
return _name.c_str();
}
void suspend() {
}
void resume() {
}
ThreadPriority getPriority() const {
return ThreadPriority::Normal;
}
void setPriority(ThreadPriority priority) const {
}
private:
std::string _name;
std::thread _thread;
};
namespace ThisThread {
inline Thread::ID getId() {
return std::this_thread::get_id();
}
void sleepForMs(size_t milliseconds) {
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
/*ThreadPriority getPriority() {
return Private::makeThreadPriority(uxTaskPriorityGet(xTaskGetCurrentTaskHandle()));
}
void setPriority(ThreadPriority priority) {
vTaskPrioritySet(xTaskGetCurrentTaskHandle(), Private::makeOsPriority(priority));
}*/
}
}
#endif
@@ -0,0 +1,26 @@
#include <LFramework/Threading/Thread.h>
#include "../UnitTest/UnitTest.h"
#ifdef LF_THREADING
using namespace LFramework::Threading;
void test(int& counter) {
counter = 100500;
}
TEST(Thread_Create) {
int counter = 0;
Thread t;
TEST_TRUE(t.joinable() == false);
t = Thread("123", 123, ThreadPriority::Normal, [&](){
test(counter);
});
t.join();
TEST_TRUE(counter == 100500);
TEST_TRUE(!t.joinable());
}
#endif
@@ -0,0 +1,6 @@
target_sources(${PROJECT_NAME}
INTERFACE
Stopwatch.h
)
+34
View File
@@ -0,0 +1,34 @@
#ifndef Stopwatch_h__
#define Stopwatch_h__
#include <chrono>
#include <cstdint>
namespace LFramework {
class Stopwatch {
public:
Stopwatch() {
Reset();
}
typedef std::chrono::high_resolution_clock clock_t;
void Reset() {
_startTime = clock_t::now();
}
clock_t::duration Check() {
_lastDelta = clock_t::now() - _startTime;
return _lastDelta;
}
std::chrono::milliseconds CheckMs() {
return std::chrono::duration_cast<std::chrono::milliseconds>(Check());
}
clock_t::duration GetLastDelta() {
return _lastDelta;
}
private:
clock_t::time_point _startTime;
clock_t::duration _lastDelta;
};
}
#endif // Stopwatch_h__
+318
View File
@@ -0,0 +1,318 @@
#ifndef TUPLEUTILS_H
#define TUPLEUTILS_H
#include <tuple>
#include <type_traits>
namespace LFramework {
template <class... Ts>
struct Tuple;
template <>
struct Tuple<> {};
template <class T, class... Ts>
struct Tuple<T, Ts...>{
T first;
Tuple<Ts...> rest;
constexpr Tuple() = default;
template <class U, class...Us, class = typename ::std::enable_if<!::std::is_base_of<Tuple,typename ::std::decay<U>::type>::value>::type>
constexpr Tuple(U&& u, Us&&...tail) : first(::std::forward<U>(u)), rest(::std::forward<Us>(tail)...) {}
};
template <class T>
struct Tuple<T>{
T first;
constexpr Tuple() = default;
template <class U, class = typename ::std::enable_if<!::std::is_base_of<Tuple, typename ::std::decay<U>::type>::value>::type>
constexpr Tuple(U&& u) : first(::std::forward<U>(u)) {}
};
template<typename T>
struct IsTuple : std::false_type {};
template<typename ...T>
struct IsTuple<Tuple<T...>> : std::true_type {};
#pragma pack(push, 1)
template <class... Ts>
struct PackedTuple;
template <>
struct PackedTuple<> {};
template <class T, class... Ts>
struct PackedTuple<T, Ts...>{
T first;
Tuple<Ts...> rest;
PackedTuple() = default;
template <class U, class...Us, class = typename ::std::enable_if<!::std::is_base_of<PackedTuple,typename ::std::decay<U>::type>::value>::type>
PackedTuple(U&& u, Us&&...tail) : first(::std::forward<U>(u)), rest(::std::forward<Us>(tail)...) {}
};
template <class T>
struct PackedTuple<T>{
T first;
PackedTuple() = default;
template <class U, class = typename ::std::enable_if<!::std::is_base_of<PackedTuple, typename ::std::decay<U>::type>::value>::type>
PackedTuple(U&& u) : first(::std::forward<U>(u)) {}
};
#pragma pack(pop)
template<typename T>
struct IsPackedTuple : std::false_type {};
template<typename ...T>
struct IsPackedTuple<PackedTuple<T...>> : std::true_type {};
namespace details {
template<size_t Index, size_t CurrentIndex, typename...Types>
auto& Get(Tuple<Types...>& t) {
if constexpr (Index == CurrentIndex) {
return t.first;
}
else if constexpr (sizeof...(Types) > 1) {
return details::Get<Index, CurrentIndex + 1>(t.rest);
}
else {
static_assert(sizeof(t) == 0, "Invalid tuple index");
}
}
}
template<typename T>
struct tupleSizeHelper {
static constexpr size_t size = 0;
};
template<typename... T>
struct tupleSizeHelper<Tuple<T...>> {
static constexpr size_t size = sizeof...(T);
};
template<typename T>
constexpr size_t tupleSize = tupleSizeHelper<T>::size;
template<size_t Index, typename...Types>
auto& Get(Tuple<Types...>& t) {
return details::Get<Index, 0>(t);
}
namespace details {
template<size_t Index, size_t CurrentIndex, typename...Types>
auto& Get(PackedTuple<Types...>& t) {
if constexpr (Index == CurrentIndex) {
return t.first;
}
else if constexpr (sizeof...(Types) > 1) {
return details::Get<Index, CurrentIndex + 1>(t.rest);
}
else {
static_assert(sizeof(t) == 0, "Invalid tuple index");
}
}
}
template<size_t Index, typename...Types>
auto& Get(PackedTuple<Types...>& t) {
return details::Get<Index, 0>(t);
}
struct TupleSkipType {};
struct TupleStepInType {};
namespace details {
template<typename...A, typename...B>
auto tupleCatImpl(Tuple<A...> done, Tuple<B...> t) {
return Tuple<A..., B...>{};
};
template<typename A, typename B>
using tupleCat = decltype(tupleCatImpl(std::declval<A>(), std::declval<B>()));
template<typename F, typename...T, typename...U>
auto tupleSelectImpl(F f, const Tuple<T...>& tuple, const Tuple<U...>& intermediate) {
if constexpr(sizeof...(T) > 1) {
using SelectedType = decltype(f(tuple.first));
if constexpr (std::is_same_v<SelectedType, TupleStepInType>) {
return tupleCat<decltype(tupleSelectImpl(f, tuple.first, Tuple<>())), decltype(tupleSelectImpl(f, tuple.rest, Tuple<U...>()))>{};
}else if constexpr (std::is_same_v<SelectedType, TupleSkipType>) {
return tupleSelectImpl(f, tuple.rest, Tuple<U...>());
}
else {
return tupleSelectImpl(f, tuple.rest, Tuple<U..., SelectedType>());
}
}
else {
using SelectedType = decltype(f(tuple.first));
if constexpr (std::is_same_v<SelectedType, TupleStepInType>) {
return tupleSelectImpl(f, tuple.first, Tuple<>());
}
else if constexpr (std::is_same_v<SelectedType, TupleSkipType>) {
return Tuple<U...>();
}
else {
return Tuple<U..., SelectedType>();
}
}
}
template<typename F, typename...T>
auto tupleSelectType_(F f, const Tuple<T...>& tuple) {
return tupleSelectImpl(f, tuple, Tuple<>{});
}
template<typename A, typename B>
using tupleAppendFront = tupleCat<Tuple<A>, B>;
template<typename A, typename B>
using tupleAppendBack = tupleCat<B, Tuple<A>>;
template<typename ... T>
struct tupleFlattenImpl {
using type = Tuple<>;
};
template<typename D, typename...T>
struct tupleFlattenImpl<D, T...> {
using type = tupleAppendFront<D, typename tupleFlattenImpl<T...>::type>;
};
template<typename D>
struct tupleFlattenImpl<D> {
using type = Tuple<D>;
};
template<typename...D, typename...T>
struct tupleFlattenImpl<Tuple<D...>, T...> {
using type = tupleCat<typename tupleFlattenImpl<D...>::type, typename tupleFlattenImpl<T...>::type>;
};
template<typename...T>
auto tupleFlatten_(const Tuple<T...>& tuple) {
return typename tupleFlattenImpl<T...>::type{};
}
}
template<typename F, typename T>
struct tupleSelectTypeHelp {
typedef decltype(details::tupleSelectType_(std::declval<F>(), std::declval<T>())) type;
};
template<typename F, typename T>
using tupleSelectType = typename tupleSelectTypeHelp<F, T>::type;
template<typename T>
using tupleFlatten = decltype(details::tupleFlatten_(std::declval<T>()));
template<typename Target, bool Recurse = false>
struct TupleTypeSelector {
template<typename T>
auto operator () (const T& t) {
if constexpr (IsTuple<T>::value) {
if constexpr (Recurse) {
return TupleStepInType{};
}
else {
return TupleSkipType{};
}
}
else {
if constexpr (std::is_base_of_v<Target, T>) {
return T{};
}
else {
return TupleSkipType{};
}
}
}
};
namespace details {
template<typename F, typename...T, typename...U>
auto tupleSelectImpl(F f, PackedTuple<T...> tuple, PackedTuple<U...> intermediate) {
if constexpr(sizeof...(T) > 1) {
return tupleSelectImpl(f, tuple.rest, PackedTuple<U..., decltype(f(tuple.first))>());
}
else {
return PackedTuple<U..., decltype(f(tuple.first))>();
}
}
template<typename F, typename...T>
auto tupleSelectType_(F f, PackedTuple<T...> tuple) {
return tupleSelectImpl(f, tuple, PackedTuple<>{});
}
}
template<typename F, typename T>
using packedTupleSelectType = decltype(details::tupleSelectType_(std::declval<F>(), std::declval<T>()));
template<typename T, typename F, int... Is>
void forEach(T&& t, F f, std::index_sequence<Is...>) {
auto l = { (f(std::get<Is>(t)), 0)... };
}
template<typename T, typename F, int... Is>
void forEachIndexed(T&& t, F f, std::index_sequence<Is...>) {
auto l = { (f(std::get<Is>(t), Is), 0)... };
}
template<typename... Ts, typename F>
void forEachInTuple(std::tuple<Ts...> const& t, F f) {
forEach(t, f, std::index_sequence_for<Ts...>());
}
template<typename... Ts, typename F>
void forEachInTupleIndexed(std::tuple<Ts...> const& t, F f) {
forEachIndexed(t, f, std::index_sequence_for<Ts...>());
}
template<typename Functor, int ID = 0, typename ... Types>
bool executeOnIndex(std::tuple<Types...>& t, int id, Functor f) {
if constexpr (ID < sizeof...(Types)) {
if (id == ID) {
f(std::get<ID>(t));
return true;
}
else {
return executeOnIndex<Functor, ID + 1, Types...>(t, id, f);
}
}
else {
return false;
}
}
}
#endif // TUPLEUTILS_H

Some files were not shown because too many files have changed in this diff Show More