Last active
July 15, 2022 21:26
-
-
Save sdbbs/1927fbb4c4c71b3094dcee387dcfc7b7 to your computer and use it in GitHub Desktop.
rp2040_fros_printf_test example project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.13) | |
# also include .h files from the current source directory | |
SET(CMAKE_INCLUDE_CURRENT_DIR ON) | |
# Pull in SDK (must be before project) | |
set(PICO_PLATFORM rp2040) | |
include(pico_sdk_import.cmake) | |
# Pull in FreeRTOS | |
# explicit FREERTOS path - use "mixed" mode for MINGW64 Windows paths (with `D:` drive identifier, but with forward slash) | |
set(FREERTOS_KERNEL_PATH "C:/path/to/FreeRTOS-Kernel-SMP") | |
#set(FREERTOS_KERNEL_PATH "C:/path/to/FreeRTOS-Kernel") | |
include(FreeRTOS_Kernel_import.cmake) | |
# note that FreeRTOS_Kernel_import.cmake does not print message if FREERTOS_KERNEL_PATH set explicitly, | |
# so let's print it out here (so we don't change the "vanilla" FreeRTOS_Kernel_import.cmake file): | |
message("The FREERTOS_KERNEL_PATH is '${FREERTOS_KERNEL_PATH}'") | |
message("The FREERTOS_KERNEL_RP2040_RELATIVE_PATH is '${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}'") | |
project(rp2040_fros_printf_test C CXX ASM) | |
set(CMAKE_C_STANDARD 11) | |
set(CMAKE_CXX_STANDARD 17) | |
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0") | |
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") | |
endif() | |
# Initialize the SDK | |
pico_sdk_init() | |
add_executable(rp2040_fros_printf_test | |
main.c | |
printf-stdarg.c | |
) | |
target_compile_definitions(rp2040_fros_printf_test PRIVATE | |
PICO_STDIO_STACK_BUFFER_SIZE=64 # use a small printf on stack buffer | |
) | |
add_compile_options(-Wall | |
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int | |
-Wno-unused-function # we have some for the docs that aren't called | |
-Wno-maybe-uninitialized | |
) | |
# pull in common dependencies and additional uart hardware support | |
target_link_libraries(rp2040_fros_printf_test | |
FreeRTOS-Kernel | |
FreeRTOS-Kernel-Heap1 | |
pico_stdlib | |
pico_multicore | |
hardware_uart | |
) | |
# create map/bin/hex file etc. | |
pico_add_extra_outputs(rp2040_fros_printf_test) | |
# this will hopefully enable `printf` printouts via USB Serial ports | |
pico_enable_stdio_usb(rp2040_fros_printf_test 1) | |
# # enable usb output, disable uart output? | |
pico_enable_stdio_uart(rp2040_fros_printf_test 0) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/C/msys64/mingw64/bin/arm-none-eabi-gcc.exe -DCFG_TUSB_DEBUG=1 -DCFG_TUSB_MCU=OPT_MCU_RP2040 -DCFG_TUSB_OS=OPT_OS_PICO -DFREE_RTOS_KERNEL_SMP=1 -DLIB_FREERTOS_KERNEL=1 -DLIB_PICO_BIT_OPS=1 -DLIB_PICO_BIT_OPS_PICO=1 -DLIB_PICO_DIVIDER=1 -DLIB_PICO_DIVIDER_HARDWARE=1 -DLIB_PICO_DOUBLE=1 -DLIB_PICO_DOUBLE_PICO=1 -DLIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1 -DLIB_PICO_FLOAT=1 -DLIB_PICO_FLOAT_PICO=1 -DLIB_PICO_INT64_OPS=1 -DLIB_PICO_INT64_OPS_PICO=1 -DLIB_PICO_MALLOC=1 -DLIB_PICO_MEM_OPS=1 -DLIB_PICO_MEM_OPS_PICO=1 -DLIB_PICO_MULTICORE=1 -DLIB_PICO_PLATFORM=1 -DLIB_PICO_PRINTF=1 -DLIB_PICO_PRINTF_PICO=1 -DLIB_PICO_RUNTIME=1 -DLIB_PICO_STANDARD_LINK=1 -DLIB_PICO_STDIO=1 -DLIB_PICO_STDIO_USB=1 -DLIB_PICO_STDLIB=1 -DLIB_PICO_SYNC=1 -DLIB_PICO_SYNC_CORE=1 -DLIB_PICO_SYNC_CRITICAL_SECTION=1 -DLIB_PICO_SYNC_MUTEX=1 -DLIB_PICO_SYNC_SEM=1 -DLIB_PICO_TIME=1 -DLIB_PICO_UNIQUE_ID=1 -DLIB_PICO_UTIL=1 -DPICO_BOARD=\"pico\" -DPICO_BUILD=1 -DPICO_CMAKE_BUILD_TYPE=\"Debug\" -DPICO_COPY_TO_RAM=0 -DPICO_CXX_ENABLE_EXCEPTIONS=0 -DPICO_NO_FLASH=0 -DPICO_NO_HARDWARE=0 -DPICO_ON_DEVICE=1 -DPICO_STDIO_STACK_BUFFER_SIZE=64 -DPICO_TARGET_NAME=\"rp2040_fros_printf_test\" -DPICO_USE_BLOCKED_RAM=0 -I/C/path/to/rp2040_fros_printf_test/build -I/C/path/to/rp2040_fros_printf_test -I/C/path/to/FreeRTOS-Kernel-SMP/portable/ThirdParty/GCC/RP2040/include -I/C/path/to/FreeRTOS-Kernel-SMP/include -I/C/path/to/pico-sdk/src/common/pico_base/include -I/C/path/to/rp2040_fros_printf_test/build/generated/pico_base -I/C/path/to/pico-sdk/src/boards/include -I/C/path/to/pico-sdk/src/rp2_common/pico_platform/include -I/C/path/to/pico-sdk/src/rp2040/hardware_regs/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_base/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_clocks/include -I/C/path/to/pico-sdk/src/rp2040/hardware_structs/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_claim/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_sync/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_gpio/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_irq/include -I/C/path/to/pico-sdk/src/common/pico_sync/include -I/C/path/to/pico-sdk/src/common/pico_time/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_timer/include -I/C/path/to/pico-sdk/src/common/pico_util/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_resets/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_pll/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_vreg/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_watchdog/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_xosc/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_exception/include -I/C/path/to/pico-sdk/src/rp2_common/pico_multicore/include -I/C/path/to/pico-sdk/src/common/pico_stdlib/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_uart/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_divider/include -I/C/path/to/pico-sdk/src/rp2_common/pico_runtime/include -I/C/path/to/pico-sdk/src/rp2_common/pico_printf/include -I/C/path/to/pico-sdk/src/rp2_common/pico_bootrom/include -I/C/path/to/pico-sdk/src/common/pico_bit_ops/include -I/C/path/to/pico-sdk/src/common/pico_divider/include -I/C/path/to/pico-sdk/src/rp2_common/pico_double/include -I/C/path/to/pico-sdk/src/rp2_common/pico_int64_ops/include -I/C/path/to/pico-sdk/src/rp2_common/pico_float/include -I/C/path/to/pico-sdk/src/rp2_common/pico_malloc/include -I/C/path/to/pico-sdk/src/rp2_common/boot_stage2/include -I/C/path/to/pico-sdk/src/common/pico_binary_info/include -I/C/path/to/pico-sdk/src/rp2_common/pico_stdio/include -I/C/path/to/pico-sdk/src/rp2_common/pico_stdio_usb/include -I/C/path/to/pico-sdk/lib/tinyusb/src -I/C/path/to/pico-sdk/lib/tinyusb/src/common -I/C/path/to/pico-sdk/lib/tinyusb/hw -I/C/path/to/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include -I/C/path/to/pico-sdk/src/rp2_common/pico_unique_id/include -I/C/path/to/pico-sdk/src/rp2_common/hardware_flash/include -I/C/path/to/pico-sdk/src/common/pico_usb_reset_interface/include -mcpu=cortex-m0plus -mthumb -Og -g -ffunction-sections -fdata-sections -std=gnu11 -MD -MT CMakeFiles/rp2040_fros_printf_test.dir/main.c.obj -MF CMakeFiles/rp2040_fros_printf_test.dir/main.c.obj.d -o CMakeFiles/rp2040_fros_printf_test.dir/main.c.obj -c /C/path/to/rp2040_fros_printf_test/main.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/C/msys64/mingw64/bin/arm-none-eabi-g++.exe -mcpu=cortex-m0plus -mthumb -Og -g -Wl,--build-id=none --specs=nosys.specs -Wl,--wrap=sprintf -Wl,--wrap=snprintf -Wl,--wrap=vsnprintf -Wl,--wrap=__clzsi2 -Wl,--wrap=__clzdi2 -Wl,--wrap=__ctzsi2 -Wl,--wrap=__ctzdi2 -Wl,--wrap=__popcountsi2 -Wl,--wrap=__popcountdi2 -Wl,--wrap=__clz -Wl,--wrap=__clzl -Wl,--wrap=__clzll -Wl,--wrap=__aeabi_idiv -Wl,--wrap=__aeabi_idivmod -Wl,--wrap=__aeabi_ldivmod -Wl,--wrap=__aeabi_uidiv -Wl,--wrap=__aeabi_uidivmod -Wl,--wrap=__aeabi_uldivmod -Wl,--wrap=__aeabi_dadd -Wl,--wrap=__aeabi_ddiv -Wl,--wrap=__aeabi_dmul -Wl,--wrap=__aeabi_drsub -Wl,--wrap=__aeabi_dsub -Wl,--wrap=__aeabi_cdcmpeq -Wl,--wrap=__aeabi_cdrcmple -Wl,--wrap=__aeabi_cdcmple -Wl,--wrap=__aeabi_dcmpeq -Wl,--wrap=__aeabi_dcmplt -Wl,--wrap=__aeabi_dcmple -Wl,--wrap=__aeabi_dcmpge -Wl,--wrap=__aeabi_dcmpgt -Wl,--wrap=__aeabi_dcmpun -Wl,--wrap=__aeabi_i2d -Wl,--wrap=__aeabi_l2d -Wl,--wrap=__aeabi_ui2d -Wl,--wrap=__aeabi_ul2d -Wl,--wrap=__aeabi_d2iz -Wl,--wrap=__aeabi_d2lz -Wl,--wrap=__aeabi_d2uiz -Wl,--wrap=__aeabi_d2ulz -Wl,--wrap=__aeabi_d2f -Wl,--wrap=sqrt -Wl,--wrap=cos -Wl,--wrap=sin -Wl,--wrap=tan -Wl,--wrap=atan2 -Wl,--wrap=exp -Wl,--wrap=log -Wl,--wrap=ldexp -Wl,--wrap=copysign -Wl,--wrap=trunc -Wl,--wrap=floor -Wl,--wrap=ceil -Wl,--wrap=round -Wl,--wrap=sincos -Wl,--wrap=asin -Wl,--wrap=acos -Wl,--wrap=atan -Wl,--wrap=sinh -Wl,--wrap=cosh -Wl,--wrap=tanh -Wl,--wrap=asinh -Wl,--wrap=acosh -Wl,--wrap=atanh -Wl,--wrap=exp2 -Wl,--wrap=log2 -Wl,--wrap=exp10 -Wl,--wrap=log10 -Wl,--wrap=pow -Wl,--wrap=powint -Wl,--wrap=hypot -Wl,--wrap=cbrt -Wl,--wrap=fmod -Wl,--wrap=drem -Wl,--wrap=remainder -Wl,--wrap=remquo -Wl,--wrap=expm1 -Wl,--wrap=log1p -Wl,--wrap=fma -Wl,--wrap=__aeabi_lmul -Wl,--wrap=__aeabi_fadd -Wl,--wrap=__aeabi_fdiv -Wl,--wrap=__aeabi_fmul -Wl,--wrap=__aeabi_frsub -Wl,--wrap=__aeabi_fsub -Wl,--wrap=__aeabi_cfcmpeq -Wl,--wrap=__aeabi_cfrcmple -Wl,--wrap=__aeabi_cfcmple -Wl,--wrap=__aeabi_fcmpeq -Wl,--wrap=__aeabi_fcmplt -Wl,--wrap=__aeabi_fcmple -Wl,--wrap=__aeabi_fcmpge -Wl,--wrap=__aeabi_fcmpgt -Wl,--wrap=__aeabi_fcmpun -Wl,--wrap=__aeabi_i2f -Wl,--wrap=__aeabi_l2f -Wl,--wrap=__aeabi_ui2f -Wl,--wrap=__aeabi_ul2f -Wl,--wrap=__aeabi_f2iz -Wl,--wrap=__aeabi_f2lz -Wl,--wrap=__aeabi_f2uiz -Wl,--wrap=__aeabi_f2ulz -Wl,--wrap=__aeabi_f2d -Wl,--wrap=sqrtf -Wl,--wrap=cosf -Wl,--wrap=sinf -Wl,--wrap=tanf -Wl,--wrap=atan2f -Wl,--wrap=expf -Wl,--wrap=logf -Wl,--wrap=ldexpf -Wl,--wrap=copysignf -Wl,--wrap=truncf -Wl,--wrap=floorf -Wl,--wrap=ceilf -Wl,--wrap=roundf -Wl,--wrap=sincosf -Wl,--wrap=asinf -Wl,--wrap=acosf -Wl,--wrap=atanf -Wl,--wrap=sinhf -Wl,--wrap=coshf -Wl,--wrap=tanhf -Wl,--wrap=asinhf -Wl,--wrap=acoshf -Wl,--wrap=atanhf -Wl,--wrap=exp2f -Wl,--wrap=log2f -Wl,--wrap=exp10f -Wl,--wrap=log10f -Wl,--wrap=powf -Wl,--wrap=powintf -Wl,--wrap=hypotf -Wl,--wrap=cbrtf -Wl,--wrap=fmodf -Wl,--wrap=dremf -Wl,--wrap=remainderf -Wl,--wrap=remquof -Wl,--wrap=expm1f -Wl,--wrap=log1pf -Wl,--wrap=fmaf -Wl,--wrap=malloc -Wl,--wrap=calloc -Wl,--wrap=free -Wl,--wrap=memcpy -Wl,--wrap=memset -Wl,--wrap=__aeabi_memcpy -Wl,--wrap=__aeabi_memset -Wl,--wrap=__aeabi_memcpy4 -Wl,--wrap=__aeabi_memset4 -Wl,--wrap=__aeabi_memcpy8 -Wl,--wrap=__aeabi_memset8 -Wl,-Map=rp2040_fros_printf_test.elf.map -Wl,--script=C:/path/to/pico-sdk/src/rp2_common/pico_standard_link/memmap_default.ld -Wl,-z,max-page-size=4096 -Wl,--gc-sections -Wl,--wrap=printf -Wl,--wrap=vprintf -Wl,--wrap=puts -Wl,--wrap=putchar -Wl,--wrap=getchar @CMakeFiles/rp2040_fros_printf_test.dir/objects1.rsp -o rp2040_fros_printf_test.elf pico-sdk/src/rp2_common/boot_stage2/bs2_default_padded_checksummed.S |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake | |
# This can be dropped into an external project to help locate the FreeRTOS kernel | |
# It should be include()ed prior to project(). Alternatively this file may | |
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory | |
# respectively. | |
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH)) | |
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH}) | |
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')") | |
endif () | |
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC/RP2040") | |
# undo the above | |
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..") | |
if (NOT FREERTOS_KERNEL_PATH) | |
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly) | |
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH) | |
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH) | |
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH) | |
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH) | |
endif() | |
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH) | |
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH) | |
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake") | |
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel") | |
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel) | |
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}") | |
endif() | |
endif () | |
if (NOT FREERTOS_KERNEL_PATH) | |
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source) | |
# check if FreeRTOS-Kernel exists under directory that included us | |
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}}) | |
set(SEARCH_ROOT ../../../..) | |
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH) | |
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt) | |
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH) | |
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project") | |
break() | |
endif() | |
endforeach() | |
endif() | |
if (NOT FREERTOS_KERNEL_PATH) | |
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.") | |
endif() | |
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel") | |
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") | |
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}) | |
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found") | |
endif() | |
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt) | |
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain an RP2040 port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}") | |
endif() | |
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE) | |
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef FREERTOS_CONFIG_H | |
#define FREERTOS_CONFIG_H | |
// #pragma message("FREERTOS_CONFIG_H included!") | |
/* Use Pico SDK ISR handlers */ | |
#define vPortSVCHandler isr_svcall | |
#define xPortPendSVHandler isr_pendsv | |
#define xPortSysTickHandler isr_systick | |
/*----------------------------------------------------------- | |
* Application specific definitions. | |
* | |
* These definitions should be adjusted for your particular hardware and | |
* application requirements. | |
* | |
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE | |
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. | |
* | |
* See http://www.freertos.org/a00110.html | |
*----------------------------------------------------------*/ | |
/* Scheduler Related */ | |
#define configUSE_PREEMPTION 1 | |
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 | |
#define configUSE_TICKLESS_IDLE 0 | |
#define configCPU_CLOCK_HZ 133000000 | |
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) | |
#define configMAX_PRIORITIES 32 | |
#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 | |
#define configMAX_TASK_NAME_LEN 16 | |
#define configUSE_16_BIT_TICKS 0 | |
#define configIDLE_SHOULD_YIELD 1 | |
#define configUSE_TASK_NOTIFICATIONS 1 | |
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 | |
/* Synchronization Related */ | |
#define configUSE_MUTEXES 1 | |
#define configUSE_RECURSIVE_MUTEXES 1 | |
#define configUSE_APPLICATION_TASK_TAG 0 | |
#define configUSE_COUNTING_SEMAPHORES 1 | |
#define configQUEUE_REGISTRY_SIZE 8 | |
#define configUSE_QUEUE_SETS 1 | |
#define configUSE_TIME_SLICING 1 | |
#define configUSE_NEWLIB_REENTRANT 0 | |
#define configENABLE_BACKWARD_COMPATIBILITY 0 | |
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 | |
/* System */ | |
#define configSTACK_DEPTH_TYPE uint32_t | |
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t | |
/* Memory allocation related definitions. */ | |
#define configSUPPORT_STATIC_ALLOCATION 0 | |
#define configSUPPORT_DYNAMIC_ALLOCATION 1 | |
#define configTOTAL_HEAP_SIZE (128*1024) | |
#define configAPPLICATION_ALLOCATED_HEAP 0 | |
/* Hook function related definitions. */ | |
#define configUSE_IDLE_HOOK 0 | |
#define configUSE_TICK_HOOK 0 | |
#define configCHECK_FOR_STACK_OVERFLOW 2 | |
#define configUSE_MALLOC_FAILED_HOOK 1 | |
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 | |
/* Run time and task stats gathering related definitions. */ | |
#define configGENERATE_RUN_TIME_STATS 0 | |
#define configUSE_TRACE_FACILITY 1 | |
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 // must be 1 in addition to configUSE_TRACE_FACILITY so we get vTaskList function | |
/* Co-routine related definitions. */ | |
#define configUSE_CO_ROUTINES 0 | |
#define configMAX_CO_ROUTINE_PRIORITIES 1 | |
/* Software timer related definitions. */ | |
#define configUSE_TIMERS 1 | |
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) | |
#define configTIMER_QUEUE_LENGTH 10 | |
#define configTIMER_TASK_STACK_DEPTH 1024 | |
/* Interrupt nesting behaviour configuration. */ | |
/* | |
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor] | |
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application] | |
#define configMAX_API_CALL_INTERRUPT_PRIORITY [dependent on processor and application] | |
*/ | |
//#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0b01000000 // causes recompile, but not sure if it makes a difference on RP2040 at all | |
/* SMP port only */ | |
#define configNUM_CORES 2 | |
#define configTICK_CORE 0 // "Core in which tick should run" | |
#define configRUN_MULTIPLE_PRIORITIES 1 // must be 1 to use core affinity/"core exclusion" | |
#define configUSE_CORE_AFFINITY 1 // "configUSE_CORE_AFFINITY must be defined as 1 | |
// for vTaskCoreAffinitySet to be available." | |
/* RP2040 specific */ | |
#define configSUPPORT_PICO_SYNC_INTEROP 1 | |
#define configSUPPORT_PICO_TIME_INTEROP 1 | |
#include <assert.h> | |
/* Define to trap errors during development. */ | |
#define configASSERT(x) assert(x) | |
/* Set the following definitions to 1 to include the API function, or zero | |
to exclude the API function. */ | |
/* Optional functions - most linkers will remove unused functions anyway. */ | |
#define INCLUDE_vTaskPrioritySet 1 | |
#define INCLUDE_uxTaskPriorityGet 1 | |
#define INCLUDE_vTaskDelete 1 | |
#define INCLUDE_vTaskSuspend 1 | |
#define INCLUDE_xResumeFromISR 1 | |
#define INCLUDE_vTaskDelayUntil 1 | |
#define INCLUDE_vTaskDelay 1 | |
#define INCLUDE_xTaskGetSchedulerState 1 | |
#define INCLUDE_xTaskGetCurrentTaskHandle 1 | |
#define INCLUDE_uxTaskGetStackHighWaterMark 1 | |
#define INCLUDE_xTaskGetIdleTaskHandle 1 | |
#define INCLUDE_eTaskGetState 1 | |
#define INCLUDE_xEventGroupSetBitFromISR 1 | |
#define INCLUDE_xTimerPendFunctionCall 1 | |
#define INCLUDE_xTaskAbortDelay 1 | |
#define INCLUDE_xTaskGetHandle 1 | |
#define INCLUDE_xTaskResumeFromISR 1 | |
#define INCLUDE_xQueueGetMutexHolder 1 | |
/* A header file that defines trace macro can be included here. */ | |
#endif /* FREERTOS_CONFIG_H */ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// made vs. pico-sdk commit 2062372; FreeRTOS smp branch commit a97741a08 | |
// NOTE: this program must be re-started with core 1 (second core) on RP2040 being initialized first, | |
// commands for openocd for that are: | |
// -c "init ; reset halt ; rp2040.core1 arp_reset assert 0 ; rp2040.core0 arp_reset assert 0 ; exit" | |
// otherwise task_two will never print anything! | |
// (see https://stackoverflow.com/questions/72745969/openocd-one-liner-for-proper-multicore-mcu-reset) | |
#include <inttypes.h> //PRIu64 | |
/* (FreeRTOS) Kernel includes. */ | |
#include <FreeRTOS.h> // Must come first. (this also includes the FreeRTOSConfig.h file in this dir) | |
#include <task.h> // RTOS task related API prototypes. // TaskHandle_t | |
#include <stdio.h> // as in pico-examples/hello_world/usb/hello_usb.c | |
#include "pico/stdlib.h" | |
#include "pico/multicore.h" // multicore_launch_core1 | |
#include "hardware/clocks.h" // clk_sys | |
#include "hardware/irq.h" // Pico SDK: UART0_IRQ, UART1_IRQ | |
#include "hardware/structs/rosc.h" // rosc_hw | |
#include <string.h> | |
// forward declares: | |
static void prvSetupHardware( void ); | |
static void setup_timer_isr( void ); | |
static void init_freertos_tasks( void ); | |
void task_one( void* pvParameters ); | |
void task_two( void* pvParameters ); | |
int main(void) { | |
prvSetupHardware(); | |
init_freertos_tasks(); | |
// Start the tasks and timers running. | |
vTaskStartScheduler(); | |
// should never reach here (FreeRTOS-SMP-Demos/FreeRTOS/Demo/CORTEX_M0+_RP2040/OnEitherCore/main.c) | |
panic_unsupported(); | |
//while(1){}; | |
} | |
////////////////////////////////////////////////////// | |
// as in FreeRTOS-SMP-Demos\FreeRTOS\Demo\CORTEX_M0+_RP2040\OnEitherCore\main.c | |
static void prvSetupHardware( void ) { | |
set_sys_clock_pll(1596000000, 6, 2); // change sys clk to 133 MHz | |
// Set up USB serial port (printf over USB serial port) | |
stdio_init_all(); | |
} | |
static void init_freertos_tasks( void ) { | |
// NOTE: FreeRTOS own "Tmr Svc" already has priority configMAX_PRIORITIES-1! | |
// should probably use less than that for our tasks: | |
TaskHandle_t xTaskOneHandle = NULL; // see https://www.freertos.org/a00125.html | |
TaskHandle_t xTaskTwoHandle = NULL; | |
// Create the task | |
xTaskCreate( | |
task_one, // The function that implements the task. | |
"task_one", // Text name for the task, just to help debugging. | |
configMINIMAL_STACK_SIZE, // The size (in words) of the stack that should be created for the task. | |
NULL, // A parameter that can be passed into the task. Not used here | |
1, // The priority to assign to the task. tskIDLE_PRIORITY (which is 0) is | |
// the lowest priority. configMAX_PRIORITIES-1 is the highest priority. | |
//NULL // Used to obtain a handle to the created task. When not used here, set to NULL. | |
&xTaskOneHandle // Used to obtain a handle to the created task. | |
); | |
configASSERT( xTaskOneHandle ); | |
vTaskSetTaskNumber(xTaskOneHandle, 1); | |
// run task_one on cpu core 0 | |
vTaskCoreAffinitySet( xTaskOneHandle, 0b01 ); | |
// Create the task | |
xTaskCreate( | |
task_two, // The function that implements the task. | |
"task_two", // Text name for the task, just to help debugging. | |
configMINIMAL_STACK_SIZE, // The size (in words) of the stack that should be created for the task. | |
NULL, // A parameter that can be passed into the task. Not used here | |
1, // The priority to assign to the task. tskIDLE_PRIORITY (which is 0) is | |
// the lowest priority. configMAX_PRIORITIES-1 is the highest priority. | |
//NULL // Used to obtain a handle to the created task. When not used here, set to NULL. | |
&xTaskTwoHandle // Used to obtain a handle to the created task. | |
); | |
configASSERT( xTaskTwoHandle ); | |
vTaskSetTaskNumber(xTaskTwoHandle, 1); | |
// run task_two on cpu core 1 | |
vTaskCoreAffinitySet( xTaskTwoHandle, 0b10 ); | |
} | |
void task_one( void* pvParameters ) { | |
uint32_t step = 0; | |
char report[128]; | |
uint16_t task_sleep_delay_ms = 4096; | |
const uint16_t task_sleep_delay_max = 2048; | |
uint8_t dir = 0; // 0: decrease, 1: increase | |
while (true) { | |
step++; | |
if (dir == 0) { | |
task_sleep_delay_ms /= 2; | |
if (task_sleep_delay_ms == 1) { | |
dir = 1; | |
} | |
} else { // dir == 1 | |
task_sleep_delay_ms *= 2; | |
if (task_sleep_delay_ms >= task_sleep_delay_max) { | |
dir = 0; | |
} | |
} | |
snprintf( report, sizeof(report), "Task one at step %d (core %d); task delay/sleep for %d ms", step, get_core_num(), task_sleep_delay_ms ); | |
printf( "%"PRIu64 ": %s\n", get_absolute_time(), report ); | |
vTaskDelay(task_sleep_delay_ms / portTICK_PERIOD_MS); // ms | |
} | |
} | |
void task_two( void* pvParameters ) { | |
uint32_t step = 0; | |
const uint32_t busy_delay_ms = 10; // at 5 ms, way too difficult to stop serial program | |
char report[128]; | |
while (true) { | |
step++; | |
snprintf( report, sizeof(report), "Task two at step %d (core %d); busy-waiting for %d ms", step, get_core_num(), busy_delay_ms ); | |
printf( "%"PRIu64 ": %s\n", get_absolute_time(), report ); | |
busy_wait_ms( busy_delay_ms ); | |
} | |
} | |
#if ( configCHECK_FOR_STACK_OVERFLOW > 0 ) | |
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) { | |
configASSERT(0); | |
} | |
#endif | |
#if ( configUSE_MALLOC_FAILED_HOOK > 0 ) | |
void vApplicationMallocFailedHook( void ) { | |
configASSERT(0); | |
} | |
#endif | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake | |
# This can be dropped into an external project to help locate this SDK | |
# It should be include()ed prior to project() | |
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) | |
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) | |
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") | |
endif () | |
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) | |
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) | |
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") | |
endif () | |
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) | |
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) | |
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") | |
endif () | |
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") | |
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") | |
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") | |
if (NOT PICO_SDK_PATH) | |
if (PICO_SDK_FETCH_FROM_GIT) | |
include(FetchContent) | |
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) | |
if (PICO_SDK_FETCH_FROM_GIT_PATH) | |
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") | |
endif () | |
FetchContent_Declare( | |
pico_sdk | |
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk | |
GIT_TAG master | |
) | |
if (NOT pico_sdk) | |
message("Downloading Raspberry Pi Pico SDK") | |
FetchContent_Populate(pico_sdk) | |
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) | |
endif () | |
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) | |
else () | |
message(FATAL_ERROR | |
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." | |
) | |
endif () | |
endif () | |
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") | |
if (NOT EXISTS ${PICO_SDK_PATH}) | |
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") | |
endif () | |
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) | |
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) | |
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") | |
endif () | |
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) | |
include(${PICO_SDK_INIT_CMAKE_FILE}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2001, 2002 Georges Menie (www.menie.org) | |
* stdarg version contributed by Christian Ettinger | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU Lesser General Public License as published by | |
* the Free Software Foundation; either version 2 of the License, or | |
* (at your option) any later version. | |
* | |
* Changes for the FreeRTOS ports: | |
* | |
* - The dot in "%-8.8s" | |
* - The specifiers 'l' (long) and 'L' (long long) | |
* - The specifier 'u' for unsigned | |
* - Dot notation for IP addresses: | |
* sprintf("IP = %xip\n", 0xC0A80164); | |
* will produce "IP = 192.168.1.100\n" | |
* sprintf("IP = %pip\n", pxIPv6_Address); | |
*/ | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#if ( USE_FREERTOS != 0 ) | |
#include "FreeRTOS.h" | |
#else | |
#include <stdint.h> | |
typedef int BaseType_t; | |
typedef uint32_t TickType_t; | |
#define pdTRUE 1 | |
#define pdFALSE 0 | |
#define pdMS_TO_TICKS( x ) ( x ) | |
#endif | |
int sprintf( char * apBuf, | |
const char * apFmt, | |
... ); | |
/* | |
* Return 1 for readable, 2 for writeable, 3 for both. | |
* Function must be provided by the application. | |
*/ | |
extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); | |
extern void vOutputChar( const char cChar, | |
const TickType_t xTicksToWait ); | |
#ifdef __GNUC__ | |
__attribute__( ( weak ) ) BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ) | |
{ | |
( void ) aAddress; | |
/* Return 1 for readable, 2 for writeable, 3 for both. */ | |
return 0x03; | |
} | |
__attribute__( ( weak ) ) void vOutputChar( const char cChar, | |
const TickType_t xTicksToWait ) | |
{ | |
( void ) cChar; | |
( void ) xTicksToWait; | |
/* Do nothing. */ | |
} | |
#endif /* __GNUC__ */ | |
static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); | |
int tiny_printf( const char * format, | |
... ); | |
/* Defined here: write a large amount as GB, MB, KB or bytes */ | |
const char * mkSize( unsigned long long aSize, | |
char * apBuf, | |
int aLen ); | |
typedef union | |
{ | |
uint8_t ucBytes[ 4 ]; | |
uint16_t ucShorts[ 2 ]; | |
uint32_t ulWords[ 1 ]; | |
} _U32; | |
struct xPrintFlags | |
{ | |
int base; /**< The number should be printed as either decimal (10), hexdecimal (16) or octal (8). */ | |
int width; /**< The total width of the thing to be printed, padded with a '0' or a space when needed. */ | |
int printLimit; /**< Total width of a number, will get leading zero's. */ | |
unsigned | |
letBase : 8, | |
pad_zero : 1, /**< Use '0', not a space for padding. */ | |
pad_right : 1, /**< Padding: right adjusted. */ | |
isSigned : 1, /**< The number is signed. */ | |
isNumber : 1, /**< A numeric value is to be printed. */ | |
long32 : 1, /**< Not used as long is the same as unsigned. */ | |
long64 : 1; /**< The number is 64-bits. */ | |
}; | |
struct SStringBuf | |
{ | |
char * str; /**< Points to the location where the next byte can be written. */ | |
const char * orgStr; /**< Points to the buffer supplied by the caller. */ | |
const char * nulPos; /**< Points to the last location that may be written, will be nulled */ | |
int curLen; /**< The number of bytes that have been written so far. */ | |
struct xPrintFlags flags; /**< Some flags that indicate how a value shall be written. */ | |
}; | |
#ifdef __GNUC__ | |
static const _U32 u32 = | |
{ | |
ucBytes : { 0, 1, 2, 3 } | |
}; | |
#else | |
static const _U32 u32 = { 0, 1, 2, 3 }; | |
#endif | |
static void strbuf_init( struct SStringBuf * apStr, | |
char * apBuf, | |
const char * apMaxStr ) | |
{ | |
apStr->str = apBuf; | |
apStr->orgStr = apBuf; | |
apStr->nulPos = apMaxStr - 1; | |
apStr->curLen = 0; | |
memset( &apStr->flags, '\0', sizeof apStr->flags ); | |
} | |
/*-----------------------------------------------------------*/ | |
static BaseType_t strbuf_printchar( struct SStringBuf * apStr, | |
int c ) | |
{ | |
if( apStr->str == NULL ) | |
{ | |
/* There is no str pointer: printing to stdout. */ | |
vOutputChar( ( char ) c, xTicksToWait ); | |
apStr->curLen++; | |
return pdTRUE; | |
} | |
if( apStr->str < apStr->nulPos ) | |
{ | |
/* There is space for this character. */ | |
*( apStr->str++ ) = c; | |
apStr->curLen++; | |
return pdTRUE; | |
} | |
if( apStr->str == apStr->nulPos ) | |
{ | |
/* nulPos is the last writeable character, zero it. */ | |
*( apStr->str++ ) = '\0'; | |
} | |
return pdFALSE; | |
} | |
/*-----------------------------------------------------------*/ | |
static __inline BaseType_t strbuf_printchar_inline( struct SStringBuf * apStr, | |
int c ) | |
{ | |
if( apStr->str == NULL ) | |
{ | |
vOutputChar( ( char ) c, xTicksToWait ); | |
if( c == 0 ) | |
{ | |
return pdFALSE; | |
} | |
apStr->curLen++; | |
return pdTRUE; | |
} | |
if( apStr->str < apStr->nulPos ) | |
{ | |
*( apStr->str++ ) = c; | |
if( c == 0 ) | |
{ | |
return pdFALSE; | |
} | |
apStr->curLen++; | |
return pdTRUE; | |
} | |
if( apStr->str == apStr->nulPos ) | |
{ | |
*( apStr->str++ ) = '\0'; | |
} | |
return pdFALSE; | |
} | |
/*-----------------------------------------------------------*/ | |
static __inline int i2hex( int aCh ) | |
{ | |
int iResult; | |
if( aCh < 10 ) | |
{ | |
iResult = '0' + aCh; | |
} | |
else | |
{ | |
iResult = 'A' + aCh - 10; | |
} | |
return iResult; | |
} | |
/*-----------------------------------------------------------*/ | |
static BaseType_t prints( struct SStringBuf * apBuf, | |
const char * apString ) | |
{ | |
register int padchar = ' '; | |
int i, len; | |
if( xApplicationMemoryPermissions( ( uint32_t ) apString ) == 0 ) | |
{ | |
/* The user has probably made a mistake with the parameter | |
* for '%s', the memory is not readbale. */ | |
apString = "INV_MEM"; | |
} | |
if( apBuf->flags.width > 0 ) | |
{ | |
register int count = 0; | |
register const char * ptr; | |
for( ptr = apString; *ptr; ++ptr ) | |
{ | |
++count; | |
} | |
if( count >= apBuf->flags.width ) | |
{ | |
apBuf->flags.width = 0; | |
} | |
else | |
{ | |
apBuf->flags.width -= count; | |
} | |
if( apBuf->flags.pad_zero != 0U ) | |
{ | |
padchar = '0'; | |
} | |
} | |
if( apBuf->flags.pad_right == 0U ) | |
{ | |
for( ; apBuf->flags.width > 0; --apBuf->flags.width ) | |
{ | |
if( strbuf_printchar( apBuf, padchar ) == 0 ) | |
{ | |
return pdFALSE; | |
} | |
} | |
} | |
if( ( apBuf->flags.isNumber == pdTRUE ) && | |
( apBuf->flags.pad_zero == pdTRUE ) && | |
( apBuf->flags.pad_right == pdFALSE ) ) | |
{ | |
/* The string to print represents an integer number. | |
* In this case, printLimit is the min number of digits to print | |
* If the length of the number to print is less than the minimal | |
* number of digits to display, we add 0 before printing the number | |
*/ | |
len = strlen( apString ); | |
if( len < apBuf->flags.printLimit ) | |
{ | |
i = apBuf->flags.printLimit - len; | |
for( ; i; i-- ) | |
{ | |
if( strbuf_printchar( apBuf, '0' ) == 0 ) | |
{ | |
return pdFALSE; | |
} | |
} | |
} | |
} | |
/* The string to print is not the result of a number conversion to ascii. | |
* For a string, printLimit is the max number of characters to display | |
*/ | |
for( ; apBuf->flags.printLimit && *apString; ++apString, --apBuf->flags.printLimit ) | |
{ | |
if( !strbuf_printchar( apBuf, *apString ) ) | |
{ | |
return pdFALSE; | |
} | |
} | |
for( ; apBuf->flags.width > 0; --apBuf->flags.width ) | |
{ | |
if( !strbuf_printchar( apBuf, padchar ) ) | |
{ | |
return pdFALSE; | |
} | |
} | |
return pdTRUE; | |
} | |
/*-----------------------------------------------------------*/ | |
/* the following should be enough for 32 bit int */ | |
#define PRINT_BUF_LEN 12 /* to print 4294967296 */ | |
#if SPRINTF_LONG_LONG | |
#warning 64-bit libraries will be included as well | |
static BaseType_t printll( struct SStringBuf * apBuf, | |
long long i ) | |
{ | |
char print_buf[ 2 * PRINT_BUF_LEN ]; | |
register char * s; | |
register int t, neg = 0; | |
register unsigned long long u = i; | |
lldiv_t lldiv_result; | |
/* typedef struct | |
* { | |
* long long int quot; // quotient | |
* long long int rem; // remainder | |
* } lldiv_t; | |
*/ | |
apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ | |
if( i == 0LL ) | |
{ | |
print_buf[ 0 ] = '0'; | |
print_buf[ 1 ] = '\0'; | |
return prints( apBuf, print_buf ); | |
} | |
if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) | |
{ | |
neg = 1; | |
u = -i; | |
} | |
s = print_buf + sizeof print_buf - 1; | |
*s = '\0'; | |
/* 18446744073709551616 */ | |
while( u != 0 ) | |
{ | |
lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); | |
t = lldiv_result.rem; | |
if( t >= 10 ) | |
{ | |
t += apBuf->flags.letBase - '0' - 10; | |
} | |
*( --s ) = t + '0'; | |
u = lldiv_result.quot; | |
} | |
if( neg != 0 ) | |
{ | |
if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad_zero != 0U ) ) | |
{ | |
if( !strbuf_printchar( apBuf, '-' ) ) | |
{ | |
return pdFALSE; | |
} | |
--apBuf->flags.width; | |
} | |
else | |
{ | |
*( --s ) = '-'; | |
} | |
} | |
return prints( apBuf, s ); | |
} | |
#endif /* SPRINTF_LONG_LONG */ | |
/*-----------------------------------------------------------*/ | |
static BaseType_t printi( struct SStringBuf * apBuf, | |
int i ) | |
{ | |
char print_buf[ PRINT_BUF_LEN ]; | |
register char * s; | |
register int t, neg = 0; | |
register unsigned int u = i; | |
register unsigned base = apBuf->flags.base; | |
apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ | |
if( i == 0 ) | |
{ | |
print_buf[ 0 ] = '0'; | |
print_buf[ 1 ] = '\0'; | |
return prints( apBuf, print_buf ); | |
} | |
if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) | |
{ | |
neg = 1; | |
u = -i; | |
} | |
s = print_buf + sizeof print_buf - 1; | |
*s = '\0'; | |
switch( base ) | |
{ | |
case 16: | |
while( u != 0 ) | |
{ | |
t = u & 0xF; | |
if( t >= 10 ) | |
{ | |
t += apBuf->flags.letBase - '0' - 10; | |
} | |
*( --s ) = t + '0'; | |
u >>= 4; | |
} | |
break; | |
case 8: | |
case 10: | |
/* GCC compiles very efficient */ | |
while( u ) | |
{ | |
t = u % base; | |
*( --s ) = t + '0'; | |
u /= base; | |
} | |
break; | |
/* | |
* // The generic case, not yet in use | |
* default: | |
* while( u ) | |
* { | |
* t = u % base; | |
* if( t >= 10) | |
* { | |
* t += apBuf->flags.letBase - '0' - 10; | |
* } | |
*( --s ) = t + '0'; | |
* u /= base; | |
* } | |
* break; | |
*/ | |
} | |
if( neg != 0 ) | |
{ | |
if( apBuf->flags.width && ( apBuf->flags.pad_zero != 0U ) ) | |
{ | |
if( strbuf_printchar( apBuf, '-' ) == 0 ) | |
{ | |
return pdFALSE; | |
} | |
--apBuf->flags.width; | |
} | |
else | |
{ | |
*( --s ) = '-'; | |
} | |
} | |
return prints( apBuf, s ); | |
} | |
/*-----------------------------------------------------------*/ | |
static BaseType_t printIpNr( struct SStringBuf * apBuf, | |
unsigned i ) | |
{ | |
apBuf->flags.printLimit = 3; | |
return printi( apBuf, i ); | |
} | |
static BaseType_t printIp( struct SStringBuf * apBuf, | |
unsigned uIPAddress ) | |
{ | |
BaseType_t xResult = pdFALSE; | |
memset( &( apBuf->flags ), 0, sizeof apBuf->flags ); | |
apBuf->flags.base = 10; | |
if( printIpNr( apBuf, uIPAddress >> 24 ) && strbuf_printchar( apBuf, '.' ) && | |
printIpNr( apBuf, ( uIPAddress >> 16 ) & 0xff ) && strbuf_printchar( apBuf, '.' ) && | |
printIpNr( apBuf, ( uIPAddress >> 8 ) & 0xff ) && strbuf_printchar( apBuf, '.' ) && | |
printIpNr( apBuf, uIPAddress & 0xff ) ) | |
{ | |
xResult = pdTRUE; | |
} | |
return xResult; | |
} | |
/*-----------------------------------------------------------*/ | |
static uint16_t usNetToHost( uint16_t usValue ) | |
{ | |
if( u32.ulWords[ 0 ] == 0x00010203 ) | |
{ | |
return usValue; | |
} | |
else | |
{ | |
return ( usValue << 8 ) | ( usValue >> 8 ); | |
} | |
} | |
static BaseType_t printIPv6( struct SStringBuf * apBuf, | |
uint16_t * pusAddress ) | |
{ | |
int iIndex; | |
int iZeroStart = -1; | |
int iZeroLength = 0; | |
int iCurStart = 0; | |
int iCurLength = 0; | |
for( iIndex = 0; iIndex < 8; iIndex++ ) | |
{ | |
uint16_t usValue = pusAddress[ iIndex ]; | |
if( usValue == 0 ) | |
{ | |
if( iCurLength == 0 ) | |
{ | |
iCurStart = iIndex; | |
} | |
iCurLength++; | |
} | |
if( ( usValue != 0 ) || ( iIndex == 7 ) ) | |
{ | |
if( iZeroLength < iCurLength ) | |
{ | |
iZeroLength = iCurLength; | |
iZeroStart = iCurStart; | |
} | |
iCurLength = 0; | |
} | |
} | |
apBuf->flags.base = 16; | |
apBuf->flags.letBase = 'a'; /* use lower-case letters 'a' to 'f' */ | |
for( iIndex = 0; iIndex < 8; iIndex++ ) | |
{ | |
if( iIndex == iZeroStart ) | |
{ | |
iIndex += iZeroLength - 1; | |
strbuf_printchar( apBuf, ':' ); | |
if( iIndex == 7 ) | |
{ | |
strbuf_printchar( apBuf, ':' ); | |
} | |
} | |
else | |
{ | |
if( iIndex > 0 ) | |
{ | |
strbuf_printchar( apBuf, ':' ); | |
} | |
printi( apBuf, ( int ) ( ( uint32_t ) usNetToHost( pusAddress[ iIndex ] ) ) ); | |
} | |
} | |
return pdTRUE; | |
} | |
/*-----------------------------------------------------------*/ | |
static void tiny_print( struct SStringBuf * apBuf, | |
const char * format, | |
va_list args ) | |
{ | |
char scr[ 2 ]; | |
for( ; ; ) | |
{ | |
int ch = *( format++ ); | |
if( ch != '%' ) | |
{ | |
do | |
{ | |
/* Put the most like flow in a small loop */ | |
if( strbuf_printchar_inline( apBuf, ch ) == 0 ) | |
{ | |
return; | |
} | |
ch = *( format++ ); | |
} while( ch != '%' ); | |
} | |
ch = *( format++ ); | |
/* Now ch has character after '%', format pointing to next */ | |
if( ch == '\0' ) | |
{ | |
break; | |
} | |
if( ch == '%' ) | |
{ | |
if( strbuf_printchar( apBuf, ch ) == 0 ) | |
{ | |
return; | |
} | |
continue; | |
} | |
memset( &apBuf->flags, '\0', sizeof apBuf->flags ); | |
if( ch == '-' ) | |
{ | |
ch = *( format++ ); | |
apBuf->flags.pad_right = 1U; | |
} | |
while( ch == '0' ) | |
{ | |
ch = *( format++ ); | |
apBuf->flags.pad_zero = 1U; | |
} | |
if( ch == '*' ) | |
{ | |
ch = *( format++ ); | |
apBuf->flags.width = va_arg( args, int ); | |
} | |
else | |
{ | |
while( ch >= '0' && ch <= '9' ) | |
{ | |
apBuf->flags.width *= 10; | |
apBuf->flags.width += ch - '0'; | |
ch = *( format++ ); | |
} | |
} | |
if( ch == '.' ) | |
{ | |
ch = *( format++ ); | |
if( ch == '*' ) | |
{ | |
apBuf->flags.printLimit = va_arg( args, int ); | |
ch = *( format++ ); | |
} | |
else | |
{ | |
while( ch >= '0' && ch <= '9' ) | |
{ | |
apBuf->flags.printLimit *= 10; | |
apBuf->flags.printLimit += ch - '0'; | |
ch = *( format++ ); | |
} | |
} | |
} | |
if( apBuf->flags.printLimit == 0 ) | |
{ | |
apBuf->flags.printLimit--; /* -1: make it unlimited */ | |
} | |
if( ch == 'p' ) | |
{ | |
if( ( format[ 0 ] == 'i' ) && ( format[ 1 ] == 'p' ) ) | |
{ | |
format += 2; /* eat the "pi" of "pip" */ | |
/* Print a IPv6 address */ | |
if( printIPv6( apBuf, va_arg( args, uint16_t * ) ) == 0 ) | |
{ | |
break; | |
} | |
continue; | |
} | |
} | |
if( ch == 's' ) | |
{ | |
register char * s = ( char * ) va_arg( args, int ); | |
if( prints( apBuf, s ? s : "(null)" ) == 0 ) | |
{ | |
break; | |
} | |
continue; | |
} | |
if( ch == 'c' ) | |
{ | |
/* char are converted to int then pushed on the stack */ | |
scr[ 0 ] = ( char ) va_arg( args, int ); | |
if( strbuf_printchar( apBuf, scr[ 0 ] ) == 0 ) | |
{ | |
return; | |
} | |
continue; | |
} | |
if( ch == 'l' ) | |
{ | |
ch = *( format++ ); | |
apBuf->flags.long32 = 1; | |
/* Makes not difference as u32 == long */ | |
} | |
if( ch == 'L' ) | |
{ | |
ch = *( format++ ); | |
apBuf->flags.long64 = 1; | |
/* Does make a difference */ | |
} | |
apBuf->flags.base = 10; | |
apBuf->flags.letBase = 'a'; | |
if( ( ch == 'd' ) || ( ch == 'u' ) ) | |
{ | |
apBuf->flags.isSigned = ( ch == 'd' ); | |
#if SPRINTF_LONG_LONG | |
if( apBuf->flags.long64 != pdFALSE ) | |
{ | |
if( printll( apBuf, va_arg( args, long long ) ) == 0 ) | |
{ | |
break; | |
} | |
} | |
else | |
#endif /* SPRINTF_LONG_LONG */ | |
if( printi( apBuf, va_arg( args, int ) ) == 0 ) | |
{ | |
break; | |
} | |
continue; | |
} | |
apBuf->flags.base = 16; /* From here all hexadecimal */ | |
if( ( ch == 'x' ) && ( format[ 0 ] == 'i' ) && ( format[ 1 ] == 'p' ) ) | |
{ | |
format += 2; /* eat the "xi" of "xip" */ | |
/* Will use base 10 again */ | |
if( printIp( apBuf, va_arg( args, int ) ) == 0 ) | |
{ | |
break; | |
} | |
continue; | |
} | |
if( ( ch == 'x' ) || ( ch == 'X' ) || ( ch == 'p' ) || ( ch == 'o' ) ) | |
{ | |
if( ch == 'X' ) | |
{ | |
apBuf->flags.letBase = 'A'; | |
} | |
else if( ch == 'o' ) | |
{ | |
apBuf->flags.base = 8; | |
} | |
#if SPRINTF_LONG_LONG | |
if( apBuf->flags.long64 != pdFALSE ) | |
{ | |
if( printll( apBuf, va_arg( args, long long ) ) == 0 ) | |
{ | |
break; | |
} | |
} | |
else | |
#endif /* SPRINTF_LONG_LONG */ | |
if( printi( apBuf, va_arg( args, int ) ) == 0 ) | |
{ | |
break; | |
} | |
continue; | |
} | |
} | |
strbuf_printchar( apBuf, '\0' ); | |
} | |
/*-----------------------------------------------------------*/ | |
int tiny_printf( const char * format, | |
... ) | |
{ | |
va_list args; | |
va_start( args, format ); | |
struct SStringBuf strBuf; | |
strbuf_init( &strBuf, NULL, ( const char * ) NULL ); | |
tiny_print( &strBuf, format, args ); | |
va_end( args ); | |
return strBuf.curLen; | |
} | |
/*-----------------------------------------------------------*/ | |
int vsnprintf( char * apBuf, | |
size_t aMaxLen, | |
const char * apFmt, | |
va_list args ) | |
{ | |
struct SStringBuf strBuf; | |
strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + aMaxLen ); | |
tiny_print( &strBuf, apFmt, args ); | |
return strBuf.curLen; | |
} | |
/*-----------------------------------------------------------*/ | |
int snprintf( char * apBuf, | |
size_t aMaxLen, | |
const char * apFmt, | |
... ) | |
{ | |
va_list args; | |
va_start( args, apFmt ); | |
struct SStringBuf strBuf; | |
strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + aMaxLen ); | |
tiny_print( &strBuf, apFmt, args ); | |
va_end( args ); | |
return strBuf.curLen; | |
} | |
/*-----------------------------------------------------------*/ | |
int sprintf( char * apBuf, | |
const char * apFmt, | |
... ) | |
{ | |
va_list args; | |
va_start( args, apFmt ); | |
struct SStringBuf strBuf; | |
strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + 1024 ); | |
tiny_print( &strBuf, apFmt, args ); | |
va_end( args ); | |
return strBuf.curLen; | |
} | |
/*-----------------------------------------------------------*/ | |
int vsprintf( char * apBuf, | |
const char * apFmt, | |
va_list args ) | |
{ | |
struct SStringBuf strBuf; | |
strbuf_init( &strBuf, apBuf, ( const char * ) apBuf + 1024 ); | |
tiny_print( &strBuf, apFmt, args ); | |
return strBuf.curLen; | |
} | |
/*-----------------------------------------------------------*/ | |
const char * mkSize( unsigned long long aSize, | |
char * apBuf, | |
int aLen ) | |
{ | |
/* Must be static because it might be returned. */ | |
static char retString[ 33 ]; | |
size_t gb, mb, kb, sb; | |
if( apBuf == NULL ) | |
{ | |
apBuf = retString; | |
aLen = sizeof retString; | |
} | |
gb = aSize / ( 1024 * 1024 * 1024 ); | |
aSize -= gb * ( 1024 * 1024 * 1024 ); | |
mb = aSize / ( 1024 * 1024 ); | |
aSize -= mb * ( 1024 * 1024 ); | |
kb = aSize / ( 1024 ); | |
aSize -= kb * ( 1024 ); | |
sb = aSize; | |
if( gb ) | |
{ | |
snprintf( apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); | |
} | |
else if( mb ) | |
{ | |
snprintf( apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb ) / 1024ul ) ); | |
} | |
else if( kb != 0ul ) | |
{ | |
snprintf( apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb ) / 1024ul ) ); | |
} | |
else | |
{ | |
snprintf( apBuf, aLen, "%u bytes", ( unsigned ) sb ); | |
} | |
return apBuf; | |
} | |
#ifdef _MSC_VER | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int printf( char const * const _Format, | |
... ) | |
{ | |
int _Result; | |
va_list _ArgList; | |
__crt_va_start( _ArgList, _Format ); | |
_Result = _vfprintf_l( stdout, _Format, NULL, _ArgList ); | |
__crt_va_end( _ArgList ); | |
return _Result; | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int sscanf( char const * const _Buffer, | |
char const * const _Format, | |
... ) | |
{ | |
int _Result; | |
va_list _ArgList; | |
__crt_va_start( _ArgList, _Format ); | |
_Result = _vsscanf_l( _Buffer, _Format, NULL, _ArgList ); | |
__crt_va_end( _ArgList ); | |
return _Result; | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int _vfprintf_l( FILE * const _Stream, | |
char const * const _Format, | |
_locale_t const _Locale, | |
va_list _ArgList ) | |
{ | |
return __stdio_common_vfprintf( _CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, _Stream, _Format, _Locale, _ArgList ); | |
} | |
#endif | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int _vsscanf_l( char const * const _Buffer, | |
char const * const _Format, | |
_locale_t const _Locale, | |
va_list _ArgList ) | |
{ | |
return __stdio_common_vsscanf( | |
_CRT_INTERNAL_LOCAL_SCANF_OPTIONS, | |
_Buffer, ( size_t ) -1, _Format, _Locale, _ArgList ); | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int scanf( char const * const _Format, | |
... ) | |
{ | |
int _Result; | |
va_list _ArgList; | |
__crt_va_start( _ArgList, _Format ); | |
_Result = _vfscanf_l( stdin, _Format, NULL, _ArgList ); | |
__crt_va_end( _ArgList ); | |
return _Result; | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int _vfscanf_l( _Inout_ FILE * const _Stream, | |
char const * const _Format, | |
const _Locale, | |
va_list _ArgList ) | |
{ | |
return __stdio_common_vfscanf( | |
_CRT_INTERNAL_LOCAL_SCANF_OPTIONS, | |
_Stream, _Format, _Locale, _ArgList ); | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int vsnprintf_s( char * const _Buffer, | |
size_t const _BufferCount, | |
size_t const _MaxCount, | |
char const * const _Format, | |
va_list _ArgList ) | |
{ | |
return _vsnprintf_s_l( _Buffer, _BufferCount, _MaxCount, _Format, NULL, _ArgList ); | |
} | |
int _vsnprintf_s( char * const _Buffer, | |
size_t const _BufferCount, | |
size_t const _MaxCount, | |
char const * const _Format, | |
va_list _ArgList ) | |
{ | |
return _vsnprintf_s_l( _Buffer, _BufferCount, _MaxCount, _Format, NULL, _ArgList ); | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#if defined( _NO_CRT_STDIO_INLINE ) | |
int _vsnprintf_s_l( char * const _Buffer, | |
size_t const _BufferCount, | |
size_t const _MaxCount, | |
char const * const _Format, | |
_locale_t const _Locale, | |
va_list _ArgList ) | |
{ | |
int const _Result = __stdio_common_vsnprintf_s( | |
_CRT_INTERNAL_LOCAL_PRINTF_OPTIONS, | |
_Buffer, _BufferCount, _MaxCount, _Format, _Locale, _ArgList ); | |
return _Result < 0 ? -1 : _Result; | |
} | |
#endif /* if defined( _NO_CRT_STDIO_INLINE ) */ | |
#endif /* __WIN32__ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment