Skip to content

Instantly share code, notes, and snippets.

@sdbbs
Last active July 15, 2022 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sdbbs/1927fbb4c4c71b3094dcee387dcfc7b7 to your computer and use it in GitHub Desktop.
Save sdbbs/1927fbb4c4c71b3094dcee387dcfc7b7 to your computer and use it in GitHub Desktop.
rp2040_fros_printf_test example project
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)
/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 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)
#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 */
// 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 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})
/*
* 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