commit ceb9b961f24eb99b8d9da4dd9cbe8637d475e4ad Author: That_One_Nerd Date: Mon Apr 29 13:51:34 2024 -0400 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e303e2c --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +# Compiled Object files +*.o +*.obj + +# Executables +*.bin +*.elf + +# PROS +bin/ +.vscode/ +.cache/ +compile_commands.json +temp.log +temp.errors +*.ini +.d/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ece8065 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +################################################################################ +######################### User configurable parameters ######################### +# filename extensions +CEXTS:=c +ASMEXTS:=s S +CXXEXTS:=cpp c++ cc + +# probably shouldn't modify these, but you may need them below +ROOT=. +FWDIR:=$(ROOT)/firmware +BINDIR=$(ROOT)/bin +SRCDIR=$(ROOT)/src +INCDIR=$(ROOT)/include + +WARNFLAGS+= +EXTRA_CFLAGS= +EXTRA_CXXFLAGS= + +# Set to 1 to enable hot/cold linking +USE_PACKAGE:=1 + +# Add libraries you do not wish to include in the cold image here +# EXCLUDE_COLD_LIBRARIES:= $(FWDIR)/your_library.a +EXCLUDE_COLD_LIBRARIES:= + +# Set this to 1 to add additional rules to compile your project as a PROS library template +IS_LIBRARY:=0 +# TODO: CHANGE THIS! +# Be sure that your header files are in the include directory inside of a folder with the +# same name as what you set LIBNAME to below. +LIBNAME:=libbest +VERSION:=1.0.0 +# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c +# this line excludes opcontrol.c and similar files +EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/main,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) + +# files that get distributed to every user (beyond your source archive) - add +# whatever files you want here. This line is configured to add all header files +# that are in the directory include/LIBNAME +TEMPLATE_FILES=$(INCDIR)/$(LIBNAME)/*.h $(INCDIR)/$(LIBNAME)/*.hpp + +.DEFAULT_GOAL=quick + +################################################################################ +################################################################################ +########## Nothing below this line should be edited by typical users ########### +-include ./common.mk diff --git a/common.mk b/common.mk new file mode 100644 index 0000000..33efe87 --- /dev/null +++ b/common.mk @@ -0,0 +1,308 @@ +ARCHTUPLE=arm-none-eabi- +DEVICE=VEX EDR V5 + +MFLAGS=-mcpu=cortex-a9 -mfpu=neon-fp16 -mfloat-abi=softfp -Os -g +CPPFLAGS=-D_POSIX_THREADS -D_UNIX98_THREAD_MUTEX_ATTRIBUTES -D_POSIX_TIMERS -D_POSIX_MONOTONIC_CLOCK +GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables + +# Check if the llemu files in libvgl exist. If they do, define macros that the +# llemu headers in the kernel repo can use to conditionally include the libvgl +# versions +ifneq (,$(wildcard ./include/liblvgl/llemu.h)) + CPPFLAGS += -D_PROS_INCLUDE_LIBLVGL_LLEMU_H +endif +ifneq (,$(wildcard ./include/liblvgl/llemu.hpp)) + CPPFLAGS += -D_PROS_INCLUDE_LIBLVGL_LLEMU_HPP +endif + +WARNFLAGS+=-Wno-psabi + +SPACE := $() $() +COMMA := , + +C_STANDARD?=gnu11 +CXX_STANDARD?=gnu++20 + +DEPDIR := .d +$(shell mkdir -p $(DEPDIR)) +DEPFLAGS = -MT $$@ -MMD -MP -MF $(DEPDIR)/$$*.Td +MAKEDEPFOLDER = -$(VV)mkdir -p $(DEPDIR)/$$(dir $$(patsubst $(BINDIR)/%, %, $(ROOT)/$$@)) +RENAMEDEPENDENCYFILE = -$(VV)mv -f $(DEPDIR)/$$*.Td $$(patsubst $(SRCDIR)/%, $(DEPDIR)/%.d, $(ROOT)/$$<) && touch $$@ + +LIBRARIES+=$(wildcard $(FWDIR)/*.a) +# Cannot include newlib and libc because not all of the req'd stubs are implemented +EXCLUDE_COLD_LIBRARIES+=$(FWDIR)/libc.a $(FWDIR)/libm.a +COLD_LIBRARIES=$(filter-out $(EXCLUDE_COLD_LIBRARIES), $(LIBRARIES)) +wlprefix=-Wl,$(subst $(SPACE),$(COMMA),$1) +LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lgcc -lstdc++ --end-group -T$(FWDIR)/v5-common.ld + +ASMFLAGS=$(MFLAGS) $(WARNFLAGS) +CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=$(C_STANDARD) +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=$(CXX_STANDARD) +LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(GCCFLAGS) +SIZEFLAGS=-d --common +NUMFMTFLAGS=--to=iec --format %.2f --suffix=B + +AR:=$(ARCHTUPLE)ar +# using arm-none-eabi-as generates a listing by default. This produces a super verbose output. +# Using gcc accomplishes the same thing without the extra output +AS:=$(ARCHTUPLE)gcc +CC:=$(ARCHTUPLE)gcc +CXX:=$(ARCHTUPLE)g++ +LD:=$(ARCHTUPLE)g++ +OBJCOPY:=$(ARCHTUPLE)objcopy +SIZETOOL:=$(ARCHTUPLE)size +READELF:=$(ARCHTUPLE)readelf +STRIP:=$(ARCHTUPLE)strip + +ifneq (, $(shell command -v gnumfmt 2> /dev/null)) + SIZES_NUMFMT:=| gnumfmt --field=-4 --header $(NUMFMTFLAGS) +else +ifneq (, $(shell command -v numfmt 2> /dev/null)) + SIZES_NUMFMT:=| numfmt --field=-4 --header $(NUMFMTFLAGS) +else + SIZES_NUMFMT:= +endif +endif + +ifneq (, $(shell command -v sed 2> /dev/null)) +SIZES_SED:=| sed -e 's/ dec/total/' +else +SIZES_SED:= +endif + +rwildcard=$(foreach d,$(filter-out $3,$(wildcard $1*)),$(call rwildcard,$d/,$2,$3)$(filter $(subst *,%,$2),$d)) + +# Colors +NO_COLOR=$(shell printf "%b" "\033[0m") +OK_COLOR=$(shell printf "%b" "\033[32;01m") +ERROR_COLOR=$(shell printf "%b" "\033[31;01m") +WARN_COLOR=$(shell printf "%b" "\033[33;01m") +STEP_COLOR=$(shell printf "%b" "\033[37;01m") +OK_STRING=$(OK_COLOR)[OK]$(NO_COLOR) +DONE_STRING=$(OK_COLOR)[DONE]$(NO_COLOR) +ERROR_STRING=$(ERROR_COLOR)[ERRORS]$(NO_COLOR) +WARN_STRING=$(WARN_COLOR)[WARNINGS]$(NO_COLOR) +ECHO=/bin/printf "%s\n" +echo=@$(ECHO) "$2$1$(NO_COLOR)" +echon=@/bin/printf "%s" "$2$1$(NO_COLOR)" + +define test_output_2 +@if test $(BUILD_VERBOSE) -eq $(or $4,1); then printf "%s\n" "$2"; fi; +@output="$$($2 2>&1)"; exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s%s\n" "$1" "$(ERROR_STRING)"; \ + printf "%s\n" "$$output"; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s%s\n" "$1" "$(WARN_STRING)"; \ + printf "%s\n" "$$output"; \ +else \ + printf "%s%s\n" "$1" "$3"; \ +fi; +endef + +define test_output +@output=$$($1 2>&1); exit=$$?; \ +if test 0 -ne $$exit; then \ + printf "%s\n" "$(ERROR_STRING)" $$?; \ + printf "%s\n" $$output; \ + exit $$exit; \ +elif test -n "$$output"; then \ + printf "%s\n" "$(WARN_STRING)"; \ + printf "%s" $$output; \ +else \ + printf "%s\n" "$2"; \ +fi; +endef + +# Makefile Verbosity +ifeq ("$(origin VERBOSE)", "command line") +BUILD_VERBOSE = $(VERBOSE) +endif +ifeq ("$(origin V)", "command line") +BUILD_VERBOSE = $(V) +endif + +ifndef BUILD_VERBOSE +BUILD_VERBOSE = 0 +endif + +# R is reduced (default messages) - build verbose = 0 +# V is verbose messages - verbosity = 1 +# VV is super verbose - verbosity = 2 +ifeq ($(BUILD_VERBOSE), 0) +R = @echo +D = @ +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 1) +R = @echo +D = +VV = @ +endif +ifeq ($(BUILD_VERBOSE), 2) +R = +D = +VV = +endif + +INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)") + +ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) +ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) +CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) +COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) +CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) +CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) + +GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) + +ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) + +LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o + +MONOLITH_BIN:=$(BINDIR)/monolith.bin +MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf + +HOT_BIN:=$(BINDIR)/hot.package.bin +HOT_ELF:=$(basename $(HOT_BIN)).elf +COLD_BIN:=$(BINDIR)/cold.package.bin +COLD_ELF:=$(basename $(COLD_BIN)).elf + +# Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87 +ifndef USE_PACKAGE +$(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how) +endif + +DEFAULT_BIN=$(MONOLITH_BIN) +ifeq ($(USE_PACKAGE),1) +DEFAULT_BIN=$(HOT_BIN) +endif + +-include $(wildcard $(FWDIR)/*.mk) + +.PHONY: all clean quick + +quick: $(DEFAULT_BIN) + +all: clean $(DEFAULT_BIN) + +clean: + @echo Cleaning project + -$Drm -rf $(BINDIR) + -$Drm -rf $(DEPDIR) + +ifeq ($(IS_LIBRARY),1) +ifeq ($(LIBNAME),libbest) +$(errror "You should rename your library! libbest is the default library name and should be changed") +endif + +LIBAR=$(BINDIR)/$(LIBNAME).a +TEMPLATE_DIR=$(ROOT)/template + +clean-template: + @echo Cleaning $(TEMPLATE_DIR) + -$Drm -rf $(TEMPLATE_DIR) + +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) + -$Drm -f $@ + $(call test_output_2,Creating $@ ,$(AR) rcs $@ $^, $(DONE_STRING)) + +.PHONY: library +library: $(LIBAR) + +.PHONY: template +template: clean-template $(LIBAR) + $Dpros c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS) +endif + +# if project is a library source, compile the archive and link output.elf against the archive rather than source objects +ifeq ($(IS_LIBRARY),1) +ELF_DEPS+=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) +LIBRARIES+=$(LIBAR) +else +ELF_DEPS+=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) +endif + +$(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking project with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(COLD_BIN): $(COLD_ELF) + $(call test_output_2,Creating cold package binary for $(DEVICE) ,$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(COLD_ELF): $(COLD_LIBRARIES) + $(VV)mkdir -p $(dir $@) + $(call test_output_2,Creating cold package with $(ARCHIVE_TEXT_LIST) ,$(LD) $(LDFLAGS) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + $(call test_output_2,Stripping cold package ,$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP --strip-symbol=_PROS_COMPILE_TIMESTAMP_INT $@ $@, $(DONE_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(HOT_BIN): $(HOT_ELF) $(COLD_BIN) + $(call test_output_2,Creating $@ for $(DEVICE) ,$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(HOT_ELF): $(COLD_ELF) $(ELF_DEPS) + $(call _pros_ld_timestamp) + $(call test_output_2,Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) ,$(LD) -nostartfiles $(LDFLAGS) $(call wlprefix,-R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + @printf "%s\n" "Section sizes:" + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +define asm_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + $$(call test_output_2,Compiled $$< ,$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) + +define c_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename $1).d + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) + +define cxx_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d + $(VV)mkdir -p $$(dir $$@) + $(MAKEDEPFOLDER) + $$(call test_output_2,Compiled $$< ,$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) + $(RENAMEDEPENDENCYFILE) +endef +$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) + +define _pros_ld_timestamp +$(VV)mkdir -p $(dir $(LDTIMEOBJ)) +@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, +@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro +@# which is the pwd | tail bit, which will truncate the path to the last 23 characters +@# +@# const int _PROS_COMPILE_TIMESTAMP_INT = $(( $(date +%s) - $(date +%z) * 3600 )) +@# char const * const _PROS_COMPILE_TIEMSTAMP = __DATE__ " " __TIME__ +@# char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)"; +@# +@# The shell command $$(($$(date +%s)+($$(date +%-z)/100*3600))) fetches the current +@# unix timestamp, and then adds the UTC timezone offset to account for time zones. + +$(call test_output_2,Adding timestamp ,echo 'const int _PROS_COMPILE_TIMESTAMP_INT = $(shell echo $$(($$(date +%s)+($$(date +%-z)/100*3600)))); char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(wildcard $(shell pwd | tail -c 23))";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING)) +endef + +# these rules are for build-compile-commands, which just print out sysroot information +cc-sysroot: + @echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null - +cxx-sysroot: + @echo | $(CXX) -c -x c++ $(CXXFLAGS) $(EXTRA_CXXFLAGS) --verbose -o /dev/null - + +$(DEPDIR)/%.d: ; +.PRECIOUS: $(DEPDIR)/%.d + +include $(wildcard $(patsubst $(SRCDIR)/%,$(DEPDIR)/%.d,$(CSRC) $(CXXSRC))) diff --git a/firmware/libc.a b/firmware/libc.a new file mode 100644 index 0000000..51439b9 Binary files /dev/null and b/firmware/libc.a differ diff --git a/firmware/liblvgl.a b/firmware/liblvgl.a new file mode 100644 index 0000000..6b3a68e Binary files /dev/null and b/firmware/liblvgl.a differ diff --git a/firmware/libm.a b/firmware/libm.a new file mode 100644 index 0000000..3d4066d Binary files /dev/null and b/firmware/libm.a differ diff --git a/firmware/libpros.a b/firmware/libpros.a new file mode 100644 index 0000000..ae9d587 Binary files /dev/null and b/firmware/libpros.a differ diff --git a/firmware/okapilib.a b/firmware/okapilib.a new file mode 100644 index 0000000..d8d4480 Binary files /dev/null and b/firmware/okapilib.a differ diff --git a/firmware/squiggles.mk b/firmware/squiggles.mk new file mode 100644 index 0000000..f970674 --- /dev/null +++ b/firmware/squiggles.mk @@ -0,0 +1 @@ +INCLUDE+=-iquote"$(ROOT)/include/okapi/squiggles" diff --git a/firmware/v5-common.ld b/firmware/v5-common.ld new file mode 100644 index 0000000..762a905 --- /dev/null +++ b/firmware/v5-common.ld @@ -0,0 +1,263 @@ +/* Define the sections, and where they are mapped in memory */ +SECTIONS +{ +/* This will get stripped out before uploading, but we need to place code + here so we can at least link to it (install_hot_table) */ +.hot_init : { + KEEP (*(.hot_magic)) + KEEP (*(.hot_init)) +} > HOT_MEMORY + +.text : { + KEEP (*(.vectors)) + /* boot data should be exactly 32 bytes long */ + *(.boot_data) + . = 0x20; + *(.boot) + . = ALIGN(64); + *(.freertos_vectors) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_except_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > RAM + +.init : { + KEEP (*(.init)) +} > RAM + +.fini : { + KEEP (*(.fini)) +} > RAM + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > RAM + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > RAM + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > RAM + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > RAM + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > RAM + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > RAM + +.got : { + *(.got) +} > RAM + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > RAM + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > RAM + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > RAM + +.eh_frame : { + *(.eh_frame) +} > RAM + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > RAM + +.gcc_except_table : { + *(.gcc_except_table) +} > RAM + +.mmu_tbl (ALIGN(16384)) : { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > RAM + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > RAM + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > RAM + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > RAM + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > RAM + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > RAM + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > RAM + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > RAM + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > RAM + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > RAM + +.bss (NOLOAD) : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; +} > RAM + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* Generate Stack and Heap definitions */ + +.heap (NOLOAD) : { + . = ALIGN(16); + _heap = .; + HeapBase = .; + _heap_start = .; + . += _HEAP_SIZE; + _heap_end = .; + HeapLimit = .; +} > HEAP + +.stack (NOLOAD) : { + . = ALIGN(16); + _stack_end = .; + . += _STACK_SIZE; + . = ALIGN(16); + _stack = .; + __stack = _stack; + . = ALIGN(16); + _irq_stack_end = .; + . += _IRQ_STACK_SIZE; + . = ALIGN(16); + __irq_stack = .; + _supervisor_stack_end = .; + . += _SUPERVISOR_STACK_SIZE; + . = ALIGN(16); + __supervisor_stack = .; + _abort_stack_end = .; + . += _ABORT_STACK_SIZE; + . = ALIGN(16); + __abort_stack = .; + _fiq_stack_end = .; + . += _FIQ_STACK_SIZE; + . = ALIGN(16); + __fiq_stack = .; + _undef_stack_end = .; + . += _UNDEF_STACK_SIZE; + . = ALIGN(16); + __undef_stack = .; +} > COLD_MEMORY + +_end = .; +} diff --git a/firmware/v5-hot.ld b/firmware/v5-hot.ld new file mode 100644 index 0000000..017cb35 --- /dev/null +++ b/firmware/v5-hot.ld @@ -0,0 +1,33 @@ +/* This stack is used during initialization, but FreeRTOS tasks have their own + stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks + in standard heap) */ +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; + +_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; +_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; +_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; +_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; +_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; + +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ + +/* Define Memories in the system */ +start_of_cold_mem = 0x03800000; +_COLD_MEM_SIZE = 0x04800000; +end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE; + +start_of_hot_mem = 0x07800000; +_HOT_MEM_SIZE = 0x00800000; +end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE; + +MEMORY +{ + /* user code 72M */ + COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */ + HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE + HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */ +} + +REGION_ALIAS("RAM", HOT_MEMORY); + +ENTRY(install_hot_table) diff --git a/firmware/v5.ld b/firmware/v5.ld new file mode 100644 index 0000000..7cbd06f --- /dev/null +++ b/firmware/v5.ld @@ -0,0 +1,33 @@ +/* This stack is used during initialization, but FreeRTOS tasks have their own + stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks + in standard heap) */ +_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; + +_ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; +_SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; +_IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; +_FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; +_UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; + +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ + +/* Define Memories in the system */ +start_of_cold_mem = 0x03800000; +_COLD_MEM_SIZE = 0x04800000; +end_of_cold_mem = start_of_cold_mem + _COLD_MEM_SIZE; + +start_of_hot_mem = 0x07800000; +_HOT_MEM_SIZE = 0x00800000; +end_of_hot_mem = start_of_hot_mem + _HOT_MEM_SIZE; + +MEMORY +{ + /* user code 72M */ + COLD_MEMORY : ORIGIN = start_of_cold_mem, LENGTH = _COLD_MEM_SIZE /* Just under 19 MB */ + HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE + HOT_MEMORY : ORIGIN = start_of_hot_mem, LENGTH = _HOT_MEM_SIZE /* Just over 8 MB */ +} + +REGION_ALIAS("RAM", COLD_MEMORY); + +ENTRY(vexStartup) diff --git a/include/api.h b/include/api.h new file mode 100644 index 0000000..58e58dd --- /dev/null +++ b/include/api.h @@ -0,0 +1,84 @@ +/** + * \file api.h + * + * PROS API header provides high-level user functionality + * + * Contains declarations for use by typical VEX programmers using PROS. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef _PROS_API_H_ +#define _PROS_API_H_ + +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#else /* (not) __cplusplus */ +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* __cplusplus */ + +#define PROS_VERSION_MAJOR 4 +#define PROS_VERSION_MINOR 0 +#define PROS_VERSION_PATCH 6 +#define PROS_VERSION_STRING "4.0.6" + +#include "pros/adi.h" +#include "pros/colors.h" +#include "pros/device.h" +#include "pros/distance.h" +#include "pros/error.h" +#include "pros/ext_adi.h" +#include "pros/gps.h" +#include "pros/imu.h" +#include "pros/link.h" +#include "pros/llemu.h" +#include "pros/misc.h" +#include "pros/motors.h" +#include "pros/optical.h" +#include "pros/rotation.h" +#include "pros/rtos.h" +#include "pros/screen.h" +#include "pros/vision.h" + +#ifdef __cplusplus +#include "pros/adi.hpp" +#include "pros/colors.hpp" +#include "pros/device.hpp" +#include "pros/distance.hpp" +#include "pros/gps.hpp" +#include "pros/imu.hpp" +#include "pros/link.hpp" +#include "pros/llemu.hpp" +#include "pros/misc.hpp" +#include "pros/motor_group.hpp" +#include "pros/motors.hpp" +#include "pros/optical.hpp" +#include "pros/rotation.hpp" +#include "pros/rtos.hpp" +#include "pros/screen.hpp" +#include "pros/vision.hpp" +#endif + +#endif // _PROS_API_H_ diff --git a/include/liblvgl/core/lv_disp.h b/include/liblvgl/core/lv_disp.h new file mode 100644 index 0000000..cd6efcc --- /dev/null +++ b/include/liblvgl/core/lv_disp.h @@ -0,0 +1,264 @@ +/** + * @file lv_disp.h + * + */ + +#ifndef LV_DISP_H +#define LV_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/hal/lv_hal.h" +#include "lv_obj.h" +#include "lv_theme.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_SCR_LOAD_ANIM_NONE, + LV_SCR_LOAD_ANIM_OVER_LEFT, + LV_SCR_LOAD_ANIM_OVER_RIGHT, + LV_SCR_LOAD_ANIM_OVER_TOP, + LV_SCR_LOAD_ANIM_OVER_BOTTOM, + LV_SCR_LOAD_ANIM_MOVE_LEFT, + LV_SCR_LOAD_ANIM_MOVE_RIGHT, + LV_SCR_LOAD_ANIM_MOVE_TOP, + LV_SCR_LOAD_ANIM_MOVE_BOTTOM, + LV_SCR_LOAD_ANIM_FADE_IN, + LV_SCR_LOAD_ANIM_FADE_ON = LV_SCR_LOAD_ANIM_FADE_IN, /*For backward compatibility*/ + LV_SCR_LOAD_ANIM_FADE_OUT, + LV_SCR_LOAD_ANIM_OUT_LEFT, + LV_SCR_LOAD_ANIM_OUT_RIGHT, + LV_SCR_LOAD_ANIM_OUT_TOP, + LV_SCR_LOAD_ANIM_OUT_BOTTOM, +} lv_scr_load_anim_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Return with a pointer to the active screen + * @param disp pointer to display which active screen should be get. (NULL to use the default + * screen) + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp); + +/** + * Return with a pointer to the previous screen. Only used during screen transitions. + * @param disp pointer to display which previous screen should be get. (NULL to use the default + * screen) + * @return pointer to the previous screen object or NULL if not used now + */ +lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp); + +/** + * Make a screen active + * @param scr pointer to a screen + */ +void lv_disp_load_scr(lv_obj_t * scr); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @param disp pointer to display which top layer should be get. (NULL to use the default screen) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp); + +/** + * Return with the sys. layer. (Same on every screen and it is above the normal screen and the top + * layer) + * @param disp pointer to display which sys. layer should be retrieved. (NULL to use the default screen) + * @return pointer to the sys layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp); + +/** + * Set the theme of a display + * @param disp pointer to a display + */ +void lv_disp_set_theme(lv_disp_t * disp, lv_theme_t * th); + +/** + * Get the theme of a display + * @param disp pointer to a display + * @return the display's theme (can be NULL) + */ +lv_theme_t * lv_disp_get_theme(lv_disp_t * disp); + +/** + * Set the background color of a display + * @param disp pointer to a display + * @param color color of the background + */ +void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color); + +/** + * Set the background image of a display + * @param disp pointer to a display + * @param img_src path to file or pointer to an `lv_img_dsc_t` variable + */ +void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src); + +/** + * Set opacity of the background + * @param disp pointer to a display + * @param opa opacity (0..255) + */ +void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa); + +/** + * Switch screen with animation + * @param scr pointer to the new screen to load + * @param anim_type type of the animation from `lv_scr_load_anim_t`, e.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT` + * @param time time of the animation + * @param delay delay before the transition + * @param auto_del true: automatically delete the old screen + */ +void lv_scr_load_anim(lv_obj_t * scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del); + +/** + * Get elapsed time since last user activity on a display (e.g. click) + * @param disp pointer to a display (NULL to get the overall smallest inactivity) + * @return elapsed ticks (milliseconds) since the last activity + */ +uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp); + +/** + * Manually trigger an activity on a display + * @param disp pointer to a display (NULL to use the default display) + */ +void lv_disp_trig_activity(lv_disp_t * disp); + +/** + * Clean any CPU cache that is related to the display. + * @param disp pointer to a display (NULL to use the default display) + */ +void lv_disp_clean_dcache(lv_disp_t * disp); + +/** + * Temporarily enable and disable the invalidation of the display. + * @param disp pointer to a display (NULL to use the default display) + * @param en true: enable invalidation; false: invalidation + */ +void lv_disp_enable_invalidation(lv_disp_t * disp, bool en); + +/** + * Get display invalidation is enabled. + * @param disp pointer to a display (NULL to use the default display) + * @return return true if invalidation is enabled + */ +bool lv_disp_is_invalidation_enabled(lv_disp_t * disp); + +/** + * Get a pointer to the screen refresher timer to + * modify its parameters with `lv_timer_...` functions. + * @param disp pointer to a display + * @return pointer to the display refresher timer. (NULL on error) + */ +lv_timer_t * _lv_disp_get_refr_timer(lv_disp_t * disp); + +/*------------------------------------------------ + * To improve backward compatibility + * Recommended only if you have one display + *------------------------------------------------*/ + +/** + * Get the active screen of the default display + * @return pointer to the active screen + */ +static inline lv_obj_t * lv_scr_act(void) +{ + return lv_disp_get_scr_act(lv_disp_get_default()); +} + +/** + * Get the top layer of the default display + * @return pointer to the top layer + */ +static inline lv_obj_t * lv_layer_top(void) +{ + return lv_disp_get_layer_top(lv_disp_get_default()); +} + +/** + * Get the active screen of the default display + * @return pointer to the sys layer + */ +static inline lv_obj_t * lv_layer_sys(void) +{ + return lv_disp_get_layer_sys(lv_disp_get_default()); +} + +static inline void lv_scr_load(lv_obj_t * scr) +{ + lv_disp_load_scr(scr); +} + +/********************** + * MACROS + **********************/ + +/*------------------------------------------------ + * To improve backward compatibility + * Recommended only if you have one display + *------------------------------------------------*/ + +#ifndef LV_HOR_RES +/** + * The horizontal resolution of the currently active display. + */ +#define LV_HOR_RES lv_disp_get_hor_res(lv_disp_get_default()) +#endif + +#ifndef LV_VER_RES +/** + * The vertical resolution of the currently active display. + */ +#define LV_VER_RES lv_disp_get_ver_res(lv_disp_get_default()) +#endif + +/** + * Scale the given number of pixels (a distance or size) relative to a 160 DPI display + * considering the DPI of the default display. + * It ensures that e.g. `lv_dpx(100)` will have the same physical size regardless to the + * DPI of the display. + * @param n the number of pixels to scale + * @return `n x current_dpi/160` + */ +static inline lv_coord_t lv_dpx(lv_coord_t n) +{ + return LV_DPX(n); +} + +/** + * Scale the given number of pixels (a distance or size) relative to a 160 DPI display + * considering the DPI of the given display. + * It ensures that e.g. `lv_dpx(100)` will have the same physical size regardless to the + * DPI of the display. + * @param obj a display whose dpi should be considered + * @param n the number of pixels to scale + * @return `n x current_dpi/160` + */ +static inline lv_coord_t lv_disp_dpx(const lv_disp_t * disp, lv_coord_t n) +{ + return _LV_DPX_CALC(lv_disp_get_dpi(disp), n); +} + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DISP_H*/ diff --git a/include/liblvgl/core/lv_event.h b/include/liblvgl/core/lv_event.h new file mode 100644 index 0000000..d5a9eb6 --- /dev/null +++ b/include/liblvgl/core/lv_event.h @@ -0,0 +1,363 @@ +/** + * @file lv_event.h + * + */ + +#ifndef LV_EVENT_H +#define LV_EVENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_event_dsc_t; + +/** + * Type of event being sent to the object. + */ +typedef enum { + LV_EVENT_ALL = 0, + + /** Input device events*/ + LV_EVENT_PRESSED, /**< The object has been pressed*/ + LV_EVENT_PRESSING, /**< The object is being pressed (called continuously while pressing)*/ + LV_EVENT_PRESS_LOST, /**< The object is still being pressed but slid cursor/finger off of the object */ + LV_EVENT_SHORT_CLICKED, /**< The object was pressed for a short period of time, then released it. Not called if scrolled.*/ + LV_EVENT_LONG_PRESSED, /**< Object has been pressed for at least `long_press_time`. Not called if scrolled.*/ + LV_EVENT_LONG_PRESSED_REPEAT, /**< Called after `long_press_time` in every `long_press_repeat_time` ms. Not called if scrolled.*/ + LV_EVENT_CLICKED, /**< Called on release if not scrolled (regardless to long press)*/ + LV_EVENT_RELEASED, /**< Called in every cases when the object has been released*/ + LV_EVENT_SCROLL_BEGIN, /**< Scrolling begins. The event parameter is a pointer to the animation of the scroll. Can be modified*/ + LV_EVENT_SCROLL_END, /**< Scrolling ends*/ + LV_EVENT_SCROLL, /**< Scrolling*/ + LV_EVENT_GESTURE, /**< A gesture is detected. Get the gesture with `lv_indev_get_gesture_dir(lv_indev_get_act());` */ + LV_EVENT_KEY, /**< A key is sent to the object. Get the key with `lv_indev_get_key(lv_indev_get_act());`*/ + LV_EVENT_FOCUSED, /**< The object is focused*/ + LV_EVENT_DEFOCUSED, /**< The object is defocused*/ + LV_EVENT_LEAVE, /**< The object is defocused but still selected*/ + LV_EVENT_HIT_TEST, /**< Perform advanced hit-testing*/ + + /** Drawing events*/ + LV_EVENT_COVER_CHECK, /**< Check if the object fully covers an area. The event parameter is `lv_cover_check_info_t *`.*/ + LV_EVENT_REFR_EXT_DRAW_SIZE, /**< Get the required extra draw area around the object (e.g. for shadow). The event parameter is `lv_coord_t *` to store the size.*/ + LV_EVENT_DRAW_MAIN_BEGIN, /**< Starting the main drawing phase*/ + LV_EVENT_DRAW_MAIN, /**< Perform the main drawing*/ + LV_EVENT_DRAW_MAIN_END, /**< Finishing the main drawing phase*/ + LV_EVENT_DRAW_POST_BEGIN, /**< Starting the post draw phase (when all children are drawn)*/ + LV_EVENT_DRAW_POST, /**< Perform the post draw phase (when all children are drawn)*/ + LV_EVENT_DRAW_POST_END, /**< Finishing the post draw phase (when all children are drawn)*/ + LV_EVENT_DRAW_PART_BEGIN, /**< Starting to draw a part. The event parameter is `lv_obj_draw_dsc_t *`. */ + LV_EVENT_DRAW_PART_END, /**< Finishing to draw a part. The event parameter is `lv_obj_draw_dsc_t *`. */ + + /** Special events*/ + LV_EVENT_VALUE_CHANGED, /**< The object's value has changed (i.e. slider moved)*/ + LV_EVENT_INSERT, /**< A text is inserted to the object. The event data is `char *` being inserted.*/ + LV_EVENT_REFRESH, /**< Notify the object to refresh something on it (for the user)*/ + LV_EVENT_READY, /**< A process has finished*/ + LV_EVENT_CANCEL, /**< A process has been cancelled */ + + /** Other events*/ + LV_EVENT_DELETE, /**< Object is being deleted*/ + LV_EVENT_CHILD_CHANGED, /**< Child was removed, added, or its size, position were changed */ + LV_EVENT_CHILD_CREATED, /**< Child was created, always bubbles up to all parents*/ + LV_EVENT_CHILD_DELETED, /**< Child was deleted, always bubbles up to all parents*/ + LV_EVENT_SCREEN_UNLOAD_START, /**< A screen unload started, fired immediately when scr_load is called*/ + LV_EVENT_SCREEN_LOAD_START, /**< A screen load started, fired when the screen change delay is expired*/ + LV_EVENT_SCREEN_LOADED, /**< A screen was loaded*/ + LV_EVENT_SCREEN_UNLOADED, /**< A screen was unloaded*/ + LV_EVENT_SIZE_CHANGED, /**< Object coordinates/size have changed*/ + LV_EVENT_STYLE_CHANGED, /**< Object's style has changed*/ + LV_EVENT_LAYOUT_CHANGED, /**< The children position has changed due to a layout recalculation*/ + LV_EVENT_GET_SELF_SIZE, /**< Get the internal size of a widget*/ + + _LV_EVENT_LAST, /** Number of default events*/ + + + LV_EVENT_PREPROCESS = 0x80, /** This is a flag that can be set with an event so it's processed + before the class default event processing */ +} lv_event_code_t; + +typedef struct _lv_event_t { + struct _lv_obj_t * target; + struct _lv_obj_t * current_target; + lv_event_code_t code; + void * user_data; + void * param; + struct _lv_event_t * prev; + uint8_t deleted : 1; + uint8_t stop_processing : 1; + uint8_t stop_bubbling : 1; +} lv_event_t; + +/** + * @brief Event callback. + * Events are used to notify the user of some action being taken on the object. + * For details, see ::lv_event_t. + */ +typedef void (*lv_event_cb_t)(lv_event_t * e); + +/** + * Used as the event parameter of ::LV_EVENT_HIT_TEST to check if an `point` can click the object or not. + * `res` should be set like this: + * - If already set to `false` an other event wants that point non clickable. If you want to respect it leave it as `false` or set `true` to overwrite it. + * - If already set `true` and `point` shouldn't be clickable set to `false` + * - If already set to `true` you agree that `point` can click the object leave it as `true` + */ +typedef struct { + const lv_point_t * point; /**< A point relative to screen to check if it can click the object or not*/ + bool res; /**< true: `point` can click the object; false: it cannot*/ +} lv_hit_test_info_t; + +/** + * Used as the event parameter of ::LV_EVENT_COVER_CHECK to check if an area is covered by the object or not. + * In the event use `const lv_area_t * area = lv_event_get_cover_area(e)` to get the area to check + * and `lv_event_set_cover_res(e, res)` to set the result. + */ +typedef struct { + lv_cover_res_t res; + const lv_area_t * area; +} lv_cover_check_info_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Send an event to the object + * @param obj pointer to an object + * @param event_code the type of the event from `lv_event_t` + * @param param arbitrary data depending on the widget type and the event. (Usually `NULL`) + * @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event_code + */ +lv_res_t lv_event_send(struct _lv_obj_t * obj, lv_event_code_t event_code, void * param); + +/** + * Used by the widgets internally to call the ancestor widget types's event handler + * @param class_p pointer to the class of the widget (NOT the ancestor class) + * @param e pointer to the event descriptor + * @return LV_RES_OK: the target object was not deleted in the event; LV_RES_INV: it was deleted in the event_code + */ +lv_res_t lv_obj_event_base(const lv_obj_class_t * class_p, lv_event_t * e); + +/** + * Get the object originally targeted by the event. It's the same even if the event is bubbled. + * @param e pointer to the event descriptor + * @return the target of the event_code + */ +struct _lv_obj_t * lv_event_get_target(lv_event_t * e); + +/** + * Get the current target of the event. It's the object which event handler being called. + * If the event is not bubbled it's the same as "normal" target. + * @param e pointer to the event descriptor + * @return pointer to the current target of the event_code + */ +struct _lv_obj_t * lv_event_get_current_target(lv_event_t * e); + +/** + * Get the event code of an event + * @param e pointer to the event descriptor + * @return the event code. (E.g. `LV_EVENT_CLICKED`, `LV_EVENT_FOCUSED`, etc) + */ +lv_event_code_t lv_event_get_code(lv_event_t * e); + +/** + * Get the parameter passed when the event was sent + * @param e pointer to the event descriptor + * @return pointer to the parameter + */ +void * lv_event_get_param(lv_event_t * e); + +/** + * Get the user_data passed when the event was registered on the object + * @param e pointer to the event descriptor + * @return pointer to the user_data + */ +void * lv_event_get_user_data(lv_event_t * e); + +/** + * Stop the event from bubbling. + * This is only valid when called in the middle of an event processing chain. + * @param e pointer to the event descriptor + */ +void lv_event_stop_bubbling(lv_event_t * e); + +/** + * Stop processing this event. + * This is only valid when called in the middle of an event processing chain. + * @param e pointer to the event descriptor + */ +void lv_event_stop_processing(lv_event_t * e); + +/** + * Register a new, custom event ID. + * It can be used the same way as e.g. `LV_EVENT_CLICKED` to send custom events + * @return the new event id + * @example + * uint32_t LV_EVENT_MINE = 0; + * ... + * e = lv_event_register_id(); + * ... + * lv_event_send(obj, LV_EVENT_MINE, &some_data); + */ +uint32_t lv_event_register_id(void); + +/** + * Nested events can be called and one of them might belong to an object that is being deleted. + * Mark this object's `event_temp_data` deleted to know that its `lv_event_send` should return `LV_RES_INV` + * @param obj pointer to an object to mark as deleted + */ +void _lv_event_mark_deleted(struct _lv_obj_t * obj); + + +/** + * Add an event handler function for an object. + * Used by the user to react on event which happens with the object. + * An object can have multiple event handler. They will be called in the same order as they were added. + * @param obj pointer to an object + * @param filter and event code (e.g. `LV_EVENT_CLICKED`) on which the event should be called. `LV_EVENT_ALL` can be sued the receive all the events. + * @param event_cb the new event function + * @param user_data custom data data will be available in `event_cb` + * @return a pointer the event descriptor. Can be used in ::lv_obj_remove_event_dsc + */ +struct _lv_event_dsc_t * lv_obj_add_event_cb(struct _lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter, + void * user_data); + +/** + * Remove an event handler function for an object. + * @param obj pointer to an object + * @param event_cb the event function to remove, or `NULL` to remove the firstly added event callback + * @return true if any event handlers were removed + */ +bool lv_obj_remove_event_cb(struct _lv_obj_t * obj, lv_event_cb_t event_cb); + +/** + * Remove an event handler function with a specific user_data from an object. + * @param obj pointer to an object + * @param event_cb the event function to remove, or `NULL` only `user_data` matters. + * @param event_user_data the user_data specified in ::lv_obj_add_event_cb + * @return true if any event handlers were removed + */ +bool lv_obj_remove_event_cb_with_user_data(struct _lv_obj_t * obj, lv_event_cb_t event_cb, + const void * event_user_data); + +/** + * DEPRECATED because doesn't work if multiple event handlers are added to an object. + * Remove an event handler function for an object. + * @param obj pointer to an object + * @param event_dsc pointer to an event descriptor to remove (returned by ::lv_obj_add_event_cb) + * @return true if any event handlers were removed + */ +bool lv_obj_remove_event_dsc(struct _lv_obj_t * obj, struct _lv_event_dsc_t * event_dsc); + +/** + * The user data of an event object event callback. Always the first match with `event_cb` will be returned. + * @param obj pointer to an object + * @param event_cb the event function + * @return the user_data + */ +void * lv_obj_get_event_user_data(struct _lv_obj_t * obj, lv_event_cb_t event_cb); + +/** + * Get the input device passed as parameter to indev related events. + * @param e pointer to an event + * @return the indev that triggered the event or NULL if called on a not indev related event + */ +lv_indev_t * lv_event_get_indev(lv_event_t * e); + +/** + * Get the part draw descriptor passed as parameter to `LV_EVENT_DRAW_PART_BEGIN/END`. + * @param e pointer to an event + * @return the part draw descriptor to hook the drawing or NULL if called on an unrelated event + */ +lv_obj_draw_part_dsc_t * lv_event_get_draw_part_dsc(lv_event_t * e); + +/** + * Get the draw context which should be the first parameter of the draw functions. + * Namely: `LV_EVENT_DRAW_MAIN/POST`, `LV_EVENT_DRAW_MAIN/POST_BEGIN`, `LV_EVENT_DRAW_MAIN/POST_END` + * @param e pointer to an event + * @return pointer to a draw context or NULL if called on an unrelated event + */ +lv_draw_ctx_t * lv_event_get_draw_ctx(lv_event_t * e); + +/** + * Get the old area of the object before its size was changed. Can be used in `LV_EVENT_SIZE_CHANGED` + * @param e pointer to an event + * @return the old absolute area of the object or NULL if called on an unrelated event + */ +const lv_area_t * lv_event_get_old_size(lv_event_t * e); + +/** + * Get the key passed as parameter to an event. Can be used in `LV_EVENT_KEY` + * @param e pointer to an event + * @return the triggering key or NULL if called on an unrelated event + */ +uint32_t lv_event_get_key(lv_event_t * e); + +/** + * Get the animation descriptor of a scrolling. Can be used in `LV_EVENT_SCROLL_BEGIN` + * @param e pointer to an event + * @return the animation that will scroll the object. (can be modified as required) + */ +lv_anim_t * lv_event_get_scroll_anim(lv_event_t * e); + +/** + * Set the new extra draw size. Can be used in `LV_EVENT_REFR_EXT_DRAW_SIZE` + * @param e pointer to an event + * @param size The new extra draw size + */ +void lv_event_set_ext_draw_size(lv_event_t * e, lv_coord_t size); + +/** + * Get a pointer to an `lv_point_t` variable in which the self size should be saved (width in `point->x` and height `point->y`). + * Can be used in `LV_EVENT_GET_SELF_SIZE` + * @param e pointer to an event + * @return pointer to `lv_point_t` or NULL if called on an unrelated event + */ +lv_point_t * lv_event_get_self_size_info(lv_event_t * e); + +/** + * Get a pointer to an `lv_hit_test_info_t` variable in which the hit test result should be saved. Can be used in `LV_EVENT_HIT_TEST` + * @param e pointer to an event + * @return pointer to `lv_hit_test_info_t` or NULL if called on an unrelated event + */ +lv_hit_test_info_t * lv_event_get_hit_test_info(lv_event_t * e); + +/** + * Get a pointer to an area which should be examined whether the object fully covers it or not. + * Can be used in `LV_EVENT_HIT_TEST` + * @param e pointer to an event + * @return an area with absolute coordinates to check + */ +const lv_area_t * lv_event_get_cover_area(lv_event_t * e); + +/** + * Set the result of cover checking. Can be used in `LV_EVENT_COVER_CHECK` + * @param e pointer to an event + * @param res an element of ::lv_cover_check_info_t + */ +void lv_event_set_cover_res(lv_event_t * e, lv_cover_res_t res); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_EVENT_H*/ diff --git a/include/liblvgl/core/lv_group.h b/include/liblvgl/core/lv_group.h new file mode 100644 index 0000000..85df325 --- /dev/null +++ b/include/liblvgl/core/lv_group.h @@ -0,0 +1,266 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include "liblvgl/misc/lv_ll.h" +#include "liblvgl/misc/lv_types.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ + +enum { + LV_KEY_UP = 17, /*0x11*/ + LV_KEY_DOWN = 18, /*0x12*/ + LV_KEY_RIGHT = 19, /*0x13*/ + LV_KEY_LEFT = 20, /*0x14*/ + LV_KEY_ESC = 27, /*0x1B*/ + LV_KEY_DEL = 127, /*0x7F*/ + LV_KEY_BACKSPACE = 8, /*0x08*/ + LV_KEY_ENTER = 10, /*0x0A, '\n'*/ + LV_KEY_NEXT = 9, /*0x09, '\t'*/ + LV_KEY_PREV = 11, /*0x0B, '*/ + LV_KEY_HOME = 2, /*0x02, STX*/ + LV_KEY_END = 3, /*0x03, ETX*/ +}; +typedef uint8_t lv_key_t; + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_group_t; + +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); +typedef void (*lv_group_edge_cb_t)(struct _lv_group_t *, bool); + +/** + * Groups can be used to logically hold objects so that they can be individually focused. + * They are NOT for laying out objects on a screen (try layouts for that). + */ +typedef struct _lv_group_t { + lv_ll_t obj_ll; /**< Linked list to store the objects in the group*/ + struct _lv_obj_t ** obj_focus; /**< The object in focus*/ + + lv_group_focus_cb_t focus_cb; /**< A function to call when a new object is focused (optional)*/ + lv_group_edge_cb_t edge_cb; /**< A function to call when an edge is reached, no more focus + targets are available in this direction (to allow edge feedback + like a sound or a scroll bounce) */ + +#if LV_USE_USER_DATA + void * user_data; +#endif + + uint8_t frozen : 1; /**< 1: can't focus to new object*/ + uint8_t editing : 1; /**< 1: Edit mode, 0: Navigate mode*/ + uint8_t refocus_policy : 1; /**< 1: Focus prev if focused on deletion. 0: Focus next if focused on + deletion.*/ + uint8_t wrap : 1; /**< 1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end + of list.*/ +} lv_group_t; + + +typedef enum { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the group module + * @remarks Internal function, do not call directly. + */ +void _lv_group_init(void); + +/** + * Create a new object group + * @return pointer to the new object group + */ +lv_group_t * lv_group_create(void); + +/** + * Delete a group object + * @param group pointer to a group + */ +void lv_group_del(lv_group_t * group); + +/** + * Set a default group. New object are added to this group if it's enabled in their class with `add_to_def_group = true` + * @param group pointer to a group (can be `NULL`) + */ +void lv_group_set_default(lv_group_t * group); + +/** + * Get the default group + * @return pointer to the default group + */ +lv_group_t * lv_group_get_default(void); + +/** + * Add an object to a group + * @param group pointer to a group + * @param obj pointer to an object to add + */ +void lv_group_add_obj(lv_group_t * group, struct _lv_obj_t * obj); + +/** + * Swap 2 object in a group. The object must be in the same group + * @param obj1 pointer to an object + * @param obj2 pointer to an other object + */ +void lv_group_swap_obj(struct _lv_obj_t * obj1, struct _lv_obj_t * obj2); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(struct _lv_obj_t * obj); + +/** + * Remove all objects from a group + * @param group pointer to a group + */ +void lv_group_remove_all_objs(lv_group_t * group); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(struct _lv_obj_t * obj); + +/** + * Focus the next object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_next(lv_group_t * group); + +/** + * Focus the previous object in a group (defocus the current) + * @param group pointer to a group + */ +void lv_group_focus_prev(lv_group_t * group); + +/** + * Do not let to change the focus from the current object + * @param group pointer to a group + * @param en true: freeze, false: release freezing (normal mode) + */ +void lv_group_focus_freeze(lv_group_t * group, bool en); + +/** + * Send a control character to the focuses object of a group + * @param group pointer to a group + * @param c a character (use LV_KEY_.. to navigate) + * @return result of focused object in group. + */ +lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c); + +/** + * Set a function for a group which will be called when a new object is focused + * @param group pointer to a group + * @param focus_cb the call back function or NULL if unused + */ +void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb); + +/** + * Set a function for a group which will be called when a focus edge is reached + * @param group pointer to a group + * @param edge_cb the call back function or NULL if unused + */ +void lv_group_set_edge_cb(lv_group_t * group, lv_group_edge_cb_t edge_cb); + + +/** + * Set whether the next or previous item in a group is focused if the currently focused obj is + * deleted. + * @param group pointer to a group + * @param policy new refocus policy enum + */ +void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy); + +/** + * Manually set the current mode (edit or navigate). + * @param group pointer to group + * @param edit true: edit mode; false: navigate mode + */ +void lv_group_set_editing(lv_group_t * group, bool edit); + +/** + * Set whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en true: wrapping enabled; false: wrapping disabled + */ +void lv_group_set_wrap(lv_group_t * group, bool en); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +struct _lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get the focus callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group); + +/** + * Get the edge callback function of a group + * @param group pointer to a group + * @return the call back function or NULL if not set + */ +lv_group_edge_cb_t lv_group_get_edge_cb(const lv_group_t * group); + +/** + * Get the current mode (edit or navigate). + * @param group pointer to group + * @return true: edit mode; false: navigate mode + */ +bool lv_group_get_editing(const lv_group_t * group); + +/** + * Get whether focus next/prev will allow wrapping from first->last or last->first object. + * @param group pointer to group + * @param en true: wrapping enabled; false: wrapping disabled + */ +bool lv_group_get_wrap(lv_group_t * group); + +/** + * Get the number of object in the group + * @param group pointer to a group + * @return number of objects in the group + */ +uint32_t lv_group_get_obj_count(lv_group_t * group); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/include/liblvgl/core/lv_indev.h b/include/liblvgl/core/lv_indev.h new file mode 100644 index 0000000..4692ef3 --- /dev/null +++ b/include/liblvgl/core/lv_indev.h @@ -0,0 +1,176 @@ +/** + * @file lv_indev.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "liblvgl/hal/lv_hal_indev.h" +#include "lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Called periodically to read the input devices + * @param timer pointer to a timer to read + */ +void lv_indev_read_timer_cb(lv_timer_t * timer); + +/** + * Enable or disable one or all input devices (default enabled) + * @param indev pointer to an input device or NULL to enable/disable all of them + * @param en true to enable, false to disable + */ +void lv_indev_enable(lv_indev_t * indev, bool en); + +/** + * Get the currently processed input device. Can be used in action functions too. + * @return pointer to the currently processed input device or NULL if no input device processing + * right now + */ +lv_indev_t * lv_indev_get_act(void); + +/** + * Get the type of an input device + * @param indev pointer to an input device + * @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`) + */ +lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev); + +/** + * Reset one or all input devices + * @param indev pointer to an input device to reset or NULL to reset all of them + * @param obj pointer to an object which triggers the reset. + */ +void lv_indev_reset(lv_indev_t * indev, lv_obj_t * obj); + +/** + * Reset the long press state of an input device + * @param indev pointer to an input device + */ +void lv_indev_reset_long_press(lv_indev_t * indev); + +/** + * Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON) + * @param indev pointer to an input device + * @param cur_obj pointer to an object to be used as cursor + */ +void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj); + +/** + * Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group); + +/** + * Set the an array of points for LV_INDEV_TYPE_BUTTON. + * These points will be assigned to the buttons to press a specific point on the screen + * @param indev pointer to an input device + * @param group point to a group + */ +void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[]); + +/** + * Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the result + */ +void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point); + +/** +* Get the current gesture direct +* @param indev pointer to an input device +* @return current gesture direct +*/ +lv_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev); + +/** + * Get the last pressed key of an input device (for LV_INDEV_TYPE_KEYPAD) + * @param indev pointer to an input device + * @return the last pressed key (0 on error) + */ +uint32_t lv_indev_get_key(const lv_indev_t * indev); + +/** + * Check the current scroll direction of an input device (for LV_INDEV_TYPE_POINTER and + * LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return LV_DIR_NONE: no scrolling now + * LV_DIR_HOR/VER + */ +lv_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev); + +/** + * Get the currently scrolled object (for LV_INDEV_TYPE_POINTER and + * LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return pointer to the currently scrolled object or NULL if no scrolling by this indev + */ +lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev); + +/** + * Get the movement vector of an input device (for LV_INDEV_TYPE_POINTER and + * LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the types.pointer.vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/** + * Gets a pointer to the currently active object in the currently processed input device. + * @return pointer to currently active object or NULL if no active object + */ +lv_obj_t * lv_indev_get_obj_act(void); + +/** + * Get a pointer to the indev read timer to + * modify its parameters with `lv_timer_...` functions. + * @param indev pointer to an input device + * @return pointer to the indev read refresher timer. (NULL on error) + */ +lv_timer_t * lv_indev_get_read_timer(lv_disp_t * indev); + +/** + * Search the most top, clickable object by a point + * @param obj pointer to a start object, typically the screen + * @param point pointer to a point for searching the most top child + * @return pointer to the found object or NULL if there was no suitable object + */ +lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/include/liblvgl/core/lv_indev_scroll.h b/include/liblvgl/core/lv_indev_scroll.h new file mode 100644 index 0000000..76c64d1 --- /dev/null +++ b/include/liblvgl/core/lv_indev_scroll.h @@ -0,0 +1,65 @@ +/** + * @file lv_indev_scroll.h + * + */ + +#ifndef LV_INDEV_SCROLL_H +#define LV_INDEV_SCROLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Handle scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_indev_scroll_handler(_lv_indev_proc_t * proc); + +/** + * Handle throwing after scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_indev_scroll_throw_handler(_lv_indev_proc_t * proc); + +/** + * Predict where would a scroll throw end + * @param indev pointer to an input device + * @param dir ` LV_DIR_VER` or `LV_DIR_HOR` + * @return the difference compared to the current position when the throw would be finished + */ +lv_coord_t lv_indev_scroll_throw_predict(lv_indev_t * indev, lv_dir_t dir); + +/** + * Get the distance of the nearest snap point + * @param obj the object on which snap points should be found + * @param p save the distance of the found snap point there + */ +void lv_indev_scroll_get_snap_dist(lv_obj_t * obj, lv_point_t * p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_INDEV_SCROLL_H*/ diff --git a/include/liblvgl/core/lv_obj.h b/include/liblvgl/core/lv_obj.h new file mode 100644 index 0000000..c89e460 --- /dev/null +++ b/include/liblvgl/core/lv_obj.h @@ -0,0 +1,409 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_conf_internal.h" + +#include +#include +#include "../misc/lv_style.h" +#include "../misc/lv_types.h" +#include "../misc/lv_area.h" +#include "../misc/lv_color.h" +#include "../misc/lv_assert.h" +#include "../hal/lv_hal.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +/** + * Possible states of a widget. + * OR-ed values are possible + */ +enum { + LV_STATE_DEFAULT = 0x0000, + LV_STATE_CHECKED = 0x0001, + LV_STATE_FOCUSED = 0x0002, + LV_STATE_FOCUS_KEY = 0x0004, + LV_STATE_EDITED = 0x0008, + LV_STATE_HOVERED = 0x0010, + LV_STATE_PRESSED = 0x0020, + LV_STATE_SCROLLED = 0x0040, + LV_STATE_DISABLED = 0x0080, + + LV_STATE_USER_1 = 0x1000, + LV_STATE_USER_2 = 0x2000, + LV_STATE_USER_3 = 0x4000, + LV_STATE_USER_4 = 0x8000, + + LV_STATE_ANY = 0xFFFF, /**< Special value can be used in some functions to target all states*/ +}; + +typedef uint16_t lv_state_t; + +/** + * The possible parts of widgets. + * The parts can be considered as the internal building block of the widgets. + * E.g. slider = background + indicator + knob + * Not all parts are used by every widget + */ +enum { + LV_PART_MAIN = 0x000000, /**< A background like rectangle*/ + LV_PART_SCROLLBAR = 0x010000, /**< The scrollbar(s)*/ + LV_PART_INDICATOR = 0x020000, /**< Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox*/ + LV_PART_KNOB = 0x030000, /**< Like handle to grab to adjust the value*/ + LV_PART_SELECTED = 0x040000, /**< Indicate the currently selected option or section*/ + LV_PART_ITEMS = 0x050000, /**< Used if the widget has multiple similar elements (e.g. table cells)*/ + LV_PART_TICKS = 0x060000, /**< Ticks on scale e.g. for a chart or meter*/ + LV_PART_CURSOR = 0x070000, /**< Mark a specific place e.g. for text area's cursor or on a chart*/ + + LV_PART_CUSTOM_FIRST = 0x080000, /**< Extension point for custom widgets*/ + + LV_PART_ANY = 0x0F0000, /**< Special value can be used in some functions to target all parts*/ +}; + +typedef uint32_t lv_part_t; + +/** + * On/Off features controlling the object's behavior. + * OR-ed values are possible + */ +enum { + LV_OBJ_FLAG_HIDDEN = (1L << 0), /**< Make the object hidden. (Like it wasn't there at all)*/ + LV_OBJ_FLAG_CLICKABLE = (1L << 1), /**< Make the object clickable by the input devices*/ + LV_OBJ_FLAG_CLICK_FOCUSABLE = (1L << 2), /**< Add focused state to the object when clicked*/ + LV_OBJ_FLAG_CHECKABLE = (1L << 3), /**< Toggle checked state when the object is clicked*/ + LV_OBJ_FLAG_SCROLLABLE = (1L << 4), /**< Make the object scrollable*/ + LV_OBJ_FLAG_SCROLL_ELASTIC = (1L << 5), /**< Allow scrolling inside but with slower speed*/ + LV_OBJ_FLAG_SCROLL_MOMENTUM = (1L << 6), /**< Make the object scroll further when "thrown"*/ + LV_OBJ_FLAG_SCROLL_ONE = (1L << 7), /**< Allow scrolling only one snappable children*/ + LV_OBJ_FLAG_SCROLL_CHAIN_HOR = (1L << 8), /**< Allow propagating the horizontal scroll to a parent*/ + LV_OBJ_FLAG_SCROLL_CHAIN_VER = (1L << 9), /**< Allow propagating the vertical scroll to a parent*/ + LV_OBJ_FLAG_SCROLL_CHAIN = (LV_OBJ_FLAG_SCROLL_CHAIN_HOR | LV_OBJ_FLAG_SCROLL_CHAIN_VER), + LV_OBJ_FLAG_SCROLL_ON_FOCUS = (1L << 10), /**< Automatically scroll object to make it visible when focused*/ + LV_OBJ_FLAG_SCROLL_WITH_ARROW = (1L << 11), /**< Allow scrolling the focused object with arrow keys*/ + LV_OBJ_FLAG_SNAPPABLE = (1L << 12), /**< If scroll snap is enabled on the parent it can snap to this object*/ + LV_OBJ_FLAG_PRESS_LOCK = (1L << 13), /**< Keep the object pressed even if the press slid from the object*/ + LV_OBJ_FLAG_EVENT_BUBBLE = (1L << 14), /**< Propagate the events to the parent too*/ + LV_OBJ_FLAG_GESTURE_BUBBLE = (1L << 15), /**< Propagate the gestures to the parent*/ + LV_OBJ_FLAG_ADV_HITTEST = (1L << 16), /**< Allow performing more accurate hit (click) test. E.g. consider rounded corners.*/ + LV_OBJ_FLAG_IGNORE_LAYOUT = (1L << 17), /**< Make the object position-able by the layouts*/ + LV_OBJ_FLAG_FLOATING = (1L << 18), /**< Do not scroll the object when the parent scrolls and ignore layout*/ + LV_OBJ_FLAG_OVERFLOW_VISIBLE = (1L << 19), /**< Do not clip the children's content to the parent's boundary*/ + + LV_OBJ_FLAG_LAYOUT_1 = (1L << 23), /**< Custom flag, free to use by layouts*/ + LV_OBJ_FLAG_LAYOUT_2 = (1L << 24), /**< Custom flag, free to use by layouts*/ + + LV_OBJ_FLAG_WIDGET_1 = (1L << 25), /**< Custom flag, free to use by widget*/ + LV_OBJ_FLAG_WIDGET_2 = (1L << 26), /**< Custom flag, free to use by widget*/ + LV_OBJ_FLAG_USER_1 = (1L << 27), /**< Custom flag, free to use by user*/ + LV_OBJ_FLAG_USER_2 = (1L << 28), /**< Custom flag, free to use by user*/ + LV_OBJ_FLAG_USER_3 = (1L << 29), /**< Custom flag, free to use by user*/ + LV_OBJ_FLAG_USER_4 = (1L << 30), /**< Custom flag, free to use by user*/ + +}; + + +typedef uint32_t lv_obj_flag_t; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_obj_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_OBJ_DRAW_PART_RECTANGLE, /**< The main rectangle*/ + LV_OBJ_DRAW_PART_BORDER_POST,/**< The border if style_border_post = true*/ + LV_OBJ_DRAW_PART_SCROLLBAR, /**< The scrollbar*/ +} lv_obj_draw_part_type_t; + +#include "lv_obj_tree.h" +#include "lv_obj_pos.h" +#include "lv_obj_scroll.h" +#include "lv_obj_style.h" +#include "lv_obj_draw.h" +#include "lv_obj_class.h" +#include "lv_event.h" +#include "lv_group.h" + +/** + * Make the base object's class publicly available. + */ +extern const lv_obj_class_t lv_obj_class; + +/** + * Special, rarely used attributes. + * They are allocated automatically if any elements is set. + */ +typedef struct { + struct _lv_obj_t ** children; /**< Store the pointer of the children in an array.*/ + uint32_t child_cnt; /**< Number of children*/ + lv_group_t * group_p; + + struct _lv_event_dsc_t * event_dsc; /**< Dynamically allocated event callback and user data array*/ + lv_point_t scroll; /**< The current X/Y scroll offset*/ + + lv_coord_t ext_click_pad; /**< Extra click padding in all direction*/ + lv_coord_t ext_draw_size; /**< EXTend the size in every direction for drawing.*/ + + lv_scrollbar_mode_t scrollbar_mode : 2; /**< How to display scrollbars*/ + lv_scroll_snap_t scroll_snap_x : 2; /**< Where to align the snappable children horizontally*/ + lv_scroll_snap_t scroll_snap_y : 2; /**< Where to align the snappable children vertically*/ + lv_dir_t scroll_dir : 4; /**< The allowed scroll direction(s)*/ + uint8_t event_dsc_cnt : 6; /**< Number of event callbacks stored in `event_dsc` array*/ + uint8_t layer_type : 2; /**< Cache the layer type here. Element of @lv_intermediate_layer_type_t */ +} _lv_obj_spec_attr_t; + +typedef struct _lv_obj_t { + const lv_obj_class_t * class_p; + struct _lv_obj_t * parent; + _lv_obj_spec_attr_t * spec_attr; + _lv_obj_style_t * styles; +#if LV_USE_USER_DATA + void * user_data; +#endif + lv_area_t coords; + lv_obj_flag_t flags; + lv_state_t state; + uint16_t layout_inv : 1; + uint16_t scr_layout_inv : 1; + uint16_t skip_trans : 1; + uint16_t style_cnt : 6; + uint16_t h_layout : 1; + uint16_t w_layout : 1; +} lv_obj_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize LVGL library. + * Should be called before any other LVGL related function. + */ +void lv_init(void); + +#if LV_ENABLE_GC || !LV_MEM_CUSTOM + +/** + * Deinit the 'lv' library + * Currently only implemented when not using custom allocators, or GC is enabled. + */ +void lv_deinit(void); + +#endif + +/** + * Returns whether the 'lv' library is currently initialized + */ +bool lv_is_initialized(void); + +/** + * Create a base object (a rectangle) + * @param parent pointer to a parent object. If NULL then a screen will be created. + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent); + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set one or more flags + * @param obj pointer to an object + * @param f R-ed values from `lv_obj_flag_t` to set. + */ +void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f); + +/** + * Clear one or more flags + * @param obj pointer to an object + * @param f OR-ed values from `lv_obj_flag_t` to set. + */ +void lv_obj_clear_flag(lv_obj_t * obj, lv_obj_flag_t f); + + +/** + * Add one or more states to the object. The other state bits will remain unchanged. + * If specified in the styles, transition animation will be started from the previous state to the current. + * @param obj pointer to an object + * @param state the states to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED` + */ +void lv_obj_add_state(lv_obj_t * obj, lv_state_t state); + +/** + * Remove one or more states to the object. The other state bits will remain unchanged. + * If specified in the styles, transition animation will be started from the previous state to the current. + * @param obj pointer to an object + * @param state the states to add. E.g `LV_STATE_PRESSED | LV_STATE_FOCUSED` + */ +void lv_obj_clear_state(lv_obj_t * obj, lv_state_t state); + +/** + * Set the user_data field of the object + * @param obj pointer to an object + * @param user_data pointer to the new user_data. + */ +#if LV_USE_USER_DATA +static inline void lv_obj_set_user_data(lv_obj_t * obj, void * user_data) +{ + obj->user_data = user_data; +} +#endif + +/*======================= + * Getter functions + *======================*/ + +/** + * Check if a given flag or all the given flags are set on an object. + * @param obj pointer to an object + * @param f the flag(s) to check (OR-ed values can be used) + * @return true: all flags are set; false: not all flags are set + */ +bool lv_obj_has_flag(const lv_obj_t * obj, lv_obj_flag_t f); + +/** + * Check if a given flag or any of the flags are set on an object. + * @param obj pointer to an object + * @param f the flag(s) to check (OR-ed values can be used) + * @return true: at lest one flag flag is set; false: none of the flags are set + */ +bool lv_obj_has_flag_any(const lv_obj_t * obj, lv_obj_flag_t f); + +/** + * Get the state of an object + * @param obj pointer to an object + * @return the state (OR-ed values from `lv_state_t`) + */ +lv_state_t lv_obj_get_state(const lv_obj_t * obj); + +/** + * Check if the object is in a given state or not. + * @param obj pointer to an object + * @param state a state or combination of states to check + * @return true: `obj` is in `state`; false: `obj` is not in `state` + */ +bool lv_obj_has_state(const lv_obj_t * obj, lv_state_t state); + +/** + * Get the group of the object + * @param obj pointer to an object + * @return the pointer to group of the object + */ +void * lv_obj_get_group(const lv_obj_t * obj); + +/** + * Get the user_data field of the object + * @param obj pointer to an object + * @return the pointer to the user_data of the object + */ +#if LV_USE_USER_DATA +static inline void * lv_obj_get_user_data(lv_obj_t * obj) +{ + return obj->user_data; +} +#endif + +/*======================= + * Other functions + *======================*/ + +/** + * Allocate special data for an object if not allocated yet. + * @param obj pointer to an object + */ +void lv_obj_allocate_spec_attr(lv_obj_t * obj); + +/** + * Check the type of obj. + * @param obj pointer to an object + * @param class_p a class to check (e.g. `lv_slider_class`) + * @return true: `class_p` is the `obj` class. + */ +bool lv_obj_check_type(const lv_obj_t * obj, const lv_obj_class_t * class_p); + +/** + * Check if any object has a given class (type). + * It checks the ancestor classes too. + * @param obj pointer to an object + * @param class_p a class to check (e.g. `lv_slider_class`) + * @return true: `obj` has the given class + */ +bool lv_obj_has_class(const lv_obj_t * obj, const lv_obj_class_t * class_p); + +/** + * Get the class (type) of the object + * @param obj pointer to an object + * @return the class (type) of the object + */ +const lv_obj_class_t * lv_obj_get_class(const lv_obj_t * obj); + +/** + * Check if any object is still "alive". + * @param obj pointer to an object + * @return true: valid + */ +bool lv_obj_is_valid(const lv_obj_t * obj); + +/** + * Scale the given number of pixels (a distance or size) relative to a 160 DPI display + * considering the DPI of the `obj`'s display. + * It ensures that e.g. `lv_dpx(100)` will have the same physical size regardless to the + * DPI of the display. + * @param obj an object whose display's dpi should be considered + * @param n the number of pixels to scale + * @return `n x current_dpi/160` + */ +static inline lv_coord_t lv_obj_dpx(const lv_obj_t * obj, lv_coord_t n) +{ + return _LV_DPX_CALC(lv_disp_get_dpi(lv_obj_get_disp(obj)), n); +} + +/********************** + * MACROS + **********************/ + +#if LV_USE_ASSERT_OBJ +# define LV_ASSERT_OBJ(obj_p, obj_class) \ + do { \ + LV_ASSERT_MSG(obj_p != NULL, "The object is NULL"); \ + LV_ASSERT_MSG(lv_obj_has_class(obj_p, obj_class) == true, "Incompatible object type."); \ + LV_ASSERT_MSG(lv_obj_is_valid(obj_p) == true, "The object is invalid, deleted or corrupted?"); \ + } while(0) +# else +# define LV_ASSERT_OBJ(obj_p, obj_class) do{}while(0) +#endif + +#if LV_USE_LOG && LV_LOG_TRACE_OBJ_CREATE +# define LV_TRACE_OBJ_CREATE(...) LV_LOG_TRACE(__VA_ARGS__) +#else +# define LV_TRACE_OBJ_CREATE(...) +#endif + + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/include/liblvgl/core/lv_obj_class.h b/include/liblvgl/core/lv_obj_class.h new file mode 100644 index 0000000..01a7248 --- /dev/null +++ b/include/liblvgl/core/lv_obj_class.h @@ -0,0 +1,94 @@ +/** + * @file lv_obj_class.h + * + */ + +#ifndef LV_OBJ_CLASS_H +#define LV_OBJ_CLASS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include + +/********************* + * DEFINES + *********************/ + + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_obj_class_t; +struct _lv_event_t; + +typedef enum { + LV_OBJ_CLASS_EDITABLE_INHERIT, /**< Check the base class. Must have 0 value to let zero initialized class inherit*/ + LV_OBJ_CLASS_EDITABLE_TRUE, + LV_OBJ_CLASS_EDITABLE_FALSE, +} lv_obj_class_editable_t; + +typedef enum { + LV_OBJ_CLASS_GROUP_DEF_INHERIT, /**< Check the base class. Must have 0 value to let zero initialized class inherit*/ + LV_OBJ_CLASS_GROUP_DEF_TRUE, + LV_OBJ_CLASS_GROUP_DEF_FALSE, +} lv_obj_class_group_def_t; + +typedef void (*lv_obj_class_event_cb_t)(struct _lv_obj_class_t * class_p, struct _lv_event_t * e); +/** + * Describe the common methods of every object. + * Similar to a C++ class. + */ +typedef struct _lv_obj_class_t { + const struct _lv_obj_class_t * base_class; + void (*constructor_cb)(const struct _lv_obj_class_t * class_p, struct _lv_obj_t * obj); + void (*destructor_cb)(const struct _lv_obj_class_t * class_p, struct _lv_obj_t * obj); +#if LV_USE_USER_DATA + void * user_data; +#endif + void (*event_cb)(const struct _lv_obj_class_t * class_p, + struct _lv_event_t * e); /**< Widget type specific event function*/ + lv_coord_t width_def; + lv_coord_t height_def; + uint32_t editable : 2; /**< Value from ::lv_obj_class_editable_t*/ + uint32_t group_def : 2; /**< Value from ::lv_obj_class_group_def_t*/ + uint32_t instance_size : 16; +} lv_obj_class_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an object form a class descriptor + * @param class_p pointer to a class + * @param parent pointer to an object where the new object should be created + * @return pointer to the created object + */ +struct _lv_obj_t * lv_obj_class_create_obj(const struct _lv_obj_class_t * class_p, struct _lv_obj_t * parent); + +void lv_obj_class_init_obj(struct _lv_obj_t * obj); + +void _lv_obj_destruct(struct _lv_obj_t * obj); + +bool lv_obj_is_editable(struct _lv_obj_t * obj); + +bool lv_obj_is_group_def(struct _lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_CLASS_H*/ diff --git a/include/liblvgl/core/lv_obj_draw.h b/include/liblvgl/core/lv_obj_draw.h new file mode 100644 index 0000000..a107e55 --- /dev/null +++ b/include/liblvgl/core/lv_obj_draw.h @@ -0,0 +1,172 @@ +/** + * @file lv_obj_draw.h + * + */ + +#ifndef LV_OBJ_DRAW_H +#define LV_OBJ_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_obj_class_t; + +/** Cover check results.*/ +typedef enum { + LV_COVER_RES_COVER = 0, + LV_COVER_RES_NOT_COVER = 1, + LV_COVER_RES_MASKED = 2, +} lv_cover_res_t; + +typedef enum { + LV_LAYER_TYPE_NONE, + LV_LAYER_TYPE_SIMPLE, + LV_LAYER_TYPE_TRANSFORM, +} lv_layer_type_t; + +typedef struct { + lv_draw_ctx_t * draw_ctx; /**< Draw context*/ + const struct _lv_obj_class_t * class_p; /**< The class that sent the event */ + uint32_t type; /**< The type if part being draw. Element of `lv__draw_part_type_t` */ + lv_area_t * draw_area; /**< The area of the part being drawn*/ + lv_draw_rect_dsc_t * + rect_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for rectangle-like parts*/ + lv_draw_label_dsc_t * + label_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for text-like parts*/ + lv_draw_line_dsc_t * + line_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for line-like parts*/ + lv_draw_img_dsc_t * + img_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for image-like parts*/ + lv_draw_arc_dsc_t * + arc_dsc; /**< A draw descriptor that can be modified to changed what LVGL will draw. Set only for arc-like parts*/ + const lv_point_t * + p1; /**< A point calculated during drawing. E.g. a point of chart or the center of an arc.*/ + const lv_point_t * p2; /**< A point calculated during drawing. E.g. a point of chart.*/ + char * text; /**< A text calculated during drawing. Can be modified. E.g. tick labels on a chart axis.*/ + uint32_t text_length; /**< Size of the text buffer containing null-terminated text string calculated during drawing.*/ + uint32_t part; /**< The current part for which the event is sent*/ + uint32_t id; /**< The index of the part. E.g. a button's index on button matrix or table cell index.*/ + lv_coord_t radius; /**< E.g. the radius of an arc (not the corner radius).*/ + int32_t value; /**< A value calculated during drawing. E.g. Chart's tick line value.*/ + const void * sub_part_ptr; /**< A pointer the identifies something in the part. E.g. chart series. */ +} lv_obj_draw_part_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a rectangle draw descriptor from an object's styles in its current state + * @param obj pointer to an object + * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc + * @param draw_dsc the descriptor to initialize. + * If an `..._opa` field is set to `LV_OPA_TRANSP` the related properties won't be initialized. + * Should be initialized with `lv_draw_rect_dsc_init(draw_dsc)`. + * @note Only the relevant fields will be set. + * E.g. if `border width == 0` the other border properties won't be evaluated. + */ +void lv_obj_init_draw_rect_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_rect_dsc_t * draw_dsc); + +/** + * Initialize a label draw descriptor from an object's styles in its current state + * @param obj pointer to an object + * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc + * @param draw_dsc the descriptor to initialize. + * If the `opa` field is set to or the property is equal to `LV_OPA_TRANSP` the rest won't be initialized. + * Should be initialized with `lv_draw_label_dsc_init(draw_dsc)`. + */ +void lv_obj_init_draw_label_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_label_dsc_t * draw_dsc); + +/** + * Initialize an image draw descriptor from an object's styles in its current state + * @param obj pointer to an object + * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc + * @param draw_dsc the descriptor to initialize. + * Should be initialized with `lv_draw_image_dsc_init(draw_dsc)`. + */ +void lv_obj_init_draw_img_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_img_dsc_t * draw_dsc); + + +/** + * Initialize a line draw descriptor from an object's styles in its current state + * @param obj pointer to an object + * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc + * @param draw_dsc the descriptor to initialize. + * Should be initialized with `lv_draw_line_dsc_init(draw_dsc)`. + */ +void lv_obj_init_draw_line_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_line_dsc_t * draw_dsc); + +/** + * Initialize an arc draw descriptor from an object's styles in its current state + * @param obj pointer to an object + * @param part part of the object, e.g. `LV_PART_MAIN`, `LV_PART_SCROLLBAR`, `LV_PART_KNOB`, etc + * @param draw_dsc the descriptor to initialize. + * Should be initialized with `lv_draw_arc_dsc_init(draw_dsc)`. + */ +void lv_obj_init_draw_arc_dsc(struct _lv_obj_t * obj, uint32_t part, lv_draw_arc_dsc_t * draw_dsc); + +/** + * Get the required extra size (around the object's part) to draw shadow, outline, value etc. + * @param obj pointer to an object + * @param part part of the object + * @return the extra size required around the object + */ +lv_coord_t lv_obj_calculate_ext_draw_size(struct _lv_obj_t * obj, uint32_t part); + +/** + * Initialize a draw descriptor used in events. + * @param dsc pointer to a descriptor. Later it should be passed as parameter to an `LV_EVENT_DRAW_PART_BEGIN/END` event. + * @param draw the current draw context. (usually returned by `lv_event_get_draw_ctx(e)`) + */ +void lv_obj_draw_dsc_init(lv_obj_draw_part_dsc_t * dsc, lv_draw_ctx_t * draw_ctx); + +/** + * Check the type obj a part draw descriptor + * @param dsc the descriptor (normally the event parameter) + * @param class_p pointer to class to which `type` is related + * @param type element of `lv__draw_part_type_t` + * @return true if ::dsc is related to ::class_p and ::type + */ +bool lv_obj_draw_part_check_type(lv_obj_draw_part_dsc_t * dsc, const struct _lv_obj_class_t * class_p, uint32_t type); + +/** + * Send a 'LV_EVENT_REFR_EXT_DRAW_SIZE' Call the ancestor's event handler to the object to refresh the value of the extended draw size. + * The result will be saved in `obj`. + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_draw_size(struct _lv_obj_t * obj); + +/** + * Get the extended draw area of an object. + * @param obj pointer to an object + * @return the size extended draw area around the real coordinates + */ +lv_coord_t _lv_obj_get_ext_draw_size(const struct _lv_obj_t * obj); + + +lv_layer_type_t _lv_obj_get_layer_type(const struct _lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_DRAW_H*/ diff --git a/include/liblvgl/core/lv_obj_pos.h b/include/liblvgl/core/lv_obj_pos.h new file mode 100644 index 0000000..fdc6476 --- /dev/null +++ b/include/liblvgl/core/lv_obj_pos.h @@ -0,0 +1,449 @@ +/** + * @file lv_obj_pos.h + * + */ + +#ifndef LV_OBJ_POS_H +#define LV_OBJ_POS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_obj_t; + +typedef void (*lv_layout_update_cb_t)(struct _lv_obj_t *, void * user_data); +typedef struct { + lv_layout_update_cb_t cb; + void * user_data; +} lv_layout_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set the position of an object relative to the set alignment. + * @param obj pointer to an object + * @param x new x coordinate + * @param y new y coordinate + * @note With default alignment it's the distance from the top left corner + * @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent + * @note The position is interpreted on the content area of the parent + * @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)` + */ +void lv_obj_set_pos(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of an object + * @param obj pointer to an object + * @param x new x coordinate + * @note With default alignment it's the distance from the top left corner + * @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent + * @note The position is interpreted on the content area of the parent + * @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)` + */ +void lv_obj_set_x(struct _lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of an object + * @param obj pointer to an object + * @param y new y coordinate + * @note With default alignment it's the distance from the top left corner + * @note E.g. LV_ALIGN_CENTER alignment it's the offset from the center of the parent + * @note The position is interpreted on the content area of the parent + * @note The values can be set in pixel or in percentage of parent size with `lv_pct(v)` + */ +void lv_obj_set_y(struct _lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object. + * @param obj pointer to an object + * @param w the new width + * @param h the new height + * @note possible values are: + * pixel simple set the size accordingly + * LV_SIZE_CONTENT set the size to involve all children in the given direction + * LV_SIZE_PCT(x) to set size in percentage of the parent's content area size (the size without paddings). + * x should be in [0..1000]% range + */ +void lv_obj_set_size(struct _lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Recalculate the size of the object + * @param obj pointer to an object + * @return true: the size has been changed + */ +bool lv_obj_refr_size(struct _lv_obj_t * obj); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w the new width + * @note possible values are: + * pixel simple set the size accordingly + * LV_SIZE_CONTENT set the size to involve all children in the given direction + * lv_pct(x) to set size in percentage of the parent's content area size (the size without paddings). + * x should be in [0..1000]% range + */ +void lv_obj_set_width(struct _lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h the new height + * @note possible values are: + * pixel simple set the size accordingly + * LV_SIZE_CONTENT set the size to involve all children in the given direction + * lv_pct(x) to set size in percentage of the parent's content area size (the size without paddings). + * x should be in [0..1000]% range + */ +void lv_obj_set_height(struct _lv_obj_t * obj, lv_coord_t h); + +/** + * Set the width reduced by the left and right padding and the border width. + * @param obj pointer to an object + * @param w the width without paddings in pixels + */ +void lv_obj_set_content_width(struct _lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height reduced by the top and bottom padding and the border width. + * @param obj pointer to an object + * @param h the height without paddings in pixels + */ +void lv_obj_set_content_height(struct _lv_obj_t * obj, lv_coord_t h); + +/** + * Set a layout for an object + * @param obj pointer to an object + * @param layout pointer to a layout descriptor to set + */ +void lv_obj_set_layout(struct _lv_obj_t * obj, uint32_t layout); + +/** + * Test whether the and object is positioned by a layout or not + * @param obj pointer to an object to test + * @return true: positioned by a layout; false: not positioned by a layout + */ +bool lv_obj_is_layout_positioned(const struct _lv_obj_t * obj); + +/** + * Mark the object for layout update. + * @param obj pointer to an object whose children needs to be updated + */ +void lv_obj_mark_layout_as_dirty(struct _lv_obj_t * obj); + +/** + * Update the layout of an object. + * @param obj pointer to an object whose children needs to be updated + */ +void lv_obj_update_layout(const struct _lv_obj_t * obj); + +/** + * Register a new layout + * @param cb the layout update callback + * @param user_data custom data that will be passed to `cb` + * @return the ID of the new layout + */ +uint32_t lv_layout_register(lv_layout_update_cb_t cb, void * user_data); + +/** + * Change the alignment of an object. + * @param obj pointer to an object to align + * @param align type of alignment (see 'lv_align_t' enum) `LV_ALIGN_OUT_...` can't be used. + */ +void lv_obj_set_align(struct _lv_obj_t * obj, lv_align_t align); + +/** + * Change the alignment of an object and set new coordinates. + * Equivalent to: + * lv_obj_set_align(obj, align); + * lv_obj_set_pos(obj, x_ofs, y_ofs); + * @param obj pointer to an object to align + * @param align type of alignment (see 'lv_align_t' enum) `LV_ALIGN_OUT_...` can't be used. + * @param x_ofs x coordinate offset after alignment + * @param y_ofs y coordinate offset after alignment + */ +void lv_obj_align(struct _lv_obj_t * obj, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an other object (if NULL `obj`s parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_ofs x coordinate offset after alignment + * @param y_ofs y coordinate offset after alignment + * @note if the position or size of `base` changes `obj` needs to be aligned manually again + */ +void lv_obj_align_to(struct _lv_obj_t * obj, const struct _lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, + lv_coord_t y_ofs); + +/** + * Align an object to the center on its parent. + * @param obj pointer to an object to align + * @note if the parent size changes `obj` needs to be aligned manually again + */ +static inline void lv_obj_center(struct _lv_obj_t * obj) +{ + lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0); +} + + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param coords pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const struct _lv_obj_t * obj, lv_area_t * coords); + +/** + * Get the x coordinate of object. + * @param obj pointer to an object + * @return distance of `obj` from the left side of its parent plus the parent's left padding + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @note Zero return value means the object is on the left padding of the parent, and not on the left edge. + * @note Scrolling of the parent doesn't change the returned value. + * @note The returned value is always the distance from the parent even if `obj` is positioned by a layout. + */ +lv_coord_t lv_obj_get_x(const struct _lv_obj_t * obj); + +/** + * Get the x2 coordinate of object. + * @param obj pointer to an object + * @return distance of `obj` from the right side of its parent plus the parent's right padding + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @note Zero return value means the object is on the right padding of the parent, and not on the right edge. + * @note Scrolling of the parent doesn't change the returned value. + * @note The returned value is always the distance from the parent even if `obj` is positioned by a layout. + */ +lv_coord_t lv_obj_get_x2(const struct _lv_obj_t * obj); + +/** + * Get the y coordinate of object. + * @param obj pointer to an object + * @return distance of `obj` from the top side of its parent plus the parent's top padding + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @note Zero return value means the object is on the top padding of the parent, and not on the top edge. + * @note Scrolling of the parent doesn't change the returned value. + * @note The returned value is always the distance from the parent even if `obj` is positioned by a layout. + */ +lv_coord_t lv_obj_get_y(const struct _lv_obj_t * obj); + +/** + * Get the y2 coordinate of object. + * @param obj pointer to an object + * @return distance of `obj` from the bottom side of its parent plus the parent's bottom padding + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @note Zero return value means the object is on the bottom padding of the parent, and not on the bottom edge. + * @note Scrolling of the parent doesn't change the returned value. + * @note The returned value is always the distance from the parent even if `obj` is positioned by a layout. + */ +lv_coord_t lv_obj_get_y2(const struct _lv_obj_t * obj); + +/** + * Get the actually set x coordinate of object, i.e. the offset form the set alignment + * @param obj pointer to an object + * @return the set x coordinate + */ +lv_coord_t lv_obj_get_x_aligned(const struct _lv_obj_t * obj); + +/** + * Get the actually set y coordinate of object, i.e. the offset form the set alignment + * @param obj pointer to an object + * @return the set y coordinate + */ +lv_coord_t lv_obj_get_y_aligned(const struct _lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @return the width in pixels + */ +lv_coord_t lv_obj_get_width(const struct _lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @return the height in pixels + */ +lv_coord_t lv_obj_get_height(const struct _lv_obj_t * obj); + +/** + * Get the width reduced by the left and right padding and the border width. + * @param obj pointer to an object + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @return the width which still fits into its parent without causing overflow (making the parent scrollable) + */ +lv_coord_t lv_obj_get_content_width(const struct _lv_obj_t * obj); + +/** + * Get the height reduced by the top and bottom padding and the border width. + * @param obj pointer to an object + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @return the height which still fits into the parent without causing overflow (making the parent scrollable) + */ +lv_coord_t lv_obj_get_content_height(const struct _lv_obj_t * obj); + +/** + * Get the area reduced by the paddings and the border width. + * @param obj pointer to an object + * @note The position of the object is recalculated only on the next redraw. To force coordinate recalculation + * call `lv_obj_update_layout(obj)`. + * @param area the area which still fits into the parent without causing overflow (making the parent scrollable) + */ +void lv_obj_get_content_coords(const struct _lv_obj_t * obj, lv_area_t * area); + +/** + * Get the width occupied by the "parts" of the widget. E.g. the width of all columns of a table. + * @param obj pointer to an objects + * @return the width of the virtually drawn content + * @note This size independent from the real size of the widget. + * It just tells how large the internal ("virtual") content is. + */ +lv_coord_t lv_obj_get_self_width(const struct _lv_obj_t * obj); + +/** + * Get the height occupied by the "parts" of the widget. E.g. the height of all rows of a table. + * @param obj pointer to an objects + * @return the width of the virtually drawn content + * @note This size independent from the real size of the widget. + * It just tells how large the internal ("virtual") content is. + */ +lv_coord_t lv_obj_get_self_height(const struct _lv_obj_t * obj); + +/** + * Handle if the size of the internal ("virtual") content of an object has changed. + * @param obj pointer to an object + * @return false: nothing happened; true: refresh happened + */ +bool lv_obj_refresh_self_size(struct _lv_obj_t * obj); + +void lv_obj_refr_pos(struct _lv_obj_t * obj); + +void lv_obj_move_to(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + + +void lv_obj_move_children_by(struct _lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff, bool ignore_floating); + +/** + * Transform a point using the angle and zoom style properties of an object + * @param obj pointer to an object whose style properties should be used + * @param p a point to transform, the result will be written back here too + * @param recursive consider the transformation properties of the parents too + * @param inv do the inverse of the transformation (-angle and 1/zoom) + */ +void lv_obj_transform_point(const struct _lv_obj_t * obj, lv_point_t * p, bool recursive, bool inv); + +/** + * Transform an area using the angle and zoom style properties of an object + * @param obj pointer to an object whose style properties should be used + * @param area an area to transform, the result will be written back here too + * @param recursive consider the transformation properties of the parents too + * @param inv do the inverse of the transformation (-angle and 1/zoom) + */ +void lv_obj_get_transformed_area(const struct _lv_obj_t * obj, lv_area_t * area, bool recursive, bool inv); + +/** + * Mark an area of an object as invalid. + * The area will be truncated to the object's area and marked for redraw. + * @param obj pointer to an object + * @param area the area to redraw + */ +void lv_obj_invalidate_area(const struct _lv_obj_t * obj, const lv_area_t * area); + +/** + * Mark the object as invalid to redrawn its area + * @param obj pointer to an object + */ +void lv_obj_invalidate(const struct _lv_obj_t * obj); + +/** + * Tell whether an area of an object is visible (even partially) now or not + * @param obj pointer to an object + * @param area the are to check. The visible part of the area will be written back here. + * @return true visible; false not visible (hidden, out of parent, on other screen, etc) + */ +bool lv_obj_area_is_visible(const struct _lv_obj_t * obj, lv_area_t * area); + +/** + * Tell whether an object is visible (even partially) now or not + * @param obj pointer to an object + * @return true: visible; false not visible (hidden, out of parent, on other screen, etc) + */ +bool lv_obj_is_visible(const struct _lv_obj_t * obj); + +/** + * Set the size of an extended clickable area + * @param obj pointer to an object + * @param size extended clickable area in all 4 directions [px] + */ +void lv_obj_set_ext_click_area(struct _lv_obj_t * obj, lv_coord_t size); + +/** + * Get the an area where to object can be clicked. + * It's the object's normal area plus the extended click area. + * @param obj pointer to an object + * @param area store the result area here + */ +void lv_obj_get_click_area(const struct _lv_obj_t * obj, lv_area_t * area); + +/** + * Hit-test an object given a particular point in screen space. + * @param obj object to hit-test + * @param point screen-space point (absolute coordinate) + * @return true: if the object is considered under the point + */ +bool lv_obj_hit_test(struct _lv_obj_t * obj, const lv_point_t * point); + +/** + * Clamp a width between min and max width. If the min/max width is in percentage value use the ref_width + * @param width width to clamp + * @param min_width the minimal width + * @param max_width the maximal width + * @param ref_width the reference width used when min/max width is in percentage + * @return the clamped width + */ +lv_coord_t lv_clamp_width(lv_coord_t width, lv_coord_t min_width, lv_coord_t max_width, lv_coord_t ref_width); + +/** + * Clamp a height between min and max height. If the min/max height is in percentage value use the ref_height + * @param height height to clamp + * @param min_height the minimal height + * @param max_height the maximal height + * @param ref_height the reference height used when min/max height is in percentage + * @return the clamped height + */ +lv_coord_t lv_clamp_height(lv_coord_t height, lv_coord_t min_height, lv_coord_t max_height, lv_coord_t ref_height); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_POS_H*/ diff --git a/include/liblvgl/core/lv_obj_scroll.h b/include/liblvgl/core/lv_obj_scroll.h new file mode 100644 index 0000000..3717dec --- /dev/null +++ b/include/liblvgl/core/lv_obj_scroll.h @@ -0,0 +1,307 @@ +/** + * @file lv_obj_scroll.h + * + */ + +#ifndef LV_OBJ_SCROLL_H +#define LV_OBJ_SCROLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_anim.h" +#include "liblvgl/misc/lv_types.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Can't include lv_obj.h because it includes this header file*/ +struct _lv_obj_t; + +/** Scrollbar modes: shows when should the scrollbars be visible*/ +enum { + LV_SCROLLBAR_MODE_OFF, /**< Never show scrollbars*/ + LV_SCROLLBAR_MODE_ON, /**< Always show scrollbars*/ + LV_SCROLLBAR_MODE_ACTIVE, /**< Show scroll bars when object is being scrolled*/ + LV_SCROLLBAR_MODE_AUTO, /**< Show scroll bars when the content is large enough to be scrolled*/ +}; +typedef uint8_t lv_scrollbar_mode_t; + + +/** Scroll span align options. Tells where to align the snappable children when scroll stops.*/ +enum { + LV_SCROLL_SNAP_NONE, /**< Do not align, leave where it is*/ + LV_SCROLL_SNAP_START, /**< Align to the left/top*/ + LV_SCROLL_SNAP_END, /**< Align to the right/bottom*/ + LV_SCROLL_SNAP_CENTER /**< Align to the center*/ +}; +typedef uint8_t lv_scroll_snap_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set how the scrollbars should behave. + * @param obj pointer to an object + * @param mode LV_SCROLL_MODE_ON/OFF/AUTO/ACTIVE + */ +void lv_obj_set_scrollbar_mode(struct _lv_obj_t * obj, lv_scrollbar_mode_t mode); + +/** + * Set the object in which directions can be scrolled + * @param obj pointer to an object + * @param dir the allow scroll directions. An element or OR-ed values of `lv_dir_t` + */ +void lv_obj_set_scroll_dir(struct _lv_obj_t * obj, lv_dir_t dir); + +/** + * Set where to snap the children when scrolling ends horizontally + * @param obj pointer to an object + * @param align the snap align to set from `lv_scroll_snap_t` + */ +void lv_obj_set_scroll_snap_x(struct _lv_obj_t * obj, lv_scroll_snap_t align); + +/** + * Set where to snap the children when scrolling ends vertically + * @param obj pointer to an object + * @param align the snap align to set from `lv_scroll_snap_t` + */ +void lv_obj_set_scroll_snap_y(struct _lv_obj_t * obj, lv_scroll_snap_t align); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current scroll mode (when to hide the scrollbars) + * @param obj pointer to an object + * @return the current scroll mode from `lv_scrollbar_mode_t` + */ +lv_scrollbar_mode_t lv_obj_get_scrollbar_mode(const struct _lv_obj_t * obj); + +/** + * Get the object in which directions can be scrolled + * @param obj pointer to an object + * @param dir the allow scroll directions. An element or OR-ed values of `lv_dir_t` + */ +lv_dir_t lv_obj_get_scroll_dir(const struct _lv_obj_t * obj); + +/** + * Get where to snap the children when scrolling ends horizontally + * @param obj pointer to an object + * @return the current snap align from `lv_scroll_snap_t` + */ +lv_scroll_snap_t lv_obj_get_scroll_snap_x(const struct _lv_obj_t * obj); + +/** + * Get where to snap the children when scrolling ends vertically + * @param obj pointer to an object + * @return the current snap align from `lv_scroll_snap_t` + */ +lv_scroll_snap_t lv_obj_get_scroll_snap_y(const struct _lv_obj_t * obj); + +/** + * Get current X scroll position. + * @param obj pointer to an object + * @return the current scroll position from the left edge. + * If the object is not scrolled return 0 + * If scrolled return > 0 + * If scrolled in (elastic scroll) return < 0 + */ +lv_coord_t lv_obj_get_scroll_x(const struct _lv_obj_t * obj); + +/** + * Get current Y scroll position. + * @param obj pointer to an object + * @return the current scroll position from the top edge. + * If the object is not scrolled return 0 + * If scrolled return > 0 + * If scrolled inside return < 0 + */ +lv_coord_t lv_obj_get_scroll_y(const struct _lv_obj_t * obj); + +/** + * Return the height of the area above the object. + * That is the number of pixels the object can be scrolled down. + * Normally positive but can be negative when scrolled inside. + * @param obj pointer to an object + * @return the scrollable area above the object in pixels + */ +lv_coord_t lv_obj_get_scroll_top(struct _lv_obj_t * obj); + +/** + * Return the height of the area below the object. + * That is the number of pixels the object can be scrolled down. + * Normally positive but can be negative when scrolled inside. + * @param obj pointer to an object + * @return the scrollable area below the object in pixels + */ +lv_coord_t lv_obj_get_scroll_bottom(struct _lv_obj_t * obj); + +/** + * Return the width of the area on the left the object. + * That is the number of pixels the object can be scrolled down. + * Normally positive but can be negative when scrolled inside. + * @param obj pointer to an object + * @return the scrollable area on the left the object in pixels + */ +lv_coord_t lv_obj_get_scroll_left(struct _lv_obj_t * obj); + +/** + * Return the width of the area on the right the object. + * That is the number of pixels the object can be scrolled down. + * Normally positive but can be negative when scrolled inside. + * @param obj pointer to an object + * @return the scrollable area on the right the object in pixels + */ +lv_coord_t lv_obj_get_scroll_right(struct _lv_obj_t * obj); + +/** + * Get the X and Y coordinates where the scrolling will end for this object if a scrolling animation is in progress. + * If no scrolling animation, give the current `x` or `y` scroll position. + * @param obj pointer to an object + * @param end pointer to store the result + */ +void lv_obj_get_scroll_end(struct _lv_obj_t * obj, lv_point_t * end); + +/*===================== + * Other functions + *====================*/ + +/** + * Scroll by a given amount of pixels + * @param obj pointer to an object to scroll + * @param dx pixels to scroll horizontally + * @param dy pixels to scroll vertically + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + * @note > 0 value means scroll right/bottom (show the more content on the right/bottom) + * @note e.g. dy = -20 means scroll down 20 px + */ +void lv_obj_scroll_by(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_anim_enable_t anim_en); + +/** + * Scroll by a given amount of pixels. + * `dx` and `dy` will be limited internally to allow scrolling only on the content area. + * @param obj pointer to an object to scroll + * @param dx pixels to scroll horizontally + * @param dy pixels to scroll vertically + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + * @note e.g. dy = -20 means scroll down 20 px + */ +void lv_obj_scroll_by_bounded(struct _lv_obj_t * obj, lv_coord_t dx, lv_coord_t dy, lv_anim_enable_t anim_en); + +/** + * Scroll to a given coordinate on an object. + * `x` and `y` will be limited internally to allow scrolling only on the content area. + * @param obj pointer to an object to scroll + * @param x pixels to scroll horizontally + * @param y pixels to scroll vertically + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + */ +void lv_obj_scroll_to(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y, lv_anim_enable_t anim_en); + +/** + * Scroll to a given X coordinate on an object. + * `x` will be limited internally to allow scrolling only on the content area. + * @param obj pointer to an object to scroll + * @param x pixels to scroll horizontally + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + */ +void lv_obj_scroll_to_x(struct _lv_obj_t * obj, lv_coord_t x, lv_anim_enable_t anim_en); + +/** + * Scroll to a given Y coordinate on an object + * `y` will be limited internally to allow scrolling only on the content area. + * @param obj pointer to an object to scroll + * @param y pixels to scroll vertically + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + */ +void lv_obj_scroll_to_y(struct _lv_obj_t * obj, lv_coord_t y, lv_anim_enable_t anim_en); + +/** + * Scroll to an object until it becomes visible on its parent + * @param obj pointer to an object to scroll into view + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + */ +void lv_obj_scroll_to_view(struct _lv_obj_t * obj, lv_anim_enable_t anim_en); + +/** + * Scroll to an object until it becomes visible on its parent. + * Do the same on the parent's parent, and so on. + * Therefore the object will be scrolled into view even it has nested scrollable parents + * @param obj pointer to an object to scroll into view + * @param anim_en LV_ANIM_ON: scroll with animation; LV_ANIM_OFF: scroll immediately + */ +void lv_obj_scroll_to_view_recursive(struct _lv_obj_t * obj, lv_anim_enable_t anim_en); + + +/** + * Low level function to scroll by given x and y coordinates. + * `LV_EVENT_SCROLL` is sent. + * @param obj pointer to an object to scroll + * @param x pixels to scroll horizontally + * @param y pixels to scroll vertically + * @return `LV_RES_INV`: to object was deleted in `LV_EVENT_SCROLL`; + * `LV_RES_OK`: if the object is still valid + */ +lv_res_t _lv_obj_scroll_by_raw(struct _lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Tell whether an object is being scrolled or not at this moment + * @param obj pointer to an object + * @return true: `obj` is being scrolled + */ +bool lv_obj_is_scrolling(const struct _lv_obj_t * obj); + +/** + * Check the children of `obj` and scroll `obj` to fulfill the scroll_snap settings + * @param obj an object whose children needs to checked and snapped + * @param anim_en LV_ANIM_ON/OFF + */ +void lv_obj_update_snap(struct _lv_obj_t * obj, lv_anim_enable_t anim_en); + +/** + * Get the area of the scrollbars + * @param obj pointer to an object + * @param hor pointer to store the area of the horizontal scrollbar + * @param ver pointer to store the area of the vertical scrollbar + */ +void lv_obj_get_scrollbar_area(struct _lv_obj_t * obj, lv_area_t * hor, lv_area_t * ver); + +/** + * Invalidate the area of the scrollbars + * @param obj pointer to an object + */ +void lv_obj_scrollbar_invalidate(struct _lv_obj_t * obj); + +/** + * Checked if the content is scrolled "in" and adjusts it to a normal position. + * @param obj pointer to an object + * @param anim_en LV_ANIM_ON/OFF + */ +void lv_obj_readjust_scroll(struct _lv_obj_t * obj, lv_anim_enable_t anim_en); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_SCROLL_H*/ diff --git a/include/liblvgl/core/lv_obj_style.h b/include/liblvgl/core/lv_obj_style.h new file mode 100644 index 0000000..18e530a --- /dev/null +++ b/include/liblvgl/core/lv_obj_style.h @@ -0,0 +1,248 @@ +/** + * @file lv_obj_style.h + * + */ + +#ifndef LV_OBJ_STYLE_H +#define LV_OBJ_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "liblvgl/misc/lv_bidi.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Can't include lv_obj.h because it includes this header file*/ +struct _lv_obj_t; + +typedef enum { + _LV_STYLE_STATE_CMP_SAME, /*The style properties in the 2 states are identical*/ + _LV_STYLE_STATE_CMP_DIFF_REDRAW, /*The differences can be shown with a simple redraw*/ + _LV_STYLE_STATE_CMP_DIFF_DRAW_PAD, /*The differences can be shown with a simple redraw*/ + _LV_STYLE_STATE_CMP_DIFF_LAYOUT, /*The differences can be shown with a simple redraw*/ +} _lv_style_state_cmp_t; + +typedef uint32_t lv_style_selector_t; + +typedef struct { + lv_style_t * style; + uint32_t selector : 24; + uint32_t is_local : 1; + uint32_t is_trans : 1; +} _lv_obj_style_t; + +typedef struct { + uint16_t time; + uint16_t delay; + lv_style_selector_t selector; + lv_style_prop_t prop; + lv_anim_path_cb_t path_cb; +#if LV_USE_USER_DATA + void * user_data; +#endif +} _lv_obj_style_transition_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the object related style manager module. + * Called by LVGL in `lv_init()` + */ +void _lv_obj_style_init(void); + +/** + * Add a style to an object. + * @param obj pointer to an object + * @param style pointer to a style to add + * @param selector OR-ed value of parts and state to which the style should be added + * @example lv_obj_add_style(btn, &style_btn, 0); //Default button style + * @example lv_obj_add_style(btn, &btn_red, LV_STATE_PRESSED); //Overwrite only some colors to red when pressed + */ +void lv_obj_add_style(struct _lv_obj_t * obj, lv_style_t * style, lv_style_selector_t selector); + +/** + * Add a style to an object. + * @param obj pointer to an object + * @param style pointer to a style to remove. Can be NULL to check only the selector + * @param selector OR-ed values of states and a part to remove only styles with matching selectors. LV_STATE_ANY and LV_PART_ANY can be used + * @example lv_obj_remove_style(obj, &style, LV_PART_ANY | LV_STATE_ANY); //Remove a specific style + * @example lv_obj_remove_style(obj, NULL, LV_PART_MAIN | LV_STATE_ANY); //Remove all styles from the main part + * @example lv_obj_remove_style(obj, NULL, LV_PART_ANY | LV_STATE_ANY); //Remove all styles + */ +void lv_obj_remove_style(struct _lv_obj_t * obj, lv_style_t * style, lv_style_selector_t selector); + +/** + * Remove all styles from an object + * @param obj pointer to an object + */ +static inline void lv_obj_remove_style_all(struct _lv_obj_t * obj) +{ + lv_obj_remove_style(obj, NULL, LV_PART_ANY | LV_STATE_ANY); +} + +/** + * Notify all object if a style is modified + * @param style pointer to a style. Only the objects with this style will be notified + * (NULL to notify all objects) + */ +void lv_obj_report_style_change(lv_style_t * style); + +/** + * Notify an object and its children about its style is modified. + * @param obj pointer to an object + * @param part the part whose style was changed. E.g. `LV_PART_ANY`, `LV_PART_MAIN` + * @param prop `LV_STYLE_PROP_ANY` or an `LV_STYLE_...` property. + * It is used to optimize what needs to be refreshed. + * `LV_STYLE_PROP_INV` to perform only a style cache update + */ +void lv_obj_refresh_style(struct _lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop); + +/** + * Enable or disable automatic style refreshing when a new style is added/removed to/from an object + * or any other style change happens. + * @param en true: enable refreshing; false: disable refreshing + */ +void lv_obj_enable_style_refresh(bool en); + +/** + * Get the value of a style property. The current state of the object will be considered. + * Inherited properties will be inherited. + * If a property is not set a default value will be returned. + * @param obj pointer to an object + * @param part a part from which the property should be get + * @param prop the property to get + * @return the value of the property. + * Should be read from the correct field of the `lv_style_value_t` according to the type of the property. + */ +lv_style_value_t lv_obj_get_style_prop(const struct _lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop); + +/** + * Set local style property on an object's part and state. + * @param obj pointer to an object + * @param prop the property + * @param value value of the property. The correct element should be set according to the type of the property + * @param selector OR-ed value of parts and state for which the style should be set + */ +void lv_obj_set_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t value, + lv_style_selector_t selector); + +void lv_obj_set_local_style_prop_meta(struct _lv_obj_t * obj, lv_style_prop_t prop, uint16_t meta, + lv_style_selector_t selector); + +lv_style_res_t lv_obj_get_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_value_t * value, + lv_style_selector_t selector); + +/** + * Remove a local style property from a part of an object with a given state. + * @param obj pointer to an object + * @param prop a style property to remove. + * @param selector OR-ed value of parts and state for which the style should be removed + * @return true the property was found and removed; false: the property was not found + */ +bool lv_obj_remove_local_style_prop(struct _lv_obj_t * obj, lv_style_prop_t prop, lv_style_selector_t selector); + +/** + * Used internally for color filtering + */ +lv_style_value_t _lv_obj_style_apply_color_filter(const struct _lv_obj_t * obj, uint32_t part, lv_style_value_t v); + +/** + * Used internally to create a style transition + * @param obj + * @param part + * @param prev_state + * @param new_state + * @param tr + */ +void _lv_obj_style_create_transition(struct _lv_obj_t * obj, lv_part_t part, lv_state_t prev_state, + lv_state_t new_state, const _lv_obj_style_transition_dsc_t * tr); + +/** + * Used internally to compare the appearance of an object in 2 states + * @param obj + * @param state1 + * @param state2 + * @return + */ +_lv_style_state_cmp_t _lv_obj_style_state_compare(struct _lv_obj_t * obj, lv_state_t state1, lv_state_t state2); + +/** + * Fade in an an object and all its children. + * @param obj the object to fade in + * @param time time of fade + * @param delay delay to start the animation + */ +void lv_obj_fade_in(struct _lv_obj_t * obj, uint32_t time, uint32_t delay); + +/** + * Fade out an an object and all its children. + * @param obj the object to fade out + * @param time time of fade + * @param delay delay to start the animation + */ +void lv_obj_fade_out(struct _lv_obj_t * obj, uint32_t time, uint32_t delay); + +lv_state_t lv_obj_style_get_selector_state(lv_style_selector_t selector); + +lv_part_t lv_obj_style_get_selector_part(lv_style_selector_t selector); + +#include "lv_obj_style_gen.h" + +static inline void lv_obj_set_style_pad_all(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector) +{ + lv_obj_set_style_pad_left(obj, value, selector); + lv_obj_set_style_pad_right(obj, value, selector); + lv_obj_set_style_pad_top(obj, value, selector); + lv_obj_set_style_pad_bottom(obj, value, selector); +} + +static inline void lv_obj_set_style_pad_hor(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector) +{ + lv_obj_set_style_pad_left(obj, value, selector); + lv_obj_set_style_pad_right(obj, value, selector); +} + +static inline void lv_obj_set_style_pad_ver(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector) +{ + lv_obj_set_style_pad_top(obj, value, selector); + lv_obj_set_style_pad_bottom(obj, value, selector); +} + +static inline void lv_obj_set_style_pad_gap(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector) +{ + lv_obj_set_style_pad_row(obj, value, selector); + lv_obj_set_style_pad_column(obj, value, selector); +} + +static inline void lv_obj_set_style_size(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector) +{ + lv_obj_set_style_width(obj, value, selector); + lv_obj_set_style_height(obj, value, selector); +} + +lv_text_align_t lv_obj_calculate_style_text_align(const struct _lv_obj_t * obj, lv_part_t part, const char * txt); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_STYLE_H*/ diff --git a/include/liblvgl/core/lv_obj_style_gen.h b/include/liblvgl/core/lv_obj_style_gen.h new file mode 100644 index 0000000..576927d --- /dev/null +++ b/include/liblvgl/core/lv_obj_style_gen.h @@ -0,0 +1,648 @@ +static inline lv_coord_t lv_obj_get_style_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_min_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MIN_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_max_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MAX_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_height(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_HEIGHT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_min_height(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MIN_HEIGHT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_max_height(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_MAX_HEIGHT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_x(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_X); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_y(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_Y); + return (lv_coord_t)v.num; +} + +static inline lv_align_t lv_obj_get_style_align(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ALIGN); + return (lv_align_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_height(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_HEIGHT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_translate_x(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSLATE_X); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_translate_y(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSLATE_Y); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_zoom(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_ZOOM); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_angle(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_ANGLE); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_pivot_x(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_X); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_transform_pivot_y(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSFORM_PIVOT_Y); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_top(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_TOP); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_bottom(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_BOTTOM); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_left(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_LEFT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_right(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_RIGHT); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_row(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_ROW); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_pad_column(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_PAD_COLUMN); + return (lv_coord_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_bg_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_bg_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_bg_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_bg_grad_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_bg_grad_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_COLOR)); + return v.color; +} + +static inline lv_grad_dir_t lv_obj_get_style_bg_grad_dir(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_DIR); + return (lv_grad_dir_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_bg_main_stop(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_MAIN_STOP); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_bg_grad_stop(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD_STOP); + return (lv_coord_t)v.num; +} + +static inline const lv_grad_dsc_t * lv_obj_get_style_bg_grad(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD); + return (const lv_grad_dsc_t *)v.ptr; +} + +static inline lv_dither_mode_t lv_obj_get_style_bg_dither_mode(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_DITHER_MODE); + return (lv_dither_mode_t)v.num; +} + +static inline const void * lv_obj_get_style_bg_img_src(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_SRC); + return (const void *)v.ptr; +} + +static inline lv_opa_t lv_obj_get_style_bg_img_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_bg_img_recolor(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_bg_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_bg_img_recolor_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_RECOLOR_OPA); + return (lv_opa_t)v.num; +} + +static inline bool lv_obj_get_style_bg_img_tiled(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_IMG_TILED); + return (bool)v.num; +} + +static inline lv_color_t lv_obj_get_style_border_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_border_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_border_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_border_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_border_side_t lv_obj_get_style_border_side(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_SIDE); + return (lv_border_side_t)v.num; +} + +static inline bool lv_obj_get_style_border_post(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BORDER_POST); + return (bool)v.num; +} + +static inline lv_coord_t lv_obj_get_style_outline_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_outline_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_outline_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_outline_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_outline_pad(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OUTLINE_PAD); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_shadow_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_shadow_ofs_x(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OFS_X); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_shadow_ofs_y(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OFS_Y); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_shadow_spread(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_SPREAD); + return (lv_coord_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_shadow_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_shadow_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_shadow_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_SHADOW_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_opa_t lv_obj_get_style_img_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_color_t lv_obj_get_style_img_recolor(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_img_recolor_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_img_recolor_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_IMG_RECOLOR_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_line_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_line_dash_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_DASH_WIDTH); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_line_dash_gap(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_DASH_GAP); + return (lv_coord_t)v.num; +} + +static inline bool lv_obj_get_style_line_rounded(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_ROUNDED); + return (bool)v.num; +} + +static inline lv_color_t lv_obj_get_style_line_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_line_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_line_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LINE_OPA); + return (lv_opa_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_arc_width(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_WIDTH); + return (lv_coord_t)v.num; +} + +static inline bool lv_obj_get_style_arc_rounded(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_ROUNDED); + return (bool)v.num; +} + +static inline lv_color_t lv_obj_get_style_arc_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_arc_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_arc_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_OPA); + return (lv_opa_t)v.num; +} + +static inline const void * lv_obj_get_style_arc_img_src(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ARC_IMG_SRC); + return (const void *)v.ptr; +} + +static inline lv_color_t lv_obj_get_style_text_color(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_COLOR); + return v.color; +} + +static inline lv_color_t lv_obj_get_style_text_color_filtered(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = _lv_obj_style_apply_color_filter(obj, part, lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_COLOR)); + return v.color; +} + +static inline lv_opa_t lv_obj_get_style_text_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_OPA); + return (lv_opa_t)v.num; +} + +static inline const lv_font_t * lv_obj_get_style_text_font(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_FONT); + return (const lv_font_t *)v.ptr; +} + +static inline lv_coord_t lv_obj_get_style_text_letter_space(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_LETTER_SPACE); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_text_line_space(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_LINE_SPACE); + return (lv_coord_t)v.num; +} + +static inline lv_text_decor_t lv_obj_get_style_text_decor(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_DECOR); + return (lv_text_decor_t)v.num; +} + +static inline lv_text_align_t lv_obj_get_style_text_align(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TEXT_ALIGN); + return (lv_text_align_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_radius(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_RADIUS); + return (lv_coord_t)v.num; +} + +static inline bool lv_obj_get_style_clip_corner(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_CLIP_CORNER); + return (bool)v.num; +} + +static inline lv_opa_t lv_obj_get_style_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_OPA); + return (lv_opa_t)v.num; +} + +static inline const lv_color_filter_dsc_t * lv_obj_get_style_color_filter_dsc(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_DSC); + return (const lv_color_filter_dsc_t *)v.ptr; +} + +static inline lv_opa_t lv_obj_get_style_color_filter_opa(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_COLOR_FILTER_OPA); + return (lv_opa_t)v.num; +} + +static inline const lv_anim_t * lv_obj_get_style_anim(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM); + return (const lv_anim_t *)v.ptr; +} + +static inline uint32_t lv_obj_get_style_anim_time(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM_TIME); + return (uint32_t)v.num; +} + +static inline uint32_t lv_obj_get_style_anim_speed(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ANIM_SPEED); + return (uint32_t)v.num; +} + +static inline const lv_style_transition_dsc_t * lv_obj_get_style_transition(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_TRANSITION); + return (const lv_style_transition_dsc_t *)v.ptr; +} + +static inline lv_blend_mode_t lv_obj_get_style_blend_mode(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BLEND_MODE); + return (lv_blend_mode_t)v.num; +} + +static inline uint16_t lv_obj_get_style_layout(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_LAYOUT); + return (uint16_t)v.num; +} + +static inline lv_base_dir_t lv_obj_get_style_base_dir(const struct _lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BASE_DIR); + return (lv_base_dir_t)v.num; +} + +void lv_obj_set_style_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_min_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_max_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_height(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_min_height(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_max_height(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_align(struct _lv_obj_t * obj, lv_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_height(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_translate_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_translate_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_zoom(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_angle(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_pivot_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_transform_pivot_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_top(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_bottom(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_left(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_right(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_row(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_pad_column(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_grad_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_grad_dir(struct _lv_obj_t * obj, lv_grad_dir_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_main_stop(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_grad_stop(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_grad(struct _lv_obj_t * obj, const lv_grad_dsc_t * value, lv_style_selector_t selector); +void lv_obj_set_style_bg_dither_mode(struct _lv_obj_t * obj, lv_dither_mode_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_img_src(struct _lv_obj_t * obj, const void * value, lv_style_selector_t selector); +void lv_obj_set_style_bg_img_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_img_recolor(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_img_recolor_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_bg_img_tiled(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); +void lv_obj_set_style_border_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_border_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_border_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_border_side(struct _lv_obj_t * obj, lv_border_side_t value, lv_style_selector_t selector); +void lv_obj_set_style_border_post(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); +void lv_obj_set_style_outline_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_outline_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_outline_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_outline_pad(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_ofs_x(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_ofs_y(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_spread(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_shadow_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_img_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_img_recolor(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_img_recolor_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_line_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_line_dash_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_line_dash_gap(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_line_rounded(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); +void lv_obj_set_style_line_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_line_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_arc_width(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_arc_rounded(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); +void lv_obj_set_style_arc_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_arc_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_arc_img_src(struct _lv_obj_t * obj, const void * value, lv_style_selector_t selector); +void lv_obj_set_style_text_color(struct _lv_obj_t * obj, lv_color_t value, lv_style_selector_t selector); +void lv_obj_set_style_text_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_text_font(struct _lv_obj_t * obj, const lv_font_t * value, lv_style_selector_t selector); +void lv_obj_set_style_text_letter_space(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_text_line_space(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_text_decor(struct _lv_obj_t * obj, lv_text_decor_t value, lv_style_selector_t selector); +void lv_obj_set_style_text_align(struct _lv_obj_t * obj, lv_text_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_radius(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_clip_corner(struct _lv_obj_t * obj, bool value, lv_style_selector_t selector); +void lv_obj_set_style_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_color_filter_dsc(struct _lv_obj_t * obj, const lv_color_filter_dsc_t * value, lv_style_selector_t selector); +void lv_obj_set_style_color_filter_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector); +void lv_obj_set_style_anim(struct _lv_obj_t * obj, const lv_anim_t * value, lv_style_selector_t selector); +void lv_obj_set_style_anim_time(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector); +void lv_obj_set_style_anim_speed(struct _lv_obj_t * obj, uint32_t value, lv_style_selector_t selector); +void lv_obj_set_style_transition(struct _lv_obj_t * obj, const lv_style_transition_dsc_t * value, lv_style_selector_t selector); +void lv_obj_set_style_blend_mode(struct _lv_obj_t * obj, lv_blend_mode_t value, lv_style_selector_t selector); +void lv_obj_set_style_layout(struct _lv_obj_t * obj, uint16_t value, lv_style_selector_t selector); +void lv_obj_set_style_base_dir(struct _lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector); diff --git a/include/liblvgl/core/lv_obj_tree.h b/include/liblvgl/core/lv_obj_tree.h new file mode 100644 index 0000000..bee9e16 --- /dev/null +++ b/include/liblvgl/core/lv_obj_tree.h @@ -0,0 +1,172 @@ +/** + * @file struct _lv_obj_tree.h + * + */ + +#ifndef LV_OBJ_TREE_H +#define LV_OBJ_TREE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include + +/********************* + * DEFINES + *********************/ + + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_obj_class_t; + +typedef enum { + LV_OBJ_TREE_WALK_NEXT, + LV_OBJ_TREE_WALK_SKIP_CHILDREN, + LV_OBJ_TREE_WALK_END, +} lv_obj_tree_walk_res_t; + +typedef lv_obj_tree_walk_res_t (*lv_obj_tree_walk_cb_t)(struct _lv_obj_t *, void *); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Delete an object and all of its children. + * Also remove the objects from their group and remove all animations (if any). + * Send `LV_EVENT_DELETED` to deleted objects. + * @param obj pointer to an object + */ +void lv_obj_del(struct _lv_obj_t * obj); + +/** + * Delete all children of an object. + * Also remove the objects from their group and remove all animations (if any). + * Send `LV_EVENT_DELETED` to deleted objects. + * @param obj pointer to an object + */ +void lv_obj_clean(struct _lv_obj_t * obj); + +/** + * Delete an object after some delay + * @param obj pointer to an object + * @param delay_ms time to wait before delete in milliseconds + */ +void lv_obj_del_delayed(struct _lv_obj_t * obj, uint32_t delay_ms); + +/** + * A function to be easily used in animation ready callback to delete an object when the animation is ready + * @param a pointer to the animation + */ +void lv_obj_del_anim_ready_cb(lv_anim_t * a); + +/** + * Helper function for asynchronously deleting objects. + * Useful for cases where you can't delete an object directly in an `LV_EVENT_DELETE` handler (i.e. parent). + * @param obj object to delete + * @see lv_async_call + */ +void lv_obj_del_async(struct _lv_obj_t * obj); + +/** + * Move the parent of an object. The relative coordinates will be kept. + * + * @param obj pointer to an object whose parent needs to be changed + * @param parent pointer to the new parent + */ +void lv_obj_set_parent(struct _lv_obj_t * obj, struct _lv_obj_t * parent); + +/** + * Swap the positions of two objects. + * When used in listboxes, it can be used to sort the listbox items. + * @param obj1 pointer to the first object + * @param obj2 pointer to the second object + */ +void lv_obj_swap(struct _lv_obj_t * obj1, struct _lv_obj_t * obj2); + +/** + * moves the object to the given index in its parent. + * When used in listboxes, it can be used to sort the listbox items. + * @param obj pointer to the object to be moved. + * @param index new index in parent. -1 to count from the back + * @note to move to the background: lv_obj_move_to_index(obj, 0) + * @note to move forward (up): lv_obj_move_to_index(obj, lv_obj_get_index(obj) - 1) + */ +void lv_obj_move_to_index(struct _lv_obj_t * obj, int32_t index); + +/** + * Get the screen of an object + * @param obj pointer to an object + * @return pointer to the object's screen + */ +struct _lv_obj_t * lv_obj_get_screen(const struct _lv_obj_t * obj); + +/** + * Get the display of the object + * @param obj pointer to an object + * @return pointer to the object's display + */ +lv_disp_t * lv_obj_get_disp(const struct _lv_obj_t * obj); + +/** + * Get the parent of an object + * @param obj pointer to an object + * @return the parent of the object. (NULL if `obj` was a screen) + */ +struct _lv_obj_t * lv_obj_get_parent(const struct _lv_obj_t * obj); + +/** + * Get the child of an object by the child's index. + * @param obj pointer to an object whose child should be get + * @param id the index of the child. + * 0: the oldest (firstly created) child + * 1: the second oldest + * child count-1: the youngest + * -1: the youngest + * -2: the second youngest + * @return pointer to the child or NULL if the index was invalid + */ +struct _lv_obj_t * lv_obj_get_child(const struct _lv_obj_t * obj, int32_t id); + +/** + * Get the number of children + * @param obj pointer to an object + * @return the number of children + */ +uint32_t lv_obj_get_child_cnt(const struct _lv_obj_t * obj); + +/** + * Get the index of a child. + * @param obj pointer to an object + * @return the child index of the object. + * E.g. 0: the oldest (firstly created child) + */ +uint32_t lv_obj_get_index(const struct _lv_obj_t * obj); + +/** + * Iterate through all children of any object. + * @param start_obj start integrating from this object + * @param cb call this callback on the objects + * @param user_data pointer to any user related data (will be passed to `cb`) + */ +void lv_obj_tree_walk(struct _lv_obj_t * start_obj, lv_obj_tree_walk_cb_t cb, void * user_data); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OBJ_TREE_H*/ diff --git a/include/liblvgl/core/lv_refr.h b/include/liblvgl/core/lv_refr.h new file mode 100644 index 0000000..72e8d6c --- /dev/null +++ b/include/liblvgl/core/lv_refr.h @@ -0,0 +1,115 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include + +/********************* + * DEFINES + *********************/ + +#define LV_REFR_TASK_PRIO LV_TASK_PRIO_MID + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Initialize the screen refresh subsystem + */ +void _lv_refr_init(void); + +/** + * Redraw the invalidated areas now. + * Normally the redrawing is periodically executed in `lv_timer_handler` but a long blocking process + * can prevent the call of `lv_timer_handler`. In this case if the GUI is updated in the process + * (e.g. progress bar) this function can be called when the screen should be updated. + * @param disp pointer to display to refresh. NULL to refresh all displays. + */ +void lv_refr_now(lv_disp_t * disp); + +/** + * Redrawn on object an all its children using the passed draw context + * @param draw pointer to an initialized draw context + * @param obj the start object from the redraw should start + */ +void lv_obj_redraw(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj); + +/** + * Invalidate an area on display to redraw it + * @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas) + * @param disp pointer to display where the area should be invalidated (NULL can be used if there is + * only one display) + */ +void _lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p); + +/** + * Get the display which is being refreshed + * @return the display being refreshed + */ +lv_disp_t * _lv_refr_get_disp_refreshing(void); + +/** + * Set the display which is being refreshed. + * It shouldn't be used directly by the user. + * It can be used to trick the drawing functions about there is an active display. + * @param the display being refreshed + */ +void _lv_refr_set_disp_refreshing(lv_disp_t * disp); + +#if LV_USE_PERF_MONITOR +/** + * Reset FPS counter + */ +void lv_refr_reset_fps_counter(void); + +/** + * Get the average FPS + * @return the average FPS + */ +uint32_t lv_refr_get_fps_avg(void); +#endif + +/** + * Called periodically to handle the refreshing + * @param timer pointer to the timer itself + */ +void _lv_disp_refr_timer(lv_timer_t * timer); + +/********************** + * STATIC FUNCTIONS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_REFR_H*/ diff --git a/include/liblvgl/core/lv_theme.h b/include/liblvgl/core/lv_theme.h new file mode 100644 index 0000000..80da522 --- /dev/null +++ b/include/liblvgl/core/lv_theme.h @@ -0,0 +1,120 @@ +/** + *@file lv_theme.h + * + */ + +#ifndef LV_THEME_H +#define LV_THEME_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_theme_t; +struct _lv_disp_t; + +typedef void (*lv_theme_apply_cb_t)(struct _lv_theme_t *, lv_obj_t *); + +typedef struct _lv_theme_t { + lv_theme_apply_cb_t apply_cb; + struct _lv_theme_t * parent; /**< Apply the current theme's style on top of this theme.*/ + void * user_data; + struct _lv_disp_t * disp; + lv_color_t color_primary; + lv_color_t color_secondary; + const lv_font_t * font_small; + const lv_font_t * font_normal; + const lv_font_t * font_large; + uint32_t flags; /*Any custom flag used by the theme*/ +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the theme assigned to the display of the object + * @param obj pointer to a theme object + * @return the theme of the object's display (can be NULL) + */ +lv_theme_t * lv_theme_get_from_obj(lv_obj_t * obj); + +/** + * Apply the active theme on an object + * @param obj pointer to an object + */ +void lv_theme_apply(lv_obj_t * obj); + +/** + * Set a base theme for a theme. + * The styles from the base them will be added before the styles of the current theme. + * Arbitrary long chain of themes can be created by setting base themes. + * @param new_theme pointer to theme which base should be set + * @param parent pointer to the base theme + */ +void lv_theme_set_parent(lv_theme_t * new_theme, lv_theme_t * parent); + +/** + * Set an apply callback for a theme. + * The apply callback is used to add styles to different objects + * @param theme pointer to theme which callback should be set + * @param apply_cb pointer to the callback + */ +void lv_theme_set_apply_cb(lv_theme_t * theme, lv_theme_apply_cb_t apply_cb); + +/** + * Get the small font of the theme + * @param obj pointer to an object + * @return pointer to the font + */ +const lv_font_t * lv_theme_get_font_small(lv_obj_t * obj); +/** + * Get the normal font of the theme + * @param obj pointer to an object + * @return pointer to the font + */ +const lv_font_t * lv_theme_get_font_normal(lv_obj_t * obj); + +/** + * Get the subtitle font of the theme + * @param obj pointer to an object + * @return pointer to the font + */ +const lv_font_t * lv_theme_get_font_large(lv_obj_t * obj); + +/** + * Get the primary color of the theme + * @param obj pointer to an object + * @return the color + */ +lv_color_t lv_theme_get_color_primary(lv_obj_t * obj); + +/** + * Get the secondary color of the theme + * @param obj pointer to an object + * @return the color + */ +lv_color_t lv_theme_get_color_secondary(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_THEME_H*/ diff --git a/include/liblvgl/draw/arm2d/lv_gpu_arm2d.h b/include/liblvgl/draw/arm2d/lv_gpu_arm2d.h new file mode 100644 index 0000000..cc66990 --- /dev/null +++ b/include/liblvgl/draw/arm2d/lv_gpu_arm2d.h @@ -0,0 +1,51 @@ +/** + * @file lv_gpu_arm2d.h + * + */ + +#ifndef LV_GPU_ARM2D_H +#define LV_GPU_ARM2D_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/hal/lv_hal_disp.h" +#include "liblvgl/draw/sw/lv_draw_sw.h" + +#if LV_USE_GPU_ARM2D + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_arm2d_ctx_t; + +struct _lv_disp_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_arm2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_arm2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_ARM2D*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_ARM2D_H*/ diff --git a/include/liblvgl/draw/lv_draw.h b/include/liblvgl/draw/lv_draw.h new file mode 100644 index 0000000..c8aed72 --- /dev/null +++ b/include/liblvgl/draw/lv_draw.h @@ -0,0 +1,218 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include "liblvgl/misc/lv_style.h" +#include "liblvgl/misc/lv_txt.h" +#include "lv_img_decoder.h" +#include "lv_img_cache.h" + +#include "lv_draw_rect.h" +#include "lv_draw_label.h" +#include "lv_draw_img.h" +#include "lv_draw_line.h" +#include "lv_draw_triangle.h" +#include "lv_draw_arc.h" +#include "lv_draw_mask.h" +#include "lv_draw_transform.h" +#include "lv_draw_layer.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + void * user_data; +} lv_draw_mask_t; + +typedef struct _lv_draw_layer_ctx_t { + lv_area_t area_full; + lv_area_t area_act; + lv_coord_t max_row_with_alpha; + lv_coord_t max_row_with_no_alpha; + void * buf; + struct { + const lv_area_t * clip_area; + lv_area_t * buf_area; + void * buf; + bool screen_transp; + } original; +} lv_draw_layer_ctx_t; + +typedef struct _lv_draw_ctx_t { + /** + * Pointer to a buffer to draw into + */ + void * buf; + + /** + * The position and size of `buf` (absolute coordinates) + */ + lv_area_t * buf_area; + + /** + * The current clip area with absolute coordinates, always the same or smaller than `buf_area` + */ + const lv_area_t * clip_area; + + + void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + + void (*draw_arc)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle); + + void (*draw_img_decoded)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); + + lv_res_t (*draw_img)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const void * src); + + void (*draw_letter)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); + + + void (*draw_line)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + + + void (*draw_polygon)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, + const lv_point_t * points, uint16_t point_cnt); + + + /** + * Get an area of a transformed image (zoomed and/or rotated) + * @param draw_ctx pointer to a draw context + * @param dest_area get this area of the result image. It assumes that the original image is placed to the 0;0 position. + * @param src_buf the source image + * @param src_w width of the source image in [px] + * @param src_h height of the source image in [px] + * @param src_stride the stride in [px]. + * @param draw_dsc an `lv_draw_img_dsc_t` descriptor containing the transformation parameters + * @param cf the color format of `src_buf` + * @param cbuf place the colors of the pixels on `dest_area` here in RGB format + * @param abuf place the opacity of the pixels on `dest_area` here + */ + void (*draw_transform)(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf, + lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride, + const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf); + + /** + * Replace the buffer with a rect without decoration like radius or borders + */ + void (*draw_bg)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_area_t * coords); + + /** + * Wait until all background operations are finished. (E.g. GPU operations) + */ + void (*wait_for_finish)(struct _lv_draw_ctx_t * draw_ctx); + + /** + * Copy an area from buffer to an other + * @param draw_ctx pointer to a draw context + * @param dest_buf copy the buffer into this buffer + * @param dest_stride the width of the dest_buf in pixels + * @param dest_area the destination area + * @param src_buf copy from this buffer + * @param src_stride the width of src_buf in pixels + * @param src_area the source area. + * + * @note dest_area and src_area must have the same width and height + * but can have different x and y position. + * @note dest_area and src_area must be clipped to the real dimensions of the buffers + */ + void (*buffer_copy)(struct _lv_draw_ctx_t * draw_ctx, void * dest_buf, lv_coord_t dest_stride, + const lv_area_t * dest_area, + void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); + + /** + * Initialize a new layer context. + * The original buffer and area data are already saved from `draw_ctx` to `layer_ctx` + * @param draw_ctx pointer to the current draw context + * @param layer_area the coordinates of the layer + * @param flags OR-ed flags from @lv_draw_layer_flags_t + * @return pointer to the layer context, or NULL on error + */ + struct _lv_draw_layer_ctx_t * (*layer_init)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + + /** + * Adjust the layer_ctx and/or draw_ctx based on the `layer_ctx->area_act`. + * It's called only if flags has `LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE` + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + * @param flags OR-ed flags from @lv_draw_layer_flags_t + */ + void (*layer_adjust)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + + /** + * Blend a rendered layer to `layer_ctx->area_act` + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + * @param draw_dsc pointer to an image draw descriptor + */ + void (*layer_blend)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + const lv_draw_img_dsc_t * draw_dsc); + + /** + * Destroy a layer context. The original buffer and area data of the `draw_ctx` will be restored + * and the `layer_ctx` itself will be freed automatically. + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + */ + void (*layer_destroy)(struct _lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx); + + /** + * Size of a layer context in bytes. + */ + size_t layer_instance_size; + +#if LV_USE_USER_DATA + void * user_data; +#endif + +} lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_init(void); + + +void lv_draw_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/include/liblvgl/draw/lv_draw_arc.h b/include/liblvgl/draw/lv_draw_arc.h new file mode 100644 index 0000000..8633af5 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_arc.h @@ -0,0 +1,83 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_color_t color; + lv_coord_t width; + uint16_t start_angle; + uint16_t end_angle; + const void * img_src; + lv_opa_t opa; + lv_blend_mode_t blend_mode : 2; + uint8_t rounded : 1; +} lv_draw_arc_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_arc_dsc_init(lv_draw_arc_dsc_t * dsc); + +/** + * Draw an arc. (Can draw pie too with great thickness.) + * @param center_x the x coordinate of the center of the arc + * @param center_y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param mask the arc will be drawn only in this mask + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param clip_area the arc will be drawn only in this area + * @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable + */ +void lv_draw_arc(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle); + +/** + * Get an area the should be invalidated when the arcs angle changed between start_angle and end_ange + * @param x the x coordinate of the center of the arc + * @param y the y coordinate of the center of the arc + * @param radius the radius of the arc + * @param start_angle the start angle of the arc (0 deg on the bottom, 90 deg on the right) + * @param end_angle the end angle of the arc + * @param w width of the arc + * @param rounded true: the arc is rounded + * @param area store the area to invalidate here + */ +void lv_draw_arc_get_area(lv_coord_t x, lv_coord_t y, uint16_t radius, uint16_t start_angle, uint16_t end_angle, + lv_coord_t w, bool rounded, lv_area_t * area); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_ARC_H*/ diff --git a/include/liblvgl/draw/lv_draw_img.h b/include/liblvgl/draw/lv_draw_img.h new file mode 100644 index 0000000..dcb7113 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_img.h @@ -0,0 +1,104 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_img_decoder.h" +#include "lv_img_buf.h" +#include "liblvgl/misc/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + + int16_t angle; + uint16_t zoom; + lv_point_t pivot; + + lv_color_t recolor; + lv_opa_t recolor_opa; + + lv_opa_t opa; + lv_blend_mode_t blend_mode : 4; + + int32_t frame_id; + uint8_t antialias : 1; +} lv_draw_img_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc); +/** + * Draw an image + * @param coords the coordinates of the image + * @param mask the image will be drawn only in this area + * @param src pointer to a lv_color_t array which contains the pixels of the image + * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable + */ +void lv_draw_img(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const lv_area_t * coords, + const void * src); + + +void lv_draw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); + +/** + * Get the type of an image source + * @param src pointer to an image source: + * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code) + * - a path to a file (e.g. "S:/folder/image.bin") + * - or a symbol (e.g. LV_SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Get the pixel size of a color format in bits + * @param cf a color format (`LV_IMG_CF_...`) + * @return the pixel size in bits + */ +uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf); + +/** + * Check if a color format is chroma keyed or not + * @param cf a color format (`LV_IMG_CF_...`) + * @return true: chroma keyed; false: not chroma keyed + */ +bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf); + +/** + * Check if a color format has alpha channel or not + * @param cf a color format (`LV_IMG_CF_...`) + * @return true: has alpha channel; false: doesn't have alpha channel + */ +bool lv_img_cf_has_alpha(lv_img_cf_t cf); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_IMG_H*/ diff --git a/include/liblvgl/draw/lv_draw_label.h b/include/liblvgl/draw/lv_draw_label.h new file mode 100644 index 0000000..736aa72 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_label.h @@ -0,0 +1,100 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_bidi.h" +#include "liblvgl/misc/lv_txt.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_style.h" + +/********************* + * DEFINES + *********************/ +#define LV_DRAW_LABEL_NO_TXT_SEL (0xFFFF) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + const lv_font_t * font; + uint32_t sel_start; + uint32_t sel_end; + lv_color_t color; + lv_color_t sel_color; + lv_color_t sel_bg_color; + lv_coord_t line_space; + lv_coord_t letter_space; + lv_coord_t ofs_x; + lv_coord_t ofs_y; + lv_opa_t opa; + lv_base_dir_t bidi_dir; + lv_text_align_t align; + lv_text_flag_t flag; + lv_text_decor_t decor : 3; + lv_blend_mode_t blend_mode: 3; +} lv_draw_label_dsc_t; + +/** Store some info to speed up drawing of very large texts + * It takes a lot of time to get the first visible character because + * all the previous characters needs to be checked to calculate the positions. + * This structure stores an earlier (e.g. at -1000 px) coordinate and the index of that line. + * Therefore the calculations can start from here.*/ +typedef struct _lv_draw_label_hint_t { + /** Index of the line at `y` coordinate*/ + int32_t line_start; + + /** Give the `y` coordinate of the first letter at `line start` index. Relative to the label's coordinates*/ + int32_t y; + + /** The 'y1' coordinate of the label when the hint was saved. + * Used to invalidate the hint if the label has moved too much.*/ + int32_t coord_y; +} lv_draw_label_hint_t; + +struct _lv_draw_ctx_t; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +LV_ATTRIBUTE_FAST_MEM void lv_draw_label_dsc_init(lv_draw_label_dsc_t * dsc); + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param dsc pointer to draw descriptor + * @param txt `\0` terminated text to write + * @param hint pointer to a `lv_draw_label_hint_t` variable. + * It is managed by the draw to speed up the drawing of very long texts (thousands of lines). + */ +LV_ATTRIBUTE_FAST_MEM void lv_draw_label(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, + const lv_area_t * coords, const char * txt, lv_draw_label_hint_t * hint); + +void lv_draw_letter(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); + +/*********************** + * GLOBAL VARIABLES + ***********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/include/liblvgl/draw/lv_draw_layer.h b/include/liblvgl/draw/lv_draw_layer.h new file mode 100644 index 0000000..1280d33 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_layer.h @@ -0,0 +1,83 @@ +/** + * @file lv_draw_layer.h + * + */ + +#ifndef LV_DRAW_LAYER_H +#define LV_DRAW_LAYER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_draw_ctx_t; +struct _lv_draw_layer_ctx_t; + +typedef enum { + LV_DRAW_LAYER_FLAG_NONE, + LV_DRAW_LAYER_FLAG_HAS_ALPHA, + LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE, +} lv_draw_layer_flags_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a new layer context. It is used to start and independent rendering session + * with the current draw_ctx + * @param draw_ctx pointer to the current draw context + * @param layer_area the coordinates of the layer + * @param flags OR-ed flags from @lv_draw_layer_flags_t + * @return pointer to the layer context, or NULL on error + */ +struct _lv_draw_layer_ctx_t * lv_draw_layer_create(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * layer_area, + lv_draw_layer_flags_t flags); + +/** + * Adjust the layer_ctx and/or draw_ctx based on the `layer_ctx->area_act`. + * It's called only if flags has `LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE` + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + * @param flags OR-ed flags from @lv_draw_layer_flags_t + */ +void lv_draw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + +/** + * Blend a rendered layer to `layer_ctx->area_act` + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + * @param draw_dsc pointer to an image draw descriptor + */ +void lv_draw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + lv_draw_img_dsc_t * draw_dsc); + +/** + * Destroy a layer context. + * @param draw_ctx pointer to the current draw context + * @param layer_ctx pointer to a layer context + */ +void lv_draw_layer_destroy(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_LAYER_H*/ diff --git a/include/liblvgl/draw/lv_draw_line.h b/include/liblvgl/draw/lv_draw_line.h new file mode 100644 index 0000000..79ca0dc --- /dev/null +++ b/include/liblvgl/draw/lv_draw_line.h @@ -0,0 +1,67 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_color_t color; + lv_coord_t width; + lv_coord_t dash_width; + lv_coord_t dash_gap; + lv_opa_t opa; + lv_blend_mode_t blend_mode : 2; + uint8_t round_start : 1; + uint8_t round_end : 1; + uint8_t raw_end : 1; /*Do not bother with perpendicular line ending if it's not visible for any reason*/ +} lv_draw_line_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +LV_ATTRIBUTE_FAST_MEM void lv_draw_line_dsc_init(lv_draw_line_dsc_t * dsc); + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param clip the line will be drawn only in this area + * @param dsc pointer to an initialized `lv_draw_line_dsc_t` variable + */ +void lv_draw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/include/liblvgl/draw/lv_draw_mask.h b/include/liblvgl/draw/lv_draw_mask.h new file mode 100644 index 0000000..f3c49e5 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_mask.h @@ -0,0 +1,394 @@ +/** + * @file lv_draw_mask.h + * + */ + +#ifndef LV_DRAW_MASK_H +#define LV_DRAW_MASK_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_math.h" + +/********************* + * DEFINES + *********************/ +#define LV_MASK_ID_INV (-1) +#if LV_DRAW_COMPLEX +# define _LV_MASK_MAX_NUM 16 +#else +# define _LV_MASK_MAX_NUM 1 +#endif + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_DRAW_MASK_RES_TRANSP, + LV_DRAW_MASK_RES_FULL_COVER, + LV_DRAW_MASK_RES_CHANGED, + LV_DRAW_MASK_RES_UNKNOWN +}; + +typedef uint8_t lv_draw_mask_res_t; + +typedef struct { + void * param; + void * custom_id; +} _lv_draw_mask_saved_t; + +typedef _lv_draw_mask_saved_t _lv_draw_mask_saved_arr_t[_LV_MASK_MAX_NUM]; + + + +#if LV_DRAW_COMPLEX == 0 +static inline uint8_t lv_draw_mask_get_cnt(void) +{ + return 0; +} + +static inline bool lv_draw_mask_is_any(const lv_area_t * a) +{ + LV_UNUSED(a); + return false; +} + +#endif + +#if LV_DRAW_COMPLEX + +enum { + LV_DRAW_MASK_TYPE_LINE, + LV_DRAW_MASK_TYPE_ANGLE, + LV_DRAW_MASK_TYPE_RADIUS, + LV_DRAW_MASK_TYPE_FADE, + LV_DRAW_MASK_TYPE_MAP, + LV_DRAW_MASK_TYPE_POLYGON, +}; + +typedef uint8_t lv_draw_mask_type_t; + +enum { + LV_DRAW_MASK_LINE_SIDE_LEFT = 0, + LV_DRAW_MASK_LINE_SIDE_RIGHT, + LV_DRAW_MASK_LINE_SIDE_TOP, + LV_DRAW_MASK_LINE_SIDE_BOTTOM, +}; + +/** + * A common callback type for every mask type. + * Used internally by the library. + */ +typedef lv_draw_mask_res_t (*lv_draw_mask_xcb_t)(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, + lv_coord_t len, + void * p); + +typedef uint8_t lv_draw_mask_line_side_t; + +typedef struct { + lv_draw_mask_xcb_t cb; + lv_draw_mask_type_t type; +} _lv_draw_mask_common_dsc_t; + +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + /*First point*/ + lv_point_t p1; + + /*Second point*/ + lv_point_t p2; + + /*Which side to keep?*/ + lv_draw_mask_line_side_t side : 2; + } cfg; + + /*A point of the line*/ + lv_point_t origo; + + /*X / (1024*Y) steepness (X is 0..1023 range). What is the change of X in 1024 Y?*/ + int32_t xy_steep; + + /*Y / (1024*X) steepness (Y is 0..1023 range). What is the change of Y in 1024 X?*/ + int32_t yx_steep; + + /*Helper which stores yx_steep for flat lines and xy_steep for steep (non flat) lines*/ + int32_t steep; + + /*Steepness in 1 px in 0..255 range. Used only by flat lines.*/ + int32_t spx; + + /*1: It's a flat line? (Near to horizontal)*/ + uint8_t flat : 1; + + /*Invert the mask. The default is: Keep the left part. + *It is used to select left/right/top/bottom*/ + uint8_t inv: 1; +} lv_draw_mask_line_param_t; + +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_point_t vertex_p; + lv_coord_t start_angle; + lv_coord_t end_angle; + } cfg; + + lv_draw_mask_line_param_t start_line; + lv_draw_mask_line_param_t end_line; + uint16_t delta_deg; +} lv_draw_mask_angle_param_t; + +typedef struct { + uint8_t * buf; + lv_opa_t * cir_opa; /*Opacity of values on the circumference of an 1/4 circle*/ + uint16_t * x_start_on_y; /*The x coordinate of the circle for each y value*/ + uint16_t * opa_start_on_y; /*The index of `cir_opa` for each y value*/ + int32_t life; /*How many times the entry way used*/ + uint32_t used_cnt; /*Like a semaphore to count the referencing masks*/ + lv_coord_t radius; /*The radius of the entry*/ +} _lv_draw_mask_radius_circle_dsc_t; + +typedef _lv_draw_mask_radius_circle_dsc_t _lv_draw_mask_radius_circle_dsc_arr_t[LV_CIRCLE_CACHE_SIZE]; + +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_area_t rect; + lv_coord_t radius; + /*Invert the mask. 0: Keep the pixels inside.*/ + uint8_t outer: 1; + } cfg; + + _lv_draw_mask_radius_circle_dsc_t * circle; +} lv_draw_mask_radius_param_t; + + +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_area_t coords; + lv_coord_t y_top; + lv_coord_t y_bottom; + lv_opa_t opa_top; + lv_opa_t opa_bottom; + } cfg; + +} lv_draw_mask_fade_param_t; + + +typedef struct _lv_draw_mask_map_param_t { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_area_t coords; + const lv_opa_t * map; + } cfg; +} lv_draw_mask_map_param_t; + +typedef struct { + /*The first element must be the common descriptor*/ + _lv_draw_mask_common_dsc_t dsc; + + struct { + lv_point_t * points; + uint16_t point_cnt; + } cfg; +} lv_draw_mask_polygon_param_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Add a draw mask. Everything drawn after it (until removing the mask) will be affected by the mask. + * @param param an initialized mask parameter. Only the pointer is saved. + * @param custom_id a custom pointer to identify the mask. Used in `lv_draw_mask_remove_custom`. + * @return the an integer, the ID of the mask. Can be used in `lv_draw_mask_remove_id`. + */ +int16_t lv_draw_mask_add(void * param, void * custom_id); + +//! @cond Doxygen_Suppress + +/** + * Apply the added buffers on a line. Used internally by the library's drawing routines. + * @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`. + * @param abs_x absolute X coordinate where the line to calculate start + * @param abs_y absolute Y coordinate where the line to calculate start + * @param len length of the line to calculate (in pixel count) + * @return One of these values: + * - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero + * - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged + * - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line + */ +LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, + lv_coord_t len); + +/** + * Apply the specified buffers on a line. Used internally by the library's drawing routines. + * @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`. + * @param abs_x absolute X coordinate where the line to calculate start + * @param abs_y absolute Y coordinate where the line to calculate start + * @param len length of the line to calculate (in pixel count) + * @param ids ID array of added buffers + * @param ids_count number of ID array + * @return One of these values: + * - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero + * - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged + * - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line + */ +LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply_ids(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y, + lv_coord_t len, const int16_t * ids, int16_t ids_count); + +//! @endcond + +/** + * Remove a mask with a given ID + * @param id the ID of the mask. Returned by `lv_draw_mask_add` + * @return the parameter of the removed mask. + * If more masks have `custom_id` ID then the last mask's parameter will be returned + */ +void * lv_draw_mask_remove_id(int16_t id); + +/** + * Remove all mask with a given custom ID + * @param custom_id a pointer used in `lv_draw_mask_add` + * @return return the parameter of the removed mask. + * If more masks have `custom_id` ID then the last mask's parameter will be returned + */ +void * lv_draw_mask_remove_custom(void * custom_id); + +/** + * Free the data from the parameter. + * It's called inside `lv_draw_mask_remove_id` and `lv_draw_mask_remove_custom` + * Needs to be called only in special cases when the mask is not added by `lv_draw_mask_add` + * and not removed by `lv_draw_mask_remove_id` or `lv_draw_mask_remove_custom` + * @param p pointer to a mask parameter + */ +void lv_draw_mask_free_param(void * p); + +/** + * Called by LVGL the rendering of a screen is ready to clean up + * the temporal (cache) data of the masks + */ +void _lv_draw_mask_cleanup(void); + +//! @cond Doxygen_Suppress + +/** + * Count the currently added masks + * @return number of active masks + */ +LV_ATTRIBUTE_FAST_MEM uint8_t lv_draw_mask_get_cnt(void); + + +/** + * Check if there is any added draw mask + * @param a an area to test for affecting masks. + * @return true: there is t least 1 draw mask; false: there are no draw masks + */ +bool lv_draw_mask_is_any(const lv_area_t * a); + +//! @endcond + +/** + *Initialize a line mask from two points. + * @param param pointer to a `lv_draw_mask_param_t` to initialize + * @param p1x X coordinate of the first point of the line + * @param p1y Y coordinate of the first point of the line + * @param p2x X coordinate of the second point of the line + * @param p2y y coordinate of the second point of the line + * @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep. + * With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept + * With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept + */ +void lv_draw_mask_line_points_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t p1y, lv_coord_t p2x, + lv_coord_t p2y, lv_draw_mask_line_side_t side); + +/** + *Initialize a line mask from a point and an angle. + * @param param pointer to a `lv_draw_mask_param_t` to initialize + * @param px X coordinate of a point of the line + * @param py X coordinate of a point of the line + * @param angle right 0 deg, bottom: 90 + * @param side and element of `lv_draw_mask_line_side_t` to describe which side to keep. + * With `LV_DRAW_MASK_LINE_SIDE_LEFT/RIGHT` and horizontal line all pixels are kept + * With `LV_DRAW_MASK_LINE_SIDE_TOP/BOTTOM` and vertical line all pixels are kept + */ +void lv_draw_mask_line_angle_init(lv_draw_mask_line_param_t * param, lv_coord_t p1x, lv_coord_t py, int16_t angle, + lv_draw_mask_line_side_t side); + +/** + * Initialize an angle mask. + * @param param pointer to a `lv_draw_mask_param_t` to initialize + * @param vertex_x X coordinate of the angle vertex (absolute coordinates) + * @param vertex_y Y coordinate of the angle vertex (absolute coordinates) + * @param start_angle start angle in degrees. 0 deg on the right, 90 deg, on the bottom + * @param end_angle end angle + */ +void lv_draw_mask_angle_init(lv_draw_mask_angle_param_t * param, lv_coord_t vertex_x, lv_coord_t vertex_y, + lv_coord_t start_angle, lv_coord_t end_angle); + +/** + * Initialize a fade mask. + * @param param pointer to an `lv_draw_mask_radius_param_t` to initialize + * @param rect coordinates of the rectangle to affect (absolute coordinates) + * @param radius radius of the rectangle + * @param inv true: keep the pixels inside the rectangle; keep the pixels outside of the rectangle + */ +void lv_draw_mask_radius_init(lv_draw_mask_radius_param_t * param, const lv_area_t * rect, lv_coord_t radius, bool inv); + +/** + * Initialize a fade mask. + * @param param pointer to a `lv_draw_mask_param_t` to initialize + * @param coords coordinates of the area to affect (absolute coordinates) + * @param opa_top opacity on the top + * @param y_top at which coordinate start to change to opacity to `opa_bottom` + * @param opa_bottom opacity at the bottom + * @param y_bottom at which coordinate reach `opa_bottom`. + */ +void lv_draw_mask_fade_init(lv_draw_mask_fade_param_t * param, const lv_area_t * coords, lv_opa_t opa_top, + lv_coord_t y_top, + lv_opa_t opa_bottom, lv_coord_t y_bottom); + +/** + * Initialize a map mask. + * @param param pointer to a `lv_draw_mask_param_t` to initialize + * @param coords coordinates of the map (absolute coordinates) + * @param map array of bytes with the mask values + */ +void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map); + +void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt); + +#endif /*LV_DRAW_COMPLEX*/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_MASK_H*/ diff --git a/include/liblvgl/draw/lv_draw_rect.h b/include/liblvgl/draw/lv_draw_rect.h new file mode 100644 index 0000000..e259446 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_rect.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_style.h" +#include "sw/lv_draw_sw_gradient.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE 0x7FFF /**< A very big radius to always draw as circle*/ +LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE); + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_coord_t radius; + lv_blend_mode_t blend_mode; + + /*Background*/ + lv_opa_t bg_opa; + lv_color_t bg_color; /**< First element of a gradient is a color, so it maps well here*/ + lv_grad_dsc_t bg_grad; + + /*Background img*/ + const void * bg_img_src; + const void * bg_img_symbol_font; + lv_color_t bg_img_recolor; + lv_opa_t bg_img_opa; + lv_opa_t bg_img_recolor_opa; + uint8_t bg_img_tiled; + + /*Border*/ + lv_color_t border_color; + lv_coord_t border_width; + lv_opa_t border_opa; + uint8_t border_post : 1; /*There is a border it will be drawn later.*/ + lv_border_side_t border_side : 5; + + /*Outline*/ + lv_color_t outline_color; + lv_coord_t outline_width; + lv_coord_t outline_pad; + lv_opa_t outline_opa; + + /*Shadow*/ + lv_color_t shadow_color; + lv_coord_t shadow_width; + lv_coord_t shadow_ofs_x; + lv_coord_t shadow_ofs_y; + lv_coord_t shadow_spread; + lv_opa_t shadow_opa; +} lv_draw_rect_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc); + + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param clip the rectangle will be drawn only in this area + * @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable + */ +void lv_draw_rect(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/include/liblvgl/draw/lv_draw_transform.h b/include/liblvgl/draw/lv_draw_transform.h new file mode 100644 index 0000000..6e6236c --- /dev/null +++ b/include/liblvgl/draw/lv_draw_transform.h @@ -0,0 +1,44 @@ +/** + * @file lv_draw_transform.h + * + */ + +#ifndef LV_DRAW_TRANSFORM_H +#define LV_DRAW_TRANSFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_transform(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf, + lv_coord_t src_w, lv_coord_t src_h, + lv_coord_t src_stride, const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_TRANSFORM_H*/ diff --git a/include/liblvgl/draw/lv_draw_triangle.h b/include/liblvgl/draw/lv_draw_triangle.h new file mode 100644 index 0000000..e8d8575 --- /dev/null +++ b/include/liblvgl/draw/lv_draw_triangle.h @@ -0,0 +1,42 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_rect.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t points[], + uint16_t point_cnt); + +void lv_draw_triangle(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t points[]); +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/include/liblvgl/draw/lv_img_buf.h b/include/liblvgl/draw/lv_img_buf.h new file mode 100644 index 0000000..8998839 --- /dev/null +++ b/include/liblvgl/draw/lv_img_buf.h @@ -0,0 +1,249 @@ +/** + * @file lv_img_buf.h + * + */ + +#ifndef LV_IMG_BUF_H +#define LV_IMG_BUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*If image pixels contains alpha we need to know how much byte is a pixel*/ +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 2 +#elif LV_COLOR_DEPTH == 16 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 3 +#elif LV_COLOR_DEPTH == 32 +#define LV_IMG_PX_SIZE_ALPHA_BYTE 4 +#endif + +#define LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) ((LV_COLOR_SIZE / 8) * w * h) +#define LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) (LV_IMG_PX_SIZE_ALPHA_BYTE * w * h) + +/*+ 1: to be sure no fractional row*/ +#define LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) ((((w / 8) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) ((((w / 4) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) ((((w / 2) + 1) * h)) +#define LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) ((w * h)) + +/*4 * X: for palette*/ +#define LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) + 4 * 2) +#define LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) + 4 * 4) +#define LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) + 4 * 16) +#define LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) (LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + 4 * 256) + +#define _LV_ZOOM_INV_UPSCALE 5 + +/********************** + * TYPEDEFS + **********************/ + +/*Image color format*/ +enum { + LV_IMG_CF_UNKNOWN = 0, + + LV_IMG_CF_RAW, /**< Contains the file as it is. Needs custom decoder function*/ + LV_IMG_CF_RAW_ALPHA, /**< Contains the file as it is. The image has alpha. Needs custom decoder + function*/ + LV_IMG_CF_RAW_CHROMA_KEYED, /**< Contains the file as it is. The image is chroma keyed. Needs + custom decoder function*/ + + LV_IMG_CF_TRUE_COLOR, /**< Color format and depth should match with LV_COLOR settings*/ + LV_IMG_CF_TRUE_COLOR_ALPHA, /**< Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/ + LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /**< Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels + will be transparent*/ + + LV_IMG_CF_INDEXED_1BIT, /**< Can have 2 different colors in a palette (can't be chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /**< Can have 4 different colors in a palette (can't be chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /**< Can have 16 different colors in a palette (can't be chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /**< Can have 256 different colors in a palette (can't be chroma keyed)*/ + + LV_IMG_CF_ALPHA_1BIT, /**< Can have one color and it can be drawn or not*/ + LV_IMG_CF_ALPHA_2BIT, /**< Can have one color but 4 different alpha value*/ + LV_IMG_CF_ALPHA_4BIT, /**< Can have one color but 16 different alpha value*/ + LV_IMG_CF_ALPHA_8BIT, /**< Can have one color but 256 different alpha value*/ + + LV_IMG_CF_RGB888, + LV_IMG_CF_RGBA8888, + LV_IMG_CF_RGBX8888, + LV_IMG_CF_RGB565, + LV_IMG_CF_RGBA5658, + LV_IMG_CF_RGB565A8, + + LV_IMG_CF_RESERVED_15, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_16, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_17, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_18, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_19, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_20, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_21, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_22, /**< Reserved for further use.*/ + LV_IMG_CF_RESERVED_23, /**< Reserved for further use.*/ + + LV_IMG_CF_USER_ENCODED_0, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_1, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_2, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_3, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_4, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_5, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_6, /**< User holder encoding format.*/ + LV_IMG_CF_USER_ENCODED_7, /**< User holder encoding format.*/ +}; +typedef uint8_t lv_img_cf_t; + + +/** + * The first 8 bit is very important to distinguish the different source types. + * For more info see `lv_img_get_src_type()` in lv_img.c + * On big endian systems the order is reversed so cf and always_zero must be at + * the end of the struct. + */ +#if LV_BIG_ENDIAN_SYSTEM +typedef struct { + + uint32_t h : 11; /*Height of the image map*/ + uint32_t w : 11; /*Width of the image map*/ + uint32_t reserved : 2; /*Reserved to be used later*/ + uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a + non-printable character*/ + uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/ + +} lv_img_header_t; +#else +typedef struct { + + uint32_t cf : 5; /*Color format: See `lv_img_color_format_t`*/ + uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a + non-printable character*/ + + uint32_t reserved : 2; /*Reserved to be used later*/ + + uint32_t w : 11; /*Width of the image map*/ + uint32_t h : 11; /*Height of the image map*/ +} lv_img_header_t; +#endif + +/** Image header it is compatible with + * the result from image converter utility*/ +typedef struct { + lv_img_header_t header; /**< A header describing the basics of the image*/ + uint32_t data_size; /**< Size of the image in bytes*/ + const uint8_t * data; /**< Pointer to the data of the image*/ +} lv_img_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Allocate an image buffer in RAM + * @param w width of image + * @param h height of image + * @param cf a color format (`LV_IMG_CF_...`) + * @return an allocated image, or NULL on failure + */ +lv_img_dsc_t * lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Get the color of an image's pixel + * @param dsc an image descriptor + * @param x x coordinate of the point to get + * @param y x coordinate of the point to get + * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used. + * Not used in other cases. + * @param safe true: check out of bounds + * @return color of the point + */ +lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color); + +/** + * Get the alpha value of an image's pixel + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param safe true: check out of bounds + * @return alpha value of the point + */ +lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y); + +/** + * Set the color of a pixel of an image. The alpha channel won't be affected. + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the point + * @param safe true: check out of bounds + */ +void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set the alpha value of a pixel of an image. The color won't be affected + * @param dsc pointer to an image descriptor + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param opa the desired opacity + * @param safe true: check out of bounds + */ +void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa); + +/** + * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` + * @param dsc pointer to an image descriptor + * @param id the palette color to set: + * - for `LV_IMG_CF_INDEXED1`: 0..1 + * - for `LV_IMG_CF_INDEXED2`: 0..3 + * - for `LV_IMG_CF_INDEXED4`: 0..15 + * - for `LV_IMG_CF_INDEXED8`: 0..255 + * @param c the color to set + */ +void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c); + +/** + * Free an allocated image buffer + * @param dsc image buffer to free + */ +void lv_img_buf_free(lv_img_dsc_t * dsc); + +/** + * Get the memory consumption of a raw bitmap, given color format and dimensions. + * @param w width + * @param h height + * @param cf color format + * @return size in bytes + */ +uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Get the area of a rectangle if its rotated and scaled + * @param res store the coordinates here + * @param w width of the rectangle to transform + * @param h height of the rectangle to transform + * @param angle angle of rotation + * @param zoom zoom, (256 no zoom) + * @param pivot x,y pivot coordinates of rotation + */ +void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t h, int16_t angle, uint16_t zoom, + const lv_point_t * pivot); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMG_BUF_H*/ diff --git a/include/liblvgl/draw/lv_img_cache.h b/include/liblvgl/draw/lv_img_cache.h new file mode 100644 index 0000000..dc0c5d9 --- /dev/null +++ b/include/liblvgl/draw/lv_img_cache.h @@ -0,0 +1,78 @@ +/** + * @file lv_img_cache.h + * + */ + +#ifndef LV_IMG_CACHE_H +#define LV_IMG_CACHE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_img_decoder.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * When loading images from the network it can take a long time to download and decode the image. + * + * To avoid repeating this heavy load images can be cached. + */ +typedef struct { + lv_img_decoder_dsc_t dec_dsc; /**< Image information*/ + + /** Count the cache entries's life. Add `time_to_open` to `life` when the entry is used. + * Decrement all lifes by one every in every ::lv_img_cache_open. + * If life == 0 the entry can be reused*/ + int32_t life; +} _lv_img_cache_entry_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Open an image using the image decoder interface and cache it. + * The image will be left open meaning if the image decoder open callback allocated memory then it will remain. + * The image is closed if a new image is opened and the new image takes its place in the cache. + * @param src source of the image. Path to file or pointer to an `lv_img_dsc_t` variable + * @param color The color of the image with `LV_IMG_CF_ALPHA_...` + * @param frame_id the index of the frame. Used only with animated images, set 0 for normal images + * @return pointer to the cache entry or NULL if can open the image + */ +_lv_img_cache_entry_t * _lv_img_cache_open(const void * src, lv_color_t color, int32_t frame_id); + +/** + * Set the number of images to be cached. + * More cached images mean more opened image at same time which might mean more memory usage. + * E.g. if 20 PNG or JPG images are open in the RAM they consume memory while opened in the cache. + * @param new_entry_cnt number of image to cache + */ +void lv_img_cache_set_size(uint16_t new_slot_num); + +/** + * Invalidate an image source in the cache. + * Useful if the image source is updated therefore it needs to be cached again. + * @param src an image source path to a file or pointer to an `lv_img_dsc_t` variable. + */ +void lv_img_cache_invalidate_src(const void * src); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMG_CACHE_H*/ diff --git a/include/liblvgl/draw/lv_img_decoder.h b/include/liblvgl/draw/lv_img_decoder.h new file mode 100644 index 0000000..c0c5860 --- /dev/null +++ b/include/liblvgl/draw/lv_img_decoder.h @@ -0,0 +1,274 @@ +/** + * @file lv_img_decoder.h + * + */ + +#ifndef LV_IMG_DECODER_H +#define LV_IMG_DECODER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include "lv_img_buf.h" +#include "liblvgl/misc/lv_fs.h" +#include "liblvgl/misc/lv_types.h" +#include "liblvgl/misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Source of image.*/ +enum { + LV_IMG_SRC_VARIABLE, /** Binary/C variable*/ + LV_IMG_SRC_FILE, /** File in filesystem*/ + LV_IMG_SRC_SYMBOL, /** Symbol (@ref lv_symbol_def.h)*/ + LV_IMG_SRC_UNKNOWN, /** Unknown source*/ +}; + +typedef uint8_t lv_img_src_t; + +/*Decoder function definitions*/ +struct _lv_img_decoder_dsc_t; +struct _lv_img_decoder_t; + +/** + * Get info from an image and store in the `header` + * @param src the image source. Can be a pointer to a C array or a file name (Use + * `lv_img_src_get_type` to determine the type) + * @param header store the info here + * @return LV_RES_OK: info written correctly; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_info_f_t)(struct _lv_img_decoder_t * decoder, const void * src, + lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @param decoder pointer to the decoder the function associated with + * @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it. + */ +typedef lv_res_t (*lv_img_decoder_open_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param decoder pointer to the decoder the function associated with + * @param dsc pointer to decoder descriptor + * @param x start x coordinate + * @param y start y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +typedef lv_res_t (*lv_img_decoder_read_line_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc, + lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + * @param decoder pointer to the decoder the function associated with + * @param dsc pointer to decoder descriptor + */ +typedef void (*lv_img_decoder_close_f_t)(struct _lv_img_decoder_t * decoder, struct _lv_img_decoder_dsc_t * dsc); + + +typedef struct _lv_img_decoder_t { + lv_img_decoder_info_f_t info_cb; + lv_img_decoder_open_f_t open_cb; + lv_img_decoder_read_line_f_t read_line_cb; + lv_img_decoder_close_f_t close_cb; + +#if LV_USE_USER_DATA + void * user_data; +#endif +} lv_img_decoder_t; + + +/**Describe an image decoding session. Stores data about the decoding*/ +typedef struct _lv_img_decoder_dsc_t { + /**The decoder which was able to open the image source*/ + lv_img_decoder_t * decoder; + + /**The image source. A file path like "S:my_img.png" or pointer to an `lv_img_dsc_t` variable*/ + const void * src; + + /**Color to draw the image. USed when the image has alpha channel only*/ + lv_color_t color; + + /**Frame of the image, using with animated images*/ + int32_t frame_id; + + /**Type of the source: file or variable. Can be set in `open` function if required*/ + lv_img_src_t src_type; + + /**Info about the opened image: color format, size, etc. MUST be set in `open` function*/ + lv_img_header_t header; + + /** Pointer to a buffer where the image's data (pixels) are stored in a decoded, plain format. + * MUST be set in `open` function*/ + const uint8_t * img_data; + + /** How much time did it take to open the image. [ms] + * If not set `lv_img_cache` will measure and set the time to open*/ + uint32_t time_to_open; + + /**A text to display instead of the image when the image can't be opened. + * Can be set in `open` function or set NULL.*/ + const char * error_msg; + + /**Store any custom data here is required*/ + void * user_data; +} lv_img_decoder_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the image decoder module + */ +void _lv_img_decoder_init(void); + +/** + * Get information about an image. + * Try the created image decoder one by one. Once one is able to get info that info will be used. + * @param src the image source. Can be + * 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_drv_register()`) + * 2) Variable: Pointer to an `lv_img_dsc_t` variable + * 3) Symbol: E.g. `LV_SYMBOL_OK` + * @param header the image info will be stored here + * @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image + */ +lv_res_t lv_img_decoder_get_info(const void * src, lv_img_header_t * header); + +/** + * Open an image. + * Try the created image decoders one by one. Once one is able to open the image that decoder is saved in `dsc` + * @param dsc describes a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable. + * @param src the image source. Can be + * 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_drv_register())`) + * 2) Variable: Pointer to an `lv_img_dsc_t` variable + * 3) Symbol: E.g. `LV_SYMBOL_OK` + * @param color The color of the image with `LV_IMG_CF_ALPHA_...` + * @param frame_id the index of the frame. Used only with animated images, set 0 for normal images + * @return LV_RES_OK: opened the image. `dsc->img_data` and `dsc->header` are set. + * LV_RES_INV: none of the registered image decoders were able to open the image. + */ +lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id); + +/** + * Read a line from an opened image + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + * @param x start X coordinate (from left) + * @param y start Y coordinate (from top) + * @param len number of pixels to read + * @param buf store the data here + * @return LV_RES_OK: success; LV_RES_INV: an error occurred + */ +lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, + uint8_t * buf); + +/** + * Close a decoding session + * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open` + */ +void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc); + +/** + * Create a new image decoder + * @return pointer to the new image decoder + */ +lv_img_decoder_t * lv_img_decoder_create(void); + +/** + * Delete an image decoder + * @param decoder pointer to an image decoder + */ +void lv_img_decoder_delete(lv_img_decoder_t * decoder); + +/** + * Set a callback to get information about the image + * @param decoder pointer to an image decoder + * @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct) + */ +void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb); + +/** + * Set a callback to open an image + * @param decoder pointer to an image decoder + * @param open_cb a function to open an image + */ +void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb); + +/** + * Set a callback to a decoded line of an image + * @param decoder pointer to an image decoder + * @param read_line_cb a function to read a line of an image + */ +void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb); + +/** + * Set a callback to close a decoding session. E.g. close files and free other resources. + * @param decoder pointer to an image decoder + * @param close_cb a function to close a decoding session + */ +void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb); + +/** + * Get info about a built-in image + * @param decoder the decoder where this function belongs + * @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol + * @param header store the image data here + * @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error. + */ +lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header); + +/** + * Open a built in image + * @param decoder the decoder where this function belongs + * @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it. + * @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error. + */ +lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); + +/** + * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`. + * Required only if the "open" function can't return with the whole decoded pixel array. + * @param decoder pointer to the decoder the function associated with + * @param dsc pointer to decoder descriptor + * @param x start x coordinate + * @param y start y coordinate + * @param len number of pixels to decode + * @param buf a buffer to store the decoded pixels + * @return LV_RES_OK: ok; LV_RES_INV: failed + */ +lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x, + lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + * @param decoder pointer to the decoder the function associated with + * @param dsc pointer to decoder descriptor + */ +void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMG_DECODER_H*/ diff --git a/include/liblvgl/draw/nxp/lv_gpu_nxp.h b/include/liblvgl/draw/nxp/lv_gpu_nxp.h new file mode 100644 index 0000000..853da56 --- /dev/null +++ b/include/liblvgl/draw/nxp/lv_gpu_nxp.h @@ -0,0 +1,71 @@ +/** + * @file lv_gpu_nxp.h + * + */ + +/** + * MIT License + * + * Copyright 2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_GPU_NXP_H +#define LV_GPU_NXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" +#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE +#include "../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_nxp_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_nxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_nxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_NXP_H*/ diff --git a/include/liblvgl/draw/nxp/pxp/lv_draw_pxp_blend.h b/include/liblvgl/draw/nxp/pxp/lv_draw_pxp_blend.h new file mode 100644 index 0000000..acce871 --- /dev/null +++ b/include/liblvgl/draw/nxp/pxp/lv_draw_pxp_blend.h @@ -0,0 +1,143 @@ +/** + * @file lv_draw_pxp_blend.h + * + */ + +/** + * MIT License + * + * Copyright 2020-2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_PXP_BLEND_H +#define LV_DRAW_PXP_BLEND_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP +#include "lv_gpu_nxp_pxp.h" +#include "../../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +#ifndef LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT +/** Minimum area (in pixels) for image copy with 100% opacity to be handled by PXP*/ +#define LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT +/** Minimum area (in pixels) for image copy with transparency to be handled by PXP*/ +#define LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT +/** Minimum invalidated area (in pixels) to be synchronized by PXP during buffer sync */ +#define LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_PXP_FILL_SIZE_LIMIT +/** Minimum area (in pixels) to be filled by PXP with 100% opacity*/ +#define LV_GPU_NXP_PXP_FILL_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT +/** Minimum area (in pixels) to be filled by PXP with transparency*/ +#define LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Fill area, with optional opacity. + * + * @param[in/out] dest_buf destination buffer + * @param[in] dest_stride width (stride) of destination buffer in pixels + * @param[in] fill_area area to fill + * @param[in] color color + * @param[in] opa transparency of the color + * @retval LV_RES_OK Fill completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, + lv_color_t color, lv_opa_t opa); + +/** + * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. + * By default, image is copied directly, with optional opacity. This function can also + * rotate the display output buffer to a specified angle (90x step). + * + * @param[in/out] dest_buf destination buffer + * @param[in] dest_area destination area + * @param[in] dest_stride width (stride) of destination buffer in pixels + * @param[in] src_buf source buffer + * @param[in] src_area source area with absolute coordinates to draw on destination buffer + * @param[in] opa opacity of the result + * @param[in] angle display rotation angle (90x) + * @retval LV_RES_OK Fill completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle); + +/** + * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. + * + * + * @param[in/out] dest_buf destination buffer + * @param[in] dest_area destination area + * @param[in] dest_stride width (stride) of destination buffer in pixels + * @param[in] src_buf source buffer + * @param[in] src_area source area with absolute coordinates to draw on destination buffer + * @param[in] dsc image descriptor + * @param[in] cf color format + * @retval LV_RES_OK Fill completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_PXP*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_PXP_BLEND_H*/ diff --git a/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp.h b/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp.h new file mode 100644 index 0000000..aeb9d6c --- /dev/null +++ b/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp.h @@ -0,0 +1,153 @@ +/** + * @file lv_gpu_nxp_pxp.h + * + */ + +/** + * MIT License + * + * Copyright 2020-2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_GPU_NXP_PXP_H +#define LV_GPU_NXP_PXP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP +#include "fsl_cache.h" +#include "fsl_pxp.h" + +#include "../../../misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/** PXP module instance to use*/ +#define LV_GPU_NXP_PXP_ID PXP + +/** PXP interrupt line ID*/ +#define LV_GPU_NXP_PXP_IRQ_ID PXP_IRQn + +#ifndef LV_GPU_NXP_PXP_LOG_ERRORS +/** Enable logging of PXP errors (\see LV_LOG_ERROR)*/ +#define LV_GPU_NXP_PXP_LOG_ERRORS 1 +#endif + +#ifndef LV_GPU_NXP_PXP_LOG_TRACES +/** Enable logging of PXP errors (\see LV_LOG_ERROR)*/ +#define LV_GPU_NXP_PXP_LOG_TRACES 0 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/** + * NXP PXP device configuration - call-backs used for + * interrupt init/wait/deinit. + */ +typedef struct { + /** Callback for PXP interrupt initialization*/ + lv_res_t (*pxp_interrupt_init)(void); + + /** Callback for PXP interrupt de-initialization*/ + void (*pxp_interrupt_deinit)(void); + + /** Callback that should start PXP and wait for operation complete*/ + void (*pxp_run)(void); +} lv_nxp_pxp_cfg_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Reset and initialize PXP device. This function should be called as a part + * of display init sequence. + * + * @retval LV_RES_OK PXP init completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_pxp_init(void); + +/** + * Disable PXP device. Should be called during display deinit sequence. + */ +void lv_gpu_nxp_pxp_deinit(void); + +/** + * Start PXP job and wait for completion. + */ +void lv_gpu_nxp_pxp_run(void); + +/********************** + * MACROS + **********************/ + +#define PXP_COND_STOP(cond, txt) \ + do { \ + if (cond) { \ + LV_LOG_ERROR("%s. STOP!", txt); \ + for ( ; ; ); \ + } \ + } while(0) + +#if LV_GPU_NXP_PXP_LOG_ERRORS +#define PXP_RETURN_INV(fmt, ...) \ + do { \ + LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + return LV_RES_INV; \ + } while (0) +#else +#define PXP_RETURN_INV(fmt, ...) \ + do { \ + return LV_RES_INV; \ + }while(0) +#endif /*LV_GPU_NXP_PXP_LOG_ERRORS*/ + +#if LV_GPU_NXP_PXP_LOG_TRACES +#define PXP_LOG_TRACE(fmt, ...) \ + do { \ + LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + } while (0) +#else +#define PXP_LOG_TRACE(fmt, ...) \ + do { \ + } while (0) +#endif /*LV_GPU_NXP_PXP_LOG_TRACES*/ + +#endif /*LV_USE_GPU_NXP_PXP*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_NXP_PXP_H*/ diff --git a/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.h b/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.h new file mode 100644 index 0000000..d907447 --- /dev/null +++ b/include/liblvgl/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.h @@ -0,0 +1,78 @@ +/** + * @file lv_gpu_nxp_pxp_osa.h + * + */ + +/** + * MIT License + * + * Copyright 2020, 2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_GPU_NXP_PXP_OSA_H +#define LV_GPU_NXP_PXP_OSA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT +#include "lv_gpu_nxp_pxp.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * PXP device interrupt handler. Used to check PXP task completion status. + */ +void PXP_IRQHandler(void); + +/** + * Helper function to get the PXP default configuration. + */ +lv_nxp_pxp_cfg_t * lv_gpu_nxp_pxp_get_cfg(void); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_NXP_PXP_OSA_H*/ diff --git a/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_arc.h b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_arc.h new file mode 100644 index 0000000..e2da419 --- /dev/null +++ b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_arc.h @@ -0,0 +1,79 @@ +/** + * @file lv_draw_vglite_arc.h + * + */ + +/** + * MIT License + * + * Copyright 2021, 2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_VGLITE_ARC_H +#define LV_DRAW_VGLITE_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_gpu_nxp_vglite.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*** + * Draw arc shape with effects + * @param draw_ctx drawing context + * @param dsc the arc description structure (width, rounded ending, opacity) + * @param center the coordinates of the arc center + * @param radius the radius of external arc + * @param start_angle the starting angle in degrees + * @param end_angle the ending angle in degrees + */ +lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + int32_t radius, int32_t start_angle, int32_t end_angle); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_ARC_H*/ diff --git a/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_blend.h b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_blend.h new file mode 100644 index 0000000..1726dcd --- /dev/null +++ b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_blend.h @@ -0,0 +1,149 @@ +/** + * @file lv_draw_vglite_blend.h + * + */ + +/** + * MIT License + * + * Copyright 2020-2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_VGLITE_BLEND_H +#define LV_DRAW_VGLITE_BLEND_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_gpu_nxp_vglite.h" + +/********************* + * DEFINES + *********************/ + +#ifndef LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT +/** Minimum area (in pixels) to be filled by VG-Lite with 100% opacity*/ +#define LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT +/** Minimum area (in pixels) to be filled by VG-Lite with transparency*/ +#define LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT +/** Minimum area (in pixels) for image copy with 100% opacity to be handled by VG-Lite*/ +#define LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT +/** Minimum invalidated area (in pixels) to be synchronized by VG-Lite during buffer sync */ +#define LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 +#endif + +#ifndef LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT +/** Minimum area (in pixels) for image copy with transparency to be handled by VG-Lite*/ +#define LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/** + * BLock Image Transfer descriptor structure + */ +typedef struct { + + const lv_color_t * src; /**< Source buffer pointer (must be aligned on 32 bytes)*/ + lv_area_t src_area; /**< Area to be copied from source*/ + lv_coord_t src_width; /**< Source buffer width*/ + lv_coord_t src_height; /**< Source buffer height*/ + int32_t src_stride; /**< Source buffer stride in bytes (must be aligned on 16 px)*/ + + const lv_color_t * dst; /**< Destination buffer pointer (must be aligned on 32 bytes)*/ + lv_area_t dst_area; /**< Target area in destination buffer (must be the same as src_area)*/ + lv_coord_t dst_width; /**< Destination buffer width*/ + lv_coord_t dst_height; /**< Destination buffer height*/ + int32_t dst_stride; /**< Destination buffer stride in bytes (must be aligned on 16 px)*/ + + lv_opa_t opa; /**< Opacity - alpha mix (0 = source not copied, 255 = 100% opaque)*/ + uint32_t angle; /**< Rotation angle (1/10 of degree)*/ + uint32_t zoom; /**< 256 = no zoom (1:1 scale ratio)*/ + lv_point_t pivot; /**< The coordinates of rotation pivot in source image buffer*/ +} lv_gpu_nxp_vglite_blit_info_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Fill area, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer pointer (must be aligned on 32 bytes) + * @param[in] dest_width Destination buffer width in pixels (must be aligned on 16 px) + * @param[in] dest_height Destination buffer height in pixels + * @param[in] fill_area Area to be filled + * @param[in] color Fill color + * @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill) + * @retval LV_RES_OK Fill completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, + const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa); + +/** + * BLock Image Transfer. + * + * @param[in] blit Description of the transfer + * @retval LV_RES_OK Transfer complete + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit); + +/** + * BLock Image Transfer with transformation. + * + * @param[in] blit Description of the transfer + * @retval LV_RES_OK Transfer complete + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_BLEND_H*/ diff --git a/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_rect.h b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_rect.h new file mode 100644 index 0000000..8a64170 --- /dev/null +++ b/include/liblvgl/draw/nxp/vglite/lv_draw_vglite_rect.h @@ -0,0 +1,77 @@ +/** + * @file lv_draw_vglite_rect.h + * + */ + +/** + * MIT License + * + * Copyright 2021, 2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_DRAW_VGLITE_RECT_H +#define LV_DRAW_VGLITE_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_gpu_nxp_vglite.h" +#include "../../lv_draw_rect.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw rectangle shape with effects (rounded corners, gradient) + * + * @param draw_ctx drawing context + * @param dsc description of the rectangle + * @param coords the area where rectangle is clipped + */ +lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_RECT_H*/ diff --git a/include/liblvgl/draw/nxp/vglite/lv_gpu_nxp_vglite.h b/include/liblvgl/draw/nxp/vglite/lv_gpu_nxp_vglite.h new file mode 100644 index 0000000..8754492 --- /dev/null +++ b/include/liblvgl/draw/nxp/vglite/lv_gpu_nxp_vglite.h @@ -0,0 +1,185 @@ +/** + * @file lv_gpu_nxp_vglite.h + * + */ + +/** + * MIT License + * + * Copyright 2020-2022 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_GPU_NXP_VGLITE_H +#define LV_GPU_NXP_VGLITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "vg_lite.h" +#include "../../sw/lv_draw_sw.h" +#include "../../../misc/lv_log.h" +#include "fsl_debug_console.h" + +/********************* + * DEFINES + *********************/ + +/** Use this symbol as limit to disable feature (value has to be larger than supported resolution) */ +#define LV_GPU_NXP_VG_LITE_FEATURE_DISABLED (1920*1080+1) + +/** Stride in px required by VG-Lite HW. Don't change this. */ +#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U + +#ifndef LV_GPU_NXP_VG_LITE_LOG_ERRORS +/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ +#define LV_GPU_NXP_VG_LITE_LOG_ERRORS 1 +#endif + +#ifndef LV_GPU_NXP_VG_LITE_LOG_TRACES +/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ +#define LV_GPU_NXP_VG_LITE_LOG_TRACES 0 +#endif + +/* Draw rectangles around BLIT tiles */ +#define BLIT_DBG_AREAS 0 + +/* Print detailed info to SDK console (NOT to LVGL log system) */ +#define BLIT_DBG_VERBOSE 0 + +/* Verbose debug print */ +#if BLIT_DBG_VERBOSE +#define PRINT_BLT PRINTF +#else +#define PRINT_BLT(...) +#endif + +/* The optimal Bezier control point offset for radial unit + * see: https://spencermortensen.com/articles/bezier-circle/ + **/ +#define BEZIER_OPTIM_CIRCLE 0.551915024494f + +/* Draw lines for control points of Bezier curves */ +#define BEZIER_DBG_CONTROL_POINTS 0 + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Fills vg_lite_buffer_t structure according given parameters. + * + * @param[in/out] vgbuf Buffer structure to be filled + * @param[in] width Width of buffer in pixels + * @param[in] height Height of buffer in pixels + * @param[in] stride Stride of the buffer in bytes + * @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements) + * @param[in] source Boolean to check if this is a source buffer + */ +lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride, + const lv_color_t * ptr, bool source); + +#if BLIT_DBG_AREAS +/** + * Draw a simple rectangle, 1 px line width. + * + * @param dest_buf Destination buffer + * @param dest_width Destination buffer width (must be aligned on 16px) + * @param dest_height Destination buffer height + * @param fill_area Rectangle coordinates + * @param color Rectangle color + */ +void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, + lv_area_t * fill_area, lv_color_t color); +#endif + +/** + * Clean & invalidate cache. + */ +void lv_vglite_invalidate_cache(void); + +/********************** + * MACROS + **********************/ + +#define VG_LITE_COND_STOP(cond, txt) \ + do { \ + if (cond) { \ + LV_LOG_ERROR("%s. STOP!", txt); \ + for ( ; ; ); \ + } \ + } while(0) + +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS +#define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \ + do { \ + if(err != VG_LITE_SUCCESS) { \ + LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + return LV_RES_INV; \ + } \ + } while (0) +#else +#define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \ + do { \ + if(err != VG_LITE_SUCCESS) { \ + return LV_RES_INV; \ + } \ + }while(0) +#endif /*LV_GPU_NXP_VG_LITE_LOG_ERRORS*/ + +#if LV_GPU_NXP_VG_LITE_LOG_TRACES +#define VG_LITE_LOG_TRACE(fmt, ...) \ + do { \ + LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + } while (0) + +#define VG_LITE_RETURN_INV(fmt, ...) \ + do { \ + LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + return LV_RES_INV; \ + } while (0) +#else +#define VG_LITE_LOG_TRACE(fmt, ...) \ + do { \ + } while (0) +#define VG_LITE_RETURN_INV(fmt, ...) \ + do { \ + return LV_RES_INV; \ + }while(0) +#endif /*LV_GPU_NXP_VG_LITE_LOG_TRACES*/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_NXP_VGLITE_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl.h b/include/liblvgl/draw/sdl/lv_draw_sdl.h new file mode 100644 index 0000000..7708d5b --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_sdl.h + * + */ + +#ifndef LV_DRAW_SDL_H +#define LV_DRAW_SDL_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" +#include "../../core/lv_disp.h" + +/********************* + * DEFINES + *********************/ + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_ARGB8888 +#else +#define LV_DRAW_SDL_TEXTURE_FORMAT SDL_PIXELFORMAT_RGBA8888 +#endif + +/********************** + * TYPEDEFS + **********************/ + +struct lv_draw_sdl_context_internals_t; + +typedef struct { + /** + * Render for display driver + */ + SDL_Renderer * renderer; + void * user_data; +} lv_draw_sdl_drv_param_t; + +typedef struct { + lv_draw_ctx_t base_draw; + SDL_Renderer * renderer; + struct lv_draw_sdl_context_internals_t * internals; +} lv_draw_sdl_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + +/** + * @brief Free caches + * + */ +void lv_draw_sdl_deinit_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + +SDL_Texture * lv_draw_sdl_create_screen_texture(SDL_Renderer * renderer, lv_coord_t hor, lv_coord_t ver); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_composite.h b/include/liblvgl/draw/sdl/lv_draw_sdl_composite.h new file mode 100644 index 0000000..3a598d7 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_composite.h @@ -0,0 +1,73 @@ +/** + * @file lv_draw_sdl_composite.h + * + */ + +#ifndef LV_DRAW_SDL_COMPOSITE_H +#define LV_DRAW_SDL_COMPOSITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "lv_draw_sdl.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef enum lv_draw_sdl_composite_texture_id_t { + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET1, + LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0, +} lv_draw_sdl_composite_texture_id_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Begin drawing with mask. Render target will be switched to a temporary texture, + * and drawing coordinates may get clipped or translated + * @param coords_in Original coordinates + * @param clip_in Original clip area + * @param extension Useful for shadows or outlines, can be NULL + * @param coords_out Translated coords + * @param clip_out Translated clip area + * @param apply_area Area of actual composited texture will be drawn + * @return true if there are any mask needs to be drawn, false otherwise + */ +bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in, + const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out, + lv_area_t * clip_out, lv_area_t * apply_area); + +void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode); + +SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id, + lv_coord_t w, lv_coord_t h); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_COMPOSITE_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_img.h b/include/liblvgl/draw/sdl/lv_draw_sdl_img.h new file mode 100644 index 0000000..d6e3758 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_img.h @@ -0,0 +1,72 @@ +/** + * @file lv_draw_sdl_img.h + * + */ + +#ifndef LV_DRAW_SDL_IMG_H +#define LV_DRAW_SDL_IMG_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" + +#include "lv_draw_sdl_texture_cache.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct lv_draw_sdl_img_header_t { + lv_img_header_t base; + SDL_Rect rect; +} lv_draw_sdl_img_header_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ +bool lv_draw_sdl_img_load_texture(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_cache_key_head_img_t * key, size_t key_size, + const void * src, int32_t frame_id, SDL_Texture ** texture, + lv_draw_sdl_img_header_t ** header); +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_IMG_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_layer.h b/include/liblvgl/draw/sdl/lv_draw_sdl_layer.h new file mode 100644 index 0000000..b60303c --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_layer.h @@ -0,0 +1,55 @@ +/** + * @file lv_draw_sdl_refr.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_sdl.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct _lv_draw_sdl_layer_ctx_t { + lv_draw_layer_ctx_t base; + + SDL_Texture * orig_target; + SDL_Texture * target; + SDL_Rect target_rect; + lv_draw_layer_flags_t flags; +} lv_draw_sdl_layer_ctx_t; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_draw_layer_ctx_t * lv_draw_sdl_layer_init(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + +void lv_draw_sdl_layer_blend(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * transform_ctx, + const lv_draw_img_dsc_t * draw_dsc); + +void lv_draw_sdl_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx); + +void lv_draw_sdl_transform_areas_offset(lv_draw_sdl_ctx_t * ctx, bool has_composite, lv_area_t * apply_area, + lv_area_t * coords, lv_area_t * clip); +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_mask.h b/include/liblvgl/draw/sdl/lv_draw_sdl_mask.h new file mode 100644 index 0000000..aa4dd2b --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_mask.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_sdl_mask.h + * + */ + +#ifndef LV_DRAW_SDL_MASK_H +#define LV_DRAW_SDL_MASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "lv_draw_sdl.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_opa_t * lv_draw_sdl_mask_dump_opa(const lv_area_t * coords, const int16_t * ids, int16_t ids_count); + +SDL_Texture * lv_draw_sdl_mask_dump_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, + int16_t ids_count); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_MASK_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_priv.h b/include/liblvgl/draw/sdl/lv_draw_sdl_priv.h new file mode 100644 index 0000000..736fe89 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_priv.h @@ -0,0 +1,72 @@ +/** + * @file lv_draw_sdl_priv.h + * + */ + +#ifndef LV_DRAW_SDL_PRIV_H +#define LV_DRAW_SDL_PRIV_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" +#include "../../misc/lv_lru.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct lv_draw_sdl_context_internals_t { + lv_lru_t * texture_cache; + SDL_Texture * mask; + SDL_Texture * composition; + SDL_Texture * target_backup; + uint8_t transform_count; +} lv_draw_sdl_context_internals_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_PRIV_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_rect.h b/include/liblvgl/draw/sdl/lv_draw_sdl_rect.h new file mode 100644 index 0000000..fc96894 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_rect.h @@ -0,0 +1,75 @@ +/** + * @file lv_draw_sdl_rect.h + * + */ + +#ifndef LV_DRAW_SDL_RECT_H +#define LV_DRAW_SDL_RECT_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH + +#include "../lv_draw.h" + +#include "lv_draw_sdl_texture_cache.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct lv_draw_sdl_rect_header_t { + lv_img_header_t base; + SDL_Rect rect; +} lv_draw_sdl_rect_header_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius); + +void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size, + const lv_area_t * coords, const lv_area_t * clip, bool full); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_RECT_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_stack_blur.h b/include/liblvgl/draw/sdl/lv_draw_sdl_stack_blur.h new file mode 100644 index 0000000..3d854e3 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_stack_blur.h @@ -0,0 +1,46 @@ +/** + * @file lv_draw_sdl_stack_blur.h + * + */ +#ifndef LV_DRAW_SDL_STACK_BLUR_H +#define LV_DRAW_SDL_STACK_BLUR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include "../../misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_STACK_BLUR_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_texture_cache.h b/include/liblvgl/draw/sdl/lv_draw_sdl_texture_cache.h new file mode 100644 index 0000000..0b54246 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_texture_cache.h @@ -0,0 +1,102 @@ +/** + * @file lv_draw_sdl_texture_cache.h + * + */ + +#ifndef LV_DRAW_SDL_TEXTURE_CACHE_H +#define LV_DRAW_SDL_TEXTURE_CACHE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_GPU_SDL + +#include LV_GPU_SDL_INCLUDE_PATH +#include "lv_draw_sdl.h" +#include "lv_draw_sdl_priv.h" +#include "../../draw/lv_img_decoder.h" +#include "../../misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +#define LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD "@LVSDLTex" + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + char head[8]; + SDL_Texture * texture; + SDL_Rect rect; + bool texture_managed; + bool texture_referenced; +} lv_draw_sdl_dec_dsc_userdata_t; + +typedef enum { + LV_GPU_CACHE_KEY_MAGIC_ARC = 0x01, + LV_GPU_CACHE_KEY_MAGIC_IMG = 0x11, + LV_GPU_CACHE_KEY_MAGIC_IMG_ROUNDED_CORNERS = 0x12, + LV_GPU_CACHE_KEY_MAGIC_LINE = 0x21, + LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31, + LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32, + LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33, + LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH = 0x41, + LV_GPU_CACHE_KEY_MAGIC_MASK = 0x51, +} lv_sdl_cache_key_magic_t; + +typedef enum { + LV_DRAW_SDL_CACHE_FLAG_NONE = 0, + LV_DRAW_SDL_CACHE_FLAG_MANAGED = 1, +} lv_draw_sdl_cache_flag_t; + +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_img_src_t type; + int32_t frame_id; +} lv_draw_sdl_cache_key_head_img_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx); + +void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx); + +/** + * Find cached texture by key. The texture can be destroyed during usage. + */ +SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found); + +SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + bool * found, void ** userdata); + +void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture); + +void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, + SDL_Texture * texture, void * userdata, void userdata_free(void *), + lv_draw_sdl_cache_flag_t flags); + +lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id, + size_t * size); + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GPU_SDL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_TEXTURE_CACHE_H*/ diff --git a/include/liblvgl/draw/sdl/lv_draw_sdl_utils.h b/include/liblvgl/draw/sdl/lv_draw_sdl_utils.h new file mode 100644 index 0000000..943bda3 --- /dev/null +++ b/include/liblvgl/draw/sdl/lv_draw_sdl_utils.h @@ -0,0 +1,65 @@ +/** + * @file lv_draw_sdl_utils.h + * + */ +#ifndef LV_DRAW_SDL_UTILS_H +#define LV_DRAW_SDL_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" +#if LV_USE_GPU_SDL + +#include "lv_draw_sdl.h" +#include "../../misc/lv_color.h" +#include "../../misc/lv_area.h" + +#include LV_GPU_SDL_INCLUDE_PATH + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void _lv_draw_sdl_utils_init(); + +void _lv_draw_sdl_utils_deinit(); + +void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out); + +void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out); + +void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot); + +SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp); + +SDL_Surface * lv_sdl_create_opa_surface(lv_opa_t * opa, lv_coord_t width, lv_coord_t height, lv_coord_t stride); + +SDL_Texture * lv_sdl_create_opa_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width, + lv_coord_t height, lv_coord_t stride); + +void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SDL*/ +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SDL_UTILS_H*/ diff --git a/include/liblvgl/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h b/include/liblvgl/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h new file mode 100644 index 0000000..f2bcdbe --- /dev/null +++ b/include/liblvgl/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h @@ -0,0 +1,70 @@ +/** + * @file lv_gpu_stm32_dma2d.h + * + */ + +#ifndef LV_GPU_STM32_DMA2D_H +#define LV_GPU_STM32_DMA2D_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/hal/lv_hal_disp.h" +#include "liblvgl/draw/sw/lv_draw_sw.h" + +#if LV_USE_GPU_STM32_DMA2D + +/********************* + * DEFINES + *********************/ + +#define LV_DMA2D_ARGB8888 0 +#define LV_DMA2D_RGB888 1 +#define LV_DMA2D_RGB565 2 +#define LV_DMA2D_ARGB1555 3 +#define LV_DMA2D_ARGB4444 4 + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_stm32_dma2d_ctx_t; + +struct _lv_disp_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_draw_stm32_dma2d_init(void); + +void lv_draw_stm32_dma2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_stm32_dma2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, + void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, + void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); + +void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_STM32_DMA2D*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_STM32_DMA2D_H*/ diff --git a/include/liblvgl/draw/sw/lv_draw_sw.h b/include/liblvgl/draw/sw/lv_draw_sw.h new file mode 100644 index 0000000..4496612 --- /dev/null +++ b/include/liblvgl/draw/sw/lv_draw_sw.h @@ -0,0 +1,104 @@ +/** + * @file lv_draw_sw.h + * + */ + +#ifndef LV_DRAW_SW_H +#define LV_DRAW_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_sw_blend.h" +#include "liblvgl/draw/lv_draw.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/hal/lv_hal_disp.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_disp_drv_t; + +typedef struct { + lv_draw_ctx_t base_draw; + + /** Fill an area of the destination buffer with a color*/ + void (*blend)(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); +} lv_draw_sw_ctx_t; + +typedef struct { + lv_draw_layer_ctx_t base_draw; + + uint32_t buf_size_bytes: 31; + uint32_t has_alpha : 1; +} lv_draw_sw_layer_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_sw_init_ctx(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_sw_deinit_ctx(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_sw_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +void lv_draw_sw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, uint16_t radius, + uint16_t start_angle, uint16_t end_angle); + +void lv_draw_sw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +void lv_draw_sw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +void lv_draw_sw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t * dsc, const lv_point_t * pos_p, + uint32_t letter); + +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf); + +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_line(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, + const lv_point_t * point1, const lv_point_t * point2); + +void lv_draw_sw_polygon(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, + const lv_point_t * points, uint16_t point_cnt); + +void lv_draw_sw_buffer_copy(lv_draw_ctx_t * draw_ctx, + void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, + void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); + +void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf, + lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride, + const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf); + +struct _lv_draw_layer_ctx_t * lv_draw_sw_layer_create(struct _lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + +void lv_draw_sw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + lv_draw_layer_flags_t flags); + +void lv_draw_sw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx, + const lv_draw_img_dsc_t * draw_dsc); + +void lv_draw_sw_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx); + +/*********************** + * GLOBAL VARIABLES + ***********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SW_H*/ diff --git a/include/liblvgl/draw/sw/lv_draw_sw_blend.h b/include/liblvgl/draw/sw/lv_draw_sw_blend.h new file mode 100644 index 0000000..6fa859c --- /dev/null +++ b/include/liblvgl/draw/sw/lv_draw_sw_blend.h @@ -0,0 +1,69 @@ +/** + * @file lv_draw_sw_blend.h + * + */ + +#ifndef LV_DRAW_SW_BLEND_H +#define LV_DRAW_SW_BLEND_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_style.h" +#include "liblvgl/draw/lv_draw_mask.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + const lv_area_t * blend_area; /**< The area with absolute coordinates to draw on `draw_ctx->buf` + * will be clipped to `draw_ctx->clip_area` */ + const lv_color_t * src_buf; /**< Pointer to an image to blend. If set `fill_color` is ignored */ + lv_color_t color; /**< Fill color*/ + lv_opa_t * mask_buf; /**< NULL if ignored, or an alpha mask to apply on `blend_area`*/ + lv_draw_mask_res_t mask_res; /**< The result of the previous mask operation */ + const lv_area_t * mask_area; /**< The area of `mask_buf` with absolute coordinates*/ + lv_opa_t opa; /**< The overall opacity*/ + lv_blend_mode_t blend_mode; /**< E.g. LV_BLEND_MODE_ADDITIVE*/ +} lv_draw_sw_blend_dsc_t; + +struct _lv_draw_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Call the blend function of the `draw_ctx`. + * @param draw_ctx pointer to a draw context + * @param dsc pointer to an initialized blend descriptor + */ +void lv_draw_sw_blend(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/** + * The basic blend function used with software rendering. + * @param draw_ctx pointer to a draw context + * @param dsc pointer to an initialized blend descriptor + */ +LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_SW_BLEND_H*/ diff --git a/include/liblvgl/draw/sw/lv_draw_sw_dither.h b/include/liblvgl/draw/sw/lv_draw_sw_dither.h new file mode 100644 index 0000000..9785e18 --- /dev/null +++ b/include/liblvgl/draw/sw/lv_draw_sw_dither.h @@ -0,0 +1,70 @@ +/** + * @file lv_draw_sw_dither.h + * + */ + +#ifndef LV_DRAW_SW_DITHER_H +#define LV_DRAW_SW_DITHER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj_pos.h" + + +/********************* + * DEFINES + *********************/ +#if LV_COLOR_DEPTH < 32 && LV_DITHER_GRADIENT == 1 +#define _DITHER_GRADIENT 1 +#else +#define _DITHER_GRADIENT 0 +#endif + +/********************** + * TYPEDEFS + **********************/ +#if _DITHER_GRADIENT +/*A signed error color component*/ +typedef struct { + int8_t r, g, b; +} lv_scolor24_t; + +struct _lv_gradient_cache_t; +typedef void (*lv_dither_func_t)(struct _lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w); + +#endif + + +/********************** + * PROTOTYPES + **********************/ +#if LV_DRAW_COMPLEX +#if _DITHER_GRADIENT +LV_ATTRIBUTE_FAST_MEM void lv_dither_none(struct _lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w); + +LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(struct _lv_gradient_cache_t * grad, const lv_coord_t xs, + const lv_coord_t y, const lv_coord_t w); +LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(struct _lv_gradient_cache_t * grad, const lv_coord_t xs, + const lv_coord_t y, const lv_coord_t w); + +#if LV_DITHER_ERROR_DIFFUSION == 1 +LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(struct _lv_gradient_cache_t * grad, const lv_coord_t xs, + const lv_coord_t y, const lv_coord_t w); +LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_ver(struct _lv_gradient_cache_t * grad, const lv_coord_t xs, + const lv_coord_t y, const lv_coord_t w); +#endif /* LV_DITHER_ERROR_DIFFUSION */ + +#endif /* _DITHER_GRADIENT */ +#endif + + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/draw/sw/lv_draw_sw_gradient.h b/include/liblvgl/draw/sw/lv_draw_sw_gradient.h new file mode 100644 index 0000000..0860d50 --- /dev/null +++ b/include/liblvgl/draw/sw/lv_draw_sw_gradient.h @@ -0,0 +1,97 @@ +/** + * @file lv_draw_sw_gradient.h + * + */ + +#ifndef LV_DRAW_SW_GRADIENT_H +#define LV_DRAW_SW_GRADIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_style.h" +#include "lv_draw_sw_dither.h" + +/********************* + * DEFINES + *********************/ +#if LV_GRADIENT_MAX_STOPS < 2 +#error LVGL needs at least 2 stops for gradients. Please increase the LV_GRADIENT_MAX_STOPS +#endif + + +/********************** + * TYPEDEFS + **********************/ +#if _DITHER_GRADIENT +typedef lv_color32_t lv_grad_color_t; +#else +typedef lv_color_t lv_grad_color_t; +#endif + +/** To avoid recomputing gradient for each draw operation, + * it's possible to cache the computation in this structure instance. + * Whenever possible, this structure is reused instead of recomputing the gradient map */ +typedef struct _lv_gradient_cache_t { + uint32_t key; /**< A discriminating key that's built from the drawing operation. + * If the key does not match, the cache item is not used */ + uint32_t life : 30; /**< A life counter that's incremented on usage. Higher counter is + * less likely to be evicted from the cache */ + uint32_t filled : 1; /**< Used to skip dithering in it if already done */ + uint32_t not_cached: 1; /**< The cache was too small so this item is not managed by the cache*/ + lv_color_t * map; /**< The computed gradient low bitdepth color map, points into the + * cache's buffer, no free needed */ + lv_coord_t alloc_size; /**< The map allocated size in colors */ + lv_coord_t size; /**< The computed gradient color map size, in colors */ +#if _DITHER_GRADIENT + lv_color32_t * hmap; /**< If dithering, we need to store the current, high bitdepth gradient + * map too, points to the cache's buffer, no free needed */ +#if LV_DITHER_ERROR_DIFFUSION == 1 + lv_scolor24_t * error_acc; /**< Error diffusion dithering algorithm requires storing the last error + * drawn, points to the cache's buffer, no free needed */ + lv_coord_t w; /**< The error array width in pixels */ +#endif +#endif +} lv_grad_t; + + +/********************** + * PROTOTYPES + **********************/ +/** Compute the color in the given gradient and fraction + * Gradient are specified in a virtual [0-255] range, so this function scales the virtual range to the given range + * @param dsc The gradient descriptor to use + * @param range The range to use in computation. + * @param frac The current part used in the range. frac is in [0; range] + */ +LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_gradient_calculate(const lv_grad_dsc_t * dsc, lv_coord_t range, + lv_coord_t frac); + +/** + * Set the gradient cache size + * @param max_bytes Max cahce size + */ +void lv_gradient_set_cache_size(size_t max_bytes); + +/** Free the gradient cache */ +void lv_gradient_free_cache(void); + +/** Get a gradient cache from the given parameters */ +lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * gradient, lv_coord_t w, lv_coord_t h); + +/** + * Clean up the gradient item after it was get with `lv_grad_get_from_cache`. + * @param grad pointer to a gradient + */ +void lv_gradient_cleanup(lv_grad_t * grad); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_GRADIENT_H*/ diff --git a/include/liblvgl/draw/swm341_dma2d/lv_gpu_swm341_dma2d.h b/include/liblvgl/draw/swm341_dma2d/lv_gpu_swm341_dma2d.h new file mode 100644 index 0000000..baec7fe --- /dev/null +++ b/include/liblvgl/draw/swm341_dma2d/lv_gpu_swm341_dma2d.h @@ -0,0 +1,64 @@ +/** + * @file lv_gpu_swm341_dma2d.h + * + */ + +#ifndef LV_GPU_SWM341_DMA2D_H +#define LV_GPU_SWM341_DMA2D_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/hal/lv_hal_disp.h" +#include "liblvgl/draw/sw/lv_draw_sw.h" + +#if LV_USE_GPU_SWM341_DMA2D + +/********************* + * DEFINES + *********************/ + +#define LV_SWM341_DMA2D_ARGB8888 0 +#define LV_SWM341_DMA2D_RGB888 1 +#define LV_SWM341_DMA2D_RGB565 2 + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_swm341_dma2d_ctx_t; + +struct _lv_disp_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_draw_swm341_dma2d_init(void); + +void lv_draw_swm341_dma2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_swm341_dma2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_swm341_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +void lv_gpu_swm341_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_SWM341_DMA2D*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GPU_SWM341_DMA2D_H*/ diff --git a/include/liblvgl/extra/layouts/flex/lv_flex.h b/include/liblvgl/extra/layouts/flex/lv_flex.h new file mode 100644 index 0000000..d961961 --- /dev/null +++ b/include/liblvgl/extra/layouts/flex/lv_flex.h @@ -0,0 +1,152 @@ +/** + * @file lv_flex.h + * + */ + +#ifndef LV_FLEX_H +#define LV_FLEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#if LV_USE_FLEX + +/********************* + * DEFINES + *********************/ + +#define LV_OBJ_FLAG_FLEX_IN_NEW_TRACK LV_OBJ_FLAG_LAYOUT_1 +LV_EXPORT_CONST_INT(LV_OBJ_FLAG_FLEX_IN_NEW_TRACK); + +#define _LV_FLEX_COLUMN (1 << 0) +#define _LV_FLEX_WRAP (1 << 2) +#define _LV_FLEX_REVERSE (1 << 3) + +/********************** + * TYPEDEFS + **********************/ + +/*Can't include lv_obj.h because it includes this header file*/ +struct _lv_obj_t; + +typedef enum { + LV_FLEX_ALIGN_START, + LV_FLEX_ALIGN_END, + LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_SPACE_EVENLY, + LV_FLEX_ALIGN_SPACE_AROUND, + LV_FLEX_ALIGN_SPACE_BETWEEN, +} lv_flex_align_t; + +typedef enum { + LV_FLEX_FLOW_ROW = 0x00, + LV_FLEX_FLOW_COLUMN = _LV_FLEX_COLUMN, + LV_FLEX_FLOW_ROW_WRAP = LV_FLEX_FLOW_ROW | _LV_FLEX_WRAP, + LV_FLEX_FLOW_ROW_REVERSE = LV_FLEX_FLOW_ROW | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_ROW_WRAP_REVERSE = LV_FLEX_FLOW_ROW | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_COLUMN_WRAP = LV_FLEX_FLOW_COLUMN | _LV_FLEX_WRAP, + LV_FLEX_FLOW_COLUMN_REVERSE = LV_FLEX_FLOW_COLUMN | _LV_FLEX_REVERSE, + LV_FLEX_FLOW_COLUMN_WRAP_REVERSE = LV_FLEX_FLOW_COLUMN | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, +} lv_flex_flow_t; + +/********************** + * GLOBAL VARIABLES + **********************/ +extern uint16_t LV_LAYOUT_FLEX; +extern lv_style_prop_t LV_STYLE_FLEX_FLOW; +extern lv_style_prop_t LV_STYLE_FLEX_MAIN_PLACE; +extern lv_style_prop_t LV_STYLE_FLEX_CROSS_PLACE; +extern lv_style_prop_t LV_STYLE_FLEX_TRACK_PLACE; +extern lv_style_prop_t LV_STYLE_FLEX_GROW; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a flex layout the default values + * @param flex pointer to a flex layout descriptor + */ +void lv_flex_init(void); + +/** + * Set hot the item should flow + * @param flex pointer to a flex layout descriptor + * @param flow an element of `lv_flex_flow_t`. + */ +void lv_obj_set_flex_flow(lv_obj_t * obj, lv_flex_flow_t flow); + +/** + * Set how to place (where to align) the items and tracks + * @param flex pointer: to a flex layout descriptor + * @param main_place where to place the items on main axis (in their track). Any value of `lv_flex_align_t`. + * @param cross_place where to place the item in their track on the cross axis. `LV_FLEX_ALIGN_START/END/CENTER` + * @param track_place where to place the tracks in the cross direction. Any value of `lv_flex_align_t`. + */ +void lv_obj_set_flex_align(lv_obj_t * obj, lv_flex_align_t main_place, lv_flex_align_t cross_place, + lv_flex_align_t track_cross_place); + +/** + * Sets the width or height (on main axis) to grow the object in order fill the free space + * @param obj pointer to an object. The parent must have flex layout else nothing will happen. + * @param grow a value to set how much free space to take proportionally to other growing items. + */ +void lv_obj_set_flex_grow(lv_obj_t * obj, uint8_t grow); + +void lv_style_set_flex_flow(lv_style_t * style, lv_flex_flow_t value); +void lv_style_set_flex_main_place(lv_style_t * style, lv_flex_align_t value); +void lv_style_set_flex_cross_place(lv_style_t * style, lv_flex_align_t value); +void lv_style_set_flex_track_place(lv_style_t * style, lv_flex_align_t value); +void lv_style_set_flex_grow(lv_style_t * style, uint8_t value); +void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector); +void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_flex_cross_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_flex_track_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_flex_grow(lv_obj_t * obj, uint8_t value, lv_style_selector_t selector); + +static inline lv_flex_flow_t lv_obj_get_style_flex_flow(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_FLOW); + return (lv_flex_flow_t)v.num; +} + +static inline lv_flex_align_t lv_obj_get_style_flex_main_place(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_MAIN_PLACE); + return (lv_flex_align_t)v.num; +} + +static inline lv_flex_align_t lv_obj_get_style_flex_cross_place(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_CROSS_PLACE); + return (lv_flex_align_t)v.num; +} + +static inline lv_flex_align_t lv_obj_get_style_flex_track_place(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_TRACK_PLACE); + return (lv_flex_align_t)v.num; +} + +static inline uint8_t lv_obj_get_style_flex_grow(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_FLEX_GROW); + return (uint8_t)v.num; +} + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_FLEX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FLEX_H*/ diff --git a/include/liblvgl/extra/layouts/grid/lv_grid.h b/include/liblvgl/extra/layouts/grid/lv_grid.h new file mode 100644 index 0000000..8e57fd9 --- /dev/null +++ b/include/liblvgl/extra/layouts/grid/lv_grid.h @@ -0,0 +1,194 @@ +/** + * @file lv_grid.h + * + */ + +#ifndef LV_GRID_H +#define LV_GRID_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#if LV_USE_GRID + +/********************* + * DEFINES + *********************/ +/** + * Can be used track size to make the track fill the free space. + * @param x how much space to take proportionally to other FR tracks + * @return a special track size + */ +#define LV_GRID_FR(x) (LV_COORD_MAX - 100 + x) + +#define LV_GRID_CONTENT (LV_COORD_MAX - 101) +LV_EXPORT_CONST_INT(LV_GRID_CONTENT); + +#define LV_GRID_TEMPLATE_LAST (LV_COORD_MAX) +LV_EXPORT_CONST_INT(LV_GRID_TEMPLATE_LAST); + +/********************** + * TYPEDEFS + **********************/ + +/*Can't include lv_obj.h because it includes this header file*/ +struct _lv_obj_t; + +typedef enum { + LV_GRID_ALIGN_START, + LV_GRID_ALIGN_CENTER, + LV_GRID_ALIGN_END, + LV_GRID_ALIGN_STRETCH, + LV_GRID_ALIGN_SPACE_EVENLY, + LV_GRID_ALIGN_SPACE_AROUND, + LV_GRID_ALIGN_SPACE_BETWEEN, +} lv_grid_align_t; + +/********************** + * GLOBAL VARIABLES + **********************/ + +extern uint16_t LV_LAYOUT_GRID; +extern lv_style_prop_t LV_STYLE_GRID_COLUMN_DSC_ARRAY; +extern lv_style_prop_t LV_STYLE_GRID_COLUMN_ALIGN; +extern lv_style_prop_t LV_STYLE_GRID_ROW_DSC_ARRAY; +extern lv_style_prop_t LV_STYLE_GRID_ROW_ALIGN; +extern lv_style_prop_t LV_STYLE_GRID_CELL_COLUMN_POS; +extern lv_style_prop_t LV_STYLE_GRID_CELL_COLUMN_SPAN; +extern lv_style_prop_t LV_STYLE_GRID_CELL_X_ALIGN; +extern lv_style_prop_t LV_STYLE_GRID_CELL_ROW_POS; +extern lv_style_prop_t LV_STYLE_GRID_CELL_ROW_SPAN; +extern lv_style_prop_t LV_STYLE_GRID_CELL_Y_ALIGN; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_grid_init(void); + +void lv_obj_set_grid_dsc_array(lv_obj_t * obj, const lv_coord_t col_dsc[], const lv_coord_t row_dsc[]); + +void lv_obj_set_grid_align(lv_obj_t * obj, lv_grid_align_t column_align, lv_grid_align_t row_align); + +/** + * Set the cell of an object. The object's parent needs to have grid layout, else nothing will happen + * @param obj pointer to an object + * @param column_align the vertical alignment in the cell. `LV_GRID_START/END/CENTER/STRETCH` + * @param col_pos column ID + * @param col_span number of columns to take (>= 1) + * @param row_align the horizontal alignment in the cell. `LV_GRID_START/END/CENTER/STRETCH` + * @param row_pos row ID + * @param row_span number of rows to take (>= 1) + */ +void lv_obj_set_grid_cell(lv_obj_t * obj, lv_grid_align_t column_align, uint8_t col_pos, uint8_t col_span, + lv_grid_align_t row_align, uint8_t row_pos, uint8_t row_span); + +/** + * Just a wrapper to `LV_GRID_FR` for bindings. + */ +static inline lv_coord_t lv_grid_fr(uint8_t x) +{ + return LV_GRID_FR(x); +} + +void lv_style_set_grid_row_dsc_array(lv_style_t * style, const lv_coord_t value[]); +void lv_style_set_grid_column_dsc_array(lv_style_t * style, const lv_coord_t value[]); +void lv_style_set_grid_row_align(lv_style_t * style, lv_grid_align_t value); +void lv_style_set_grid_column_align(lv_style_t * style, lv_grid_align_t value); +void lv_style_set_grid_cell_column_pos(lv_style_t * style, lv_coord_t value); +void lv_style_set_grid_cell_column_span(lv_style_t * style, lv_coord_t value); +void lv_style_set_grid_cell_row_pos(lv_style_t * style, lv_coord_t value); +void lv_style_set_grid_cell_row_span(lv_style_t * style, lv_coord_t value); +void lv_style_set_grid_cell_x_align(lv_style_t * style, lv_coord_t value); +void lv_style_set_grid_cell_y_align(lv_style_t * style, lv_coord_t value); + +void lv_obj_set_style_grid_row_dsc_array(lv_obj_t * obj, const lv_coord_t value[], lv_style_selector_t selector); +void lv_obj_set_style_grid_column_dsc_array(lv_obj_t * obj, const lv_coord_t value[], lv_style_selector_t selector); +void lv_obj_set_style_grid_row_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_column_align(lv_obj_t * obj, lv_grid_align_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_column_pos(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_column_span(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_row_pos(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_row_span(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_x_align(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); +void lv_obj_set_style_grid_cell_y_align(lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector); + +static inline const lv_coord_t * lv_obj_get_style_grid_row_dsc_array(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_ROW_DSC_ARRAY); + return (const lv_coord_t *)v.ptr; +} + +static inline const lv_coord_t * lv_obj_get_style_grid_column_dsc_array(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_COLUMN_DSC_ARRAY); + return (const lv_coord_t *)v.ptr; +} + +static inline lv_grid_align_t lv_obj_get_style_grid_row_align(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_ROW_ALIGN); + return (lv_grid_align_t)v.num; +} + +static inline lv_grid_align_t lv_obj_get_style_grid_column_align(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_COLUMN_ALIGN); + return (lv_grid_align_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_column_pos(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_COLUMN_POS); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_column_span(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_COLUMN_SPAN); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_row_pos(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_ROW_POS); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_row_span(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_ROW_SPAN); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_x_align(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_X_ALIGN); + return (lv_coord_t)v.num; +} + +static inline lv_coord_t lv_obj_get_style_grid_cell_y_align(const lv_obj_t * obj, uint32_t part) +{ + lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_GRID_CELL_Y_ALIGN); + return (lv_coord_t)v.num; +} + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GRID*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GRID_H*/ diff --git a/include/liblvgl/extra/layouts/lv_layouts.h b/include/liblvgl/extra/layouts/lv_layouts.h new file mode 100644 index 0000000..9c1e958 --- /dev/null +++ b/include/liblvgl/extra/layouts/lv_layouts.h @@ -0,0 +1,44 @@ +/** + * @file lv_layouts.h + * + */ + +#ifndef LV_LAYOUTS_H +#define LV_LAYOUTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "flex/lv_flex.h" +#include "grid/lv_grid.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +#if LV_USE_LOG && LV_LOG_TRACE_LAYOUT +# define LV_TRACE_LAYOUT(...) LV_LOG_TRACE(__VA_ARGS__) +#else +# define LV_TRACE_LAYOUT(...) +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LAYOUTS_H*/ diff --git a/include/liblvgl/extra/libs/bmp/lv_bmp.h b/include/liblvgl/extra/libs/bmp/lv_bmp.h new file mode 100644 index 0000000..3d9e948 --- /dev/null +++ b/include/liblvgl/extra/libs/bmp/lv_bmp.h @@ -0,0 +1,42 @@ +/** + * @file lv_bmp.h + * + */ + +#ifndef LV_BMP_H +#define LV_BMP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#if LV_USE_BMP + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_bmp_init(void); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_BMP*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BMP_H*/ diff --git a/include/liblvgl/extra/libs/ffmpeg/lv_ffmpeg.h b/include/liblvgl/extra/libs/ffmpeg/lv_ffmpeg.h new file mode 100644 index 0000000..f3a365c --- /dev/null +++ b/include/liblvgl/extra/libs/ffmpeg/lv_ffmpeg.h @@ -0,0 +1,104 @@ +/** + * @file lv_ffmpeg.h + * + */ +#ifndef LV_FFMPEG_H +#define LV_FFMPEG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" +#if LV_USE_FFMPEG != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct ffmpeg_context_s; + +extern const lv_obj_class_t lv_ffmpeg_player_class; + +typedef struct { + lv_img_t img; + lv_timer_t * timer; + lv_img_dsc_t imgdsc; + bool auto_restart; + struct ffmpeg_context_s * ffmpeg_ctx; +} lv_ffmpeg_player_t; + +typedef enum { + LV_FFMPEG_PLAYER_CMD_START, + LV_FFMPEG_PLAYER_CMD_STOP, + LV_FFMPEG_PLAYER_CMD_PAUSE, + LV_FFMPEG_PLAYER_CMD_RESUME, + _LV_FFMPEG_PLAYER_CMD_LAST +} lv_ffmpeg_player_cmd_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register FFMPEG image decoder + */ +void lv_ffmpeg_init(void); + +/** + * Get the number of frames contained in the file + * @param path image or video file name + * @return Number of frames, less than 0 means failed + */ +int lv_ffmpeg_get_frame_num(const char * path); + +/** + * Create ffmpeg_player object + * @param parent pointer to an object, it will be the parent of the new player + * @return pointer to the created ffmpeg_player + */ +lv_obj_t * lv_ffmpeg_player_create(lv_obj_t * parent); + +/** + * Set the path of the file to be played + * @param obj pointer to a ffmpeg_player object + * @param path video file path + * @return LV_RES_OK: no error; LV_RES_INV: can't get the info. + */ +lv_res_t lv_ffmpeg_player_set_src(lv_obj_t * obj, const char * path); + +/** + * Set command control video player + * @param obj pointer to a ffmpeg_player object + * @param cmd control commands + */ +void lv_ffmpeg_player_set_cmd(lv_obj_t * obj, lv_ffmpeg_player_cmd_t cmd); + +/** + * Set the video to automatically replay + * @param obj pointer to a ffmpeg_player object + * @param en true: enable the auto restart + */ +void lv_ffmpeg_player_set_auto_restart(lv_obj_t * obj, bool en); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_FFMPEG*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FFMPEG_H*/ diff --git a/include/liblvgl/extra/libs/freetype/lv_freetype.h b/include/liblvgl/extra/libs/freetype/lv_freetype.h new file mode 100644 index 0000000..e576c2e --- /dev/null +++ b/include/liblvgl/extra/libs/freetype/lv_freetype.h @@ -0,0 +1,83 @@ +/** + * @file lv_freetype.h + * + */ +#ifndef LV_FREETYPE_H +#define LV_FREETYPE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" +#if LV_USE_FREETYPE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef enum { + FT_FONT_STYLE_NORMAL = 0, + FT_FONT_STYLE_ITALIC = 1 << 0, + FT_FONT_STYLE_BOLD = 1 << 1 +} LV_FT_FONT_STYLE; + +typedef struct { + const char * name; /* The name of the font file */ + const void * mem; /* The pointer of the font file */ + size_t mem_size; /* The size of the memory */ + lv_font_t * font; /* point to lvgl font */ + uint16_t weight; /* font size */ + uint16_t style; /* font style */ +} lv_ft_info_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * init freetype library + * @param max_faces Maximum number of opened FT_Face objects managed by this cache instance. Use 0 for defaults. + * @param max_sizes Maximum number of opened FT_Size objects managed by this cache instance. Use 0 for defaults. + * @param max_bytes Maximum number of bytes to use for cached data nodes. Use 0 for defaults. + * Note that this value does not account for managed FT_Face and FT_Size objects. + * @return true on success, otherwise false. + */ +bool lv_freetype_init(uint16_t max_faces, uint16_t max_sizes, uint32_t max_bytes); + +/** + * Destroy freetype library + */ +void lv_freetype_destroy(void); + +/** + * Creates a font with info parameter specified. + * @param info See lv_ft_info_t for details. + * when success, lv_ft_info_t->font point to the font you created. + * @return true on success, otherwise false. + */ +bool lv_ft_font_init(lv_ft_info_t * info); + +/** + * Destroy a font that has been created. + * @param font pointer to font. + */ +void lv_ft_font_destroy(lv_font_t * font); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_FREETYPE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_FREETYPE_H */ diff --git a/include/liblvgl/extra/libs/fsdrv/lv_fsdrv.h b/include/liblvgl/extra/libs/fsdrv/lv_fsdrv.h new file mode 100644 index 0000000..2b0adfd --- /dev/null +++ b/include/liblvgl/extra/libs/fsdrv/lv_fsdrv.h @@ -0,0 +1,55 @@ +/** + * @file lv_fsdrv.h + * + */ + +#ifndef LV_FSDRV_H +#define LV_FSDRV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_USE_FS_FATFS != '\0' +void lv_fs_fatfs_init(void); +#endif + +#if LV_USE_FS_STDIO != '\0' +void lv_fs_stdio_init(void); +#endif + +#if LV_USE_FS_POSIX != '\0' +void lv_fs_posix_init(void); +#endif + +#if LV_USE_FS_WIN32 != '\0' +void lv_fs_win32_init(void); +#endif + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FSDRV_H*/ + diff --git a/include/liblvgl/extra/libs/gif/gifdec.h b/include/liblvgl/extra/libs/gif/gifdec.h new file mode 100644 index 0000000..eaa4cad --- /dev/null +++ b/include/liblvgl/extra/libs/gif/gifdec.h @@ -0,0 +1,60 @@ +#ifndef GIFDEC_H +#define GIFDEC_H + +#include +#include "liblvgl/misc/lv_fs.h" + +#if LV_USE_GIF + +typedef struct gd_Palette { + int size; + uint8_t colors[0x100 * 3]; +} gd_Palette; + +typedef struct gd_GCE { + uint16_t delay; + uint8_t tindex; + uint8_t disposal; + int input; + int transparency; +} gd_GCE; + + + +typedef struct gd_GIF { + lv_fs_file_t fd; + const char * data; + uint8_t is_file; + uint32_t f_rw_p; + int32_t anim_start; + uint16_t width, height; + uint16_t depth; + uint16_t loop_count; + gd_GCE gce; + gd_Palette *palette; + gd_Palette lct, gct; + void (*plain_text)( + struct gd_GIF *gif, uint16_t tx, uint16_t ty, + uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch, + uint8_t fg, uint8_t bg + ); + void (*comment)(struct gd_GIF *gif); + void (*application)(struct gd_GIF *gif, char id[8], char auth[3]); + uint16_t fx, fy, fw, fh; + uint8_t bgindex; + uint8_t *canvas, *frame; +} gd_GIF; + +gd_GIF * gd_open_gif_file(const char *fname); + +gd_GIF * gd_open_gif_data(const void *data); + +void gd_render_frame(gd_GIF *gif, uint8_t *buffer); + +int gd_get_frame(gd_GIF *gif); +void gd_rewind(gd_GIF *gif); +void gd_close_gif(gd_GIF *gif); + +#endif /*LV_USE_GIF*/ + +#endif /* GIFDEC_H */ diff --git a/include/liblvgl/extra/libs/gif/lv_gif.h b/include/liblvgl/extra/libs/gif/lv_gif.h new file mode 100644 index 0000000..b40b690 --- /dev/null +++ b/include/liblvgl/extra/libs/gif/lv_gif.h @@ -0,0 +1,58 @@ +/** + * @file lv_gif.h + * + */ + +#ifndef LV_GIF_H +#define LV_GIF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lvgl.h" +#if LV_USE_GIF + +#include "gifdec.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_img_t img; + gd_GIF * gif; + lv_timer_t * timer; + lv_img_dsc_t imgdsc; + uint32_t last_call; +} lv_gif_t; + +extern const lv_obj_class_t lv_gif_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_gif_create(lv_obj_t * parent); +void lv_gif_set_src(lv_obj_t * obj, const void * src); +void lv_gif_restart(lv_obj_t * gif); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GIF*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GIF_H*/ diff --git a/include/liblvgl/extra/libs/lv_libs.h b/include/liblvgl/extra/libs/lv_libs.h new file mode 100644 index 0000000..6782b1d --- /dev/null +++ b/include/liblvgl/extra/libs/lv_libs.h @@ -0,0 +1,46 @@ +/** + * @file lv_libs.h + * + */ + +#ifndef LV_LIBS_H +#define LV_LIBS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "bmp/lv_bmp.h" +#include "fsdrv/lv_fsdrv.h" +#include "png/lv_png.h" +#include "gif/lv_gif.h" +#include "qrcode/lv_qrcode.h" +#include "sjpg/lv_sjpg.h" +#include "freetype/lv_freetype.h" +#include "rlottie/lv_rlottie.h" +#include "ffmpeg/lv_ffmpeg.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LIBS_H*/ diff --git a/include/liblvgl/extra/libs/png/lodepng.h b/include/liblvgl/extra/libs/png/lodepng.h new file mode 100644 index 0000000..4068d4b --- /dev/null +++ b/include/liblvgl/extra/libs/png/lodepng.h @@ -0,0 +1,1981 @@ +/* +LodePNG version 20201017 + +Copyright (c) 2005-2020 Lode Vandevenne + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ + +#ifndef LODEPNG_H +#define LODEPNG_H + +#include /*for size_t*/ + +#include "liblvgl/lvgl.h" +#if LV_USE_PNG +extern const char* LODEPNG_VERSION_STRING; + +/* +The following #defines are used to create code sections. They can be disabled +to disable code sections, which can give faster compile time and smaller binary. +The "NO_COMPILE" defines are designed to be used to pass as defines to the +compiler command to disable them without modifying this header, e.g. +-DLODEPNG_NO_COMPILE_ZLIB for gcc. +In addition to those below, you can also define LODEPNG_NO_COMPILE_CRC to +allow implementing a custom lodepng_crc32. +*/ +/*deflate & zlib. If disabled, you must specify alternative zlib functions in +the custom_zlib field of the compress and decompress settings*/ +#ifndef LODEPNG_NO_COMPILE_ZLIB +#define LODEPNG_COMPILE_ZLIB +#endif + +/*png encoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_PNG +#define LODEPNG_COMPILE_PNG +#endif + +/*deflate&zlib decoder and png decoder*/ +#ifndef LODEPNG_NO_COMPILE_DECODER +#define LODEPNG_COMPILE_DECODER +#endif + +/*deflate&zlib encoder and png encoder*/ +#ifndef LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_COMPILE_ENCODER +#endif + +/*the optional built in harddisk file loading and saving functions*/ +#ifndef LODEPNG_NO_COMPILE_DISK +#define LODEPNG_COMPILE_DISK +#endif + +/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/ +#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_COMPILE_ANCILLARY_CHUNKS +#endif + +/*ability to convert error numerical codes to English text string*/ +#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_COMPILE_ERROR_TEXT +#endif + +/*Compile the default allocators (C's free, malloc and realloc). If you disable this, +you can define the functions lodepng_free, lodepng_malloc and lodepng_realloc in your +source files with custom allocators.*/ +#ifndef LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_COMPILE_ALLOCATORS +#endif + +/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/ +#ifdef __cplusplus +#ifndef LODEPNG_NO_COMPILE_CPP +#define LODEPNG_COMPILE_CPP +#endif +#endif + +#ifdef LODEPNG_COMPILE_CPP +#include +#include +#endif /*LODEPNG_COMPILE_CPP*/ + +#ifdef LODEPNG_COMPILE_PNG +/*The PNG color types (also used for raw image).*/ +typedef enum LodePNGColorType { + LCT_GREY = 0, /*grayscale: 1,2,4,8,16 bit*/ + LCT_RGB = 2, /*RGB: 8,16 bit*/ + LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/ + LCT_GREY_ALPHA = 4, /*grayscale with alpha: 8,16 bit*/ + LCT_RGBA = 6, /*RGB with alpha: 8,16 bit*/ + /*LCT_MAX_OCTET_VALUE lets the compiler allow this enum to represent any invalid + byte value from 0 to 255 that could be present in an invalid PNG file header. Do + not use, compare with or set the name LCT_MAX_OCTET_VALUE, instead either use + the valid color type names above, or numeric values like 1 or 7 when checking for + particular disallowed color type byte values, or cast to integer to print it.*/ + LCT_MAX_OCTET_VALUE = 255 +} LodePNGColorType; + +#ifdef LODEPNG_COMPILE_DECODER +/* +Converts PNG data in memory to raw pixel data. +out: Output parameter. Pointer to buffer that will contain the raw pixel data. + After decoding, its size is w * h * (bytes per pixel) bytes larger than + initially. Bytes per pixel depends on colortype and bitdepth. + Must be freed after usage with free(*out). + Note: for 16-bit per channel colors, uses big endian format like PNG does. +w: Output parameter. Pointer to width of pixel data. +h: Output parameter. Pointer to height of pixel data. +in: Memory buffer with the PNG file. +insize: size of the in buffer. +colortype: the desired color type for the raw output image. See explanation on PNG color types. +bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/ +unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/ +unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_DISK +/* +Load PNG from disk, from file with given name. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/ +unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); + +/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/ +unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, + const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_DECODER*/ + + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Converts raw pixel data into a PNG image in memory. The colortype and bitdepth + of the output PNG image cannot be chosen, they are automatically determined + by the colortype, bitdepth and content of the input pixel data. + Note: for 16-bit per channel colors, needs big endian format like PNG does. +out: Output parameter. Pointer to buffer that will contain the PNG image data. + Must be freed after usage with free(*out). +outsize: Output parameter. Pointer to the size in bytes of the out buffer. +image: The raw pixel data to encode. The size of this buffer should be + w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth. +w: width of the raw pixel data in pixels. +h: height of the raw pixel data in pixels. +colortype: the color type of the raw input image. See explanation on PNG color types. +bitdepth: the bit depth of the raw input image. See explanation on PNG color types. +Return value: LodePNG error code (0 means no error). +*/ +unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DISK +/* +Converts raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned lodepng_encode_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h, + LodePNGColorType colortype, unsigned bitdepth); + +/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/ +unsigned lodepng_encode32_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); + +/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/ +unsigned lodepng_encode24_file(const char* filename, + const unsigned char* image, unsigned w, unsigned h); +#endif /*LODEPNG_COMPILE_DISK*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#ifdef LODEPNG_COMPILE_CPP +namespace lodepng { +#ifdef LODEPNG_COMPILE_DECODER +/*Same as lodepng_decode_memory, but decodes to an std::vector. The colortype +is the format to output the pixels to. Default is RGBA 8-bit per channel.*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const unsigned char* in, size_t insize, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::vector& in, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts PNG file from disk to raw pixel data in memory. +Same as the other decode functions, but instead takes a filename as input. +*/ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + const std::string& filename, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/*Same as lodepng_encode_memory, but encodes to an std::vector. colortype +is that of the raw input data. The output PNG color type will be auto chosen.*/ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#ifdef LODEPNG_COMPILE_DISK +/* +Converts 32-bit RGBA raw pixel data into a PNG file on disk. +Same as the other encode functions, but instead takes a filename as output. +NOTE: This overwrites existing files without warning! +*/ +unsigned encode(const std::string& filename, + const unsigned char* in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +unsigned encode(const std::string& filename, + const std::vector& in, unsigned w, unsigned h, + LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_ENCODER */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ +#endif /*LODEPNG_COMPILE_PNG*/ + +#ifdef LODEPNG_COMPILE_ERROR_TEXT +/*Returns an English description of the numerical error code.*/ +const char* lodepng_error_text(unsigned code); +#endif /*LODEPNG_COMPILE_ERROR_TEXT*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Settings for zlib decompression*/ +typedef struct LodePNGDecompressSettings LodePNGDecompressSettings; +struct LodePNGDecompressSettings { + /* Check LodePNGDecoderSettings for more ignorable errors such as ignore_crc */ + unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/ + unsigned ignore_nlen; /*ignore complement of len checksum in uncompressed blocks*/ + + /*Maximum decompressed size, beyond this the decoder may (and is encouraged to) stop decoding, + return an error, output a data size > max_output_size and all the data up to that point. This is + not hard limit nor a guarantee, but can prevent excessive memory usage. This setting is + ignored by the PNG decoder, but is used by the deflate/zlib decoder and can be used by custom ones. + Set to 0 to impose no limit (the default).*/ + size_t max_output_size; + + /*use custom zlib decoder instead of built in one (default: null). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + /*use custom deflate decoder instead of built in one (default: null) + if custom_zlib is not null, custom_inflate is ignored (the zlib format uses deflate). + Should return 0 if success, any non-0 if error (numeric value not exposed).*/ + unsigned (*custom_inflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGDecompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGDecompressSettings lodepng_default_decompress_settings; +void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Settings for zlib compression. Tweaking these settings tweaks the balance +between speed and compression ratio. +*/ +typedef struct LodePNGCompressSettings LodePNGCompressSettings; +struct LodePNGCompressSettings /*deflate = compress*/ { + /*LZ77 related settings*/ + unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/ + unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/ + unsigned windowsize; /*must be a power of two <= 32768. higher compresses more but is slower. Default value: 2048.*/ + unsigned minmatch; /*minimum lz77 length. 3 is normally best, 6 can be better for some PNGs. Default: 0*/ + unsigned nicematch; /*stop searching if >= this length found. Set to 258 for best compression. Default: 128*/ + unsigned lazymatching; /*use lazy matching: better compression but a bit slower. Default: true*/ + + /*use custom zlib encoder instead of built in one (default: null)*/ + unsigned (*custom_zlib)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + /*use custom deflate encoder instead of built in one (default: null) + if custom_zlib is used, custom_deflate is ignored since only the built in + zlib function will call custom_deflate*/ + unsigned (*custom_deflate)(unsigned char**, size_t*, + const unsigned char*, size_t, + const LodePNGCompressSettings*); + + const void* custom_context; /*optional custom settings for custom functions*/ +}; + +extern const LodePNGCompressSettings lodepng_default_compress_settings; +void lodepng_compress_settings_init(LodePNGCompressSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_PNG +/* +Color mode of an image. Contains all information required to decode the pixel +bits to RGBA colors. This information is the same as used in the PNG file +format, and is used both for PNG and raw image data in LodePNG. +*/ +typedef struct LodePNGColorMode { + /*header (IHDR)*/ + LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/ + unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/ + + /* + palette (PLTE and tRNS) + + Dynamically allocated with the colors of the palette, including alpha. + This field may not be allocated directly, use lodepng_color_mode_init first, + then lodepng_palette_add per color to correctly initialize it (to ensure size + of exactly 1024 bytes). + + The alpha channels must be set as well, set them to 255 for opaque images. + + When decoding, by default you can ignore this palette, since LodePNG already + fills the palette colors in the pixels of the raw RGBA output. + + The palette is only supported for color type 3. + */ + unsigned char* palette; /*palette in RGBARGBA... order. Must be either 0, or when allocated must have 1024 bytes*/ + size_t palettesize; /*palette size in number of colors (amount of used bytes is 4 * palettesize)*/ + + /* + transparent color key (tRNS) + + This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit. + For grayscale PNGs, r, g and b will all 3 be set to the same. + + When decoding, by default you can ignore this information, since LodePNG sets + pixels with this key to transparent already in the raw RGBA output. + + The color key is only supported for color types 0 and 2. + */ + unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/ + unsigned key_r; /*red/grayscale component of color key*/ + unsigned key_g; /*green component of color key*/ + unsigned key_b; /*blue component of color key*/ +} LodePNGColorMode; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_color_mode_init(LodePNGColorMode* info); +void lodepng_color_mode_cleanup(LodePNGColorMode* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source); +/* Makes a temporary LodePNGColorMode that does not need cleanup (no palette) */ +LodePNGColorMode lodepng_color_mode_make(LodePNGColorType colortype, unsigned bitdepth); + +void lodepng_palette_clear(LodePNGColorMode* info); +/*add 1 color to the palette*/ +unsigned lodepng_palette_add(LodePNGColorMode* info, + unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/ +unsigned lodepng_get_bpp(const LodePNGColorMode* info); +/*get the amount of color channels used, based on colortype in the struct. +If a palette is used, it counts as 1 channel.*/ +unsigned lodepng_get_channels(const LodePNGColorMode* info); +/*is it a grayscale type? (only colortype 0 or 4)*/ +unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info); +/*has it got an alpha channel? (only colortype 2 or 6)*/ +unsigned lodepng_is_alpha_type(const LodePNGColorMode* info); +/*has it got a palette? (only colortype 3)*/ +unsigned lodepng_is_palette_type(const LodePNGColorMode* info); +/*only returns true if there is a palette and there is a value in the palette with alpha < 255. +Loops through the palette to check this.*/ +unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info); +/* +Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image. +Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels). +Returns false if the image can only have opaque pixels. +In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values, +or if "key_defined" is true. +*/ +unsigned lodepng_can_have_alpha(const LodePNGColorMode* info); +/*Returns the byte size of a raw image buffer with given width, height and color mode*/ +size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +/*The information of a Time chunk in PNG.*/ +typedef struct LodePNGTime { + unsigned year; /*2 bytes used (0-65535)*/ + unsigned month; /*1-12*/ + unsigned day; /*1-31*/ + unsigned hour; /*0-23*/ + unsigned minute; /*0-59*/ + unsigned second; /*0-60 (to allow for leap seconds)*/ +} LodePNGTime; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/*Information about the PNG image, except pixels, width and height.*/ +typedef struct LodePNGInfo { + /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/ + unsigned compression_method;/*compression method of the original file. Always 0.*/ + unsigned filter_method; /*filter method of the original file*/ + unsigned interlace_method; /*interlace method of the original file: 0=none, 1=Adam7*/ + LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /* + Suggested background color chunk (bKGD) + + This uses the same color mode and bit depth as the PNG (except no alpha channel), + with values truncated to the bit depth in the unsigned integer. + + For grayscale and palette PNGs, the value is stored in background_r. The values + in background_g and background_b are then unused. + + So when decoding, you may get these in a different color mode than the one you requested + for the raw pixels. + + When encoding with auto_convert, you must use the color model defined in info_png.color for + these values. The encoder normally ignores info_png.color when auto_convert is on, but will + use it to interpret these values (and convert copies of them to its chosen color model). + + When encoding, avoid setting this to an expensive color, such as a non-gray value + when the image is gray, or the compression will be worse since it will be forced to + write the PNG with a more expensive color mode (when auto_convert is on). + + The decoder does not use this background color to edit the color of pixels. This is a + completely optional metadata feature. + */ + unsigned background_defined; /*is a suggested background color given?*/ + unsigned background_r; /*red/gray/palette component of suggested background color*/ + unsigned background_g; /*green component of suggested background color*/ + unsigned background_b; /*blue component of suggested background color*/ + + /* + Non-international text chunks (tEXt and zTXt) + + The char** arrays each contain num strings. The actual messages are in + text_strings, while text_keys are keywords that give a short description what + the actual text represents, e.g. Title, Author, Description, or anything else. + + All the string fields below including strings, keys, names and language tags are null terminated. + The PNG specification uses null characters for the keys, names and tags, and forbids null + characters to appear in the main text which is why we can use null termination everywhere here. + + A keyword is minimum 1 character and maximum 79 characters long (plus the + additional null terminator). It's discouraged to use a single line length + longer than 79 characters for texts. + + Don't allocate these text buffers yourself. Use the init/cleanup functions + correctly and use lodepng_add_text and lodepng_clear_text. + + Standard text chunk keywords and strings are encoded using Latin-1. + */ + size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/ + char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/ + char** text_strings; /*the actual text*/ + + /* + International text chunks (iTXt) + Similar to the non-international text chunks, but with additional strings + "langtags" and "transkeys", and the following text encodings are used: + keys: Latin-1, langtags: ASCII, transkeys and strings: UTF-8. + keys must be 1-79 characters (plus the additional null terminator), the other + strings are any length. + */ + size_t itext_num; /*the amount of international texts in this PNG*/ + char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/ + char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/ + char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/ + char** itext_strings; /*the actual international text - UTF-8 string*/ + + /*time chunk (tIME)*/ + unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/ + LodePNGTime time; + + /*phys chunk (pHYs)*/ + unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/ + unsigned phys_x; /*pixels per unit in x direction*/ + unsigned phys_y; /*pixels per unit in y direction*/ + unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/ + + /* + Color profile related chunks: gAMA, cHRM, sRGB, iCPP + + LodePNG does not apply any color conversions on pixels in the encoder or decoder and does not interpret these color + profile values. It merely passes on the information. If you wish to use color profiles and convert colors, please + use these values with a color management library. + + See the PNG, ICC and sRGB specifications for more information about the meaning of these values. + */ + + /* gAMA chunk: optional, overridden by sRGB or iCCP if those are present. */ + unsigned gama_defined; /* Whether a gAMA chunk is present (0 = not present, 1 = present). */ + unsigned gama_gamma; /* Gamma exponent times 100000 */ + + /* cHRM chunk: optional, overridden by sRGB or iCCP if those are present. */ + unsigned chrm_defined; /* Whether a cHRM chunk is present (0 = not present, 1 = present). */ + unsigned chrm_white_x; /* White Point x times 100000 */ + unsigned chrm_white_y; /* White Point y times 100000 */ + unsigned chrm_red_x; /* Red x times 100000 */ + unsigned chrm_red_y; /* Red y times 100000 */ + unsigned chrm_green_x; /* Green x times 100000 */ + unsigned chrm_green_y; /* Green y times 100000 */ + unsigned chrm_blue_x; /* Blue x times 100000 */ + unsigned chrm_blue_y; /* Blue y times 100000 */ + + /* + sRGB chunk: optional. May not appear at the same time as iCCP. + If gAMA is also present gAMA must contain value 45455. + If cHRM is also present cHRM must contain respectively 31270,32900,64000,33000,30000,60000,15000,6000. + */ + unsigned srgb_defined; /* Whether an sRGB chunk is present (0 = not present, 1 = present). */ + unsigned srgb_intent; /* Rendering intent: 0=perceptual, 1=rel. colorimetric, 2=saturation, 3=abs. colorimetric */ + + /* + iCCP chunk: optional. May not appear at the same time as sRGB. + + LodePNG does not parse or use the ICC profile (except its color space header field for an edge case), a + separate library to handle the ICC data (not included in LodePNG) format is needed to use it for color + management and conversions. + + For encoding, if iCCP is present, gAMA and cHRM are recommended to be added as well with values that match the ICC + profile as closely as possible, if you wish to do this you should provide the correct values for gAMA and cHRM and + enable their '_defined' flags since LodePNG will not automatically compute them from the ICC profile. + + For encoding, the ICC profile is required by the PNG specification to be an "RGB" profile for non-gray + PNG color types and a "GRAY" profile for gray PNG color types. If you disable auto_convert, you must ensure + the ICC profile type matches your requested color type, else the encoder gives an error. If auto_convert is + enabled (the default), and the ICC profile is not a good match for the pixel data, this will result in an encoder + error if the pixel data has non-gray pixels for a GRAY profile, or a silent less-optimal compression of the pixel + data if the pixels could be encoded as grayscale but the ICC profile is RGB. + + To avoid this do not set an ICC profile in the image unless there is a good reason for it, and when doing so + make sure you compute it carefully to avoid the above problems. + */ + unsigned iccp_defined; /* Whether an iCCP chunk is present (0 = not present, 1 = present). */ + char* iccp_name; /* Null terminated string with profile name, 1-79 bytes */ + /* + The ICC profile in iccp_profile_size bytes. + Don't allocate this buffer yourself. Use the init/cleanup functions + correctly and use lodepng_set_icc and lodepng_clear_icc. + */ + unsigned char* iccp_profile; + unsigned iccp_profile_size; /* The size of iccp_profile in bytes */ + + /* End of color profile related chunks */ + + + /* + unknown chunks: chunks not known by LodePNG, passed on byte for byte. + + There are 3 buffers, one for each position in the PNG where unknown chunks can appear. + Each buffer contains all unknown chunks for that position consecutively. + The 3 positions are: + 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. + + For encoding, do not store critical chunks or known chunks that are enabled with a "_defined" flag + above in here, since the encoder will blindly follow this and could then encode an invalid PNG file + (such as one with two IHDR chunks or the disallowed combination of sRGB with iCCP). But do use + this if you wish to store an ancillary chunk that is not supported by LodePNG (such as sPLT or hIST), + or any non-standard PNG chunk. + + Do not allocate or traverse this data yourself. Use the chunk traversing functions declared + later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct. + */ + unsigned char* unknown_chunks_data[3]; + size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGInfo; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_info_init(LodePNGInfo* info); +void lodepng_info_cleanup(LodePNGInfo* info); +/*return value is error code (0 means no error)*/ +unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source); + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS +unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/ +void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ + +unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag, + const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/ +void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/ + +/*replaces if exists*/ +unsigned lodepng_set_icc(LodePNGInfo* info, const char* name, const unsigned char* profile, unsigned profile_size); +void lodepng_clear_icc(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/ +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ + +/* +Converts raw buffer from one color type to another color type, based on +LodePNGColorMode structs to describe the input and output color type. +See the reference manual at the end of this header file to see which color conversions are supported. +return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported) +The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel +of the output color type (lodepng_get_bpp). +For < 8 bpp images, there should not be padding bits at the end of scanlines. +For 16-bit per channel colors, uses big endian format like PNG does. +Return value is LodePNG error code +*/ +unsigned lodepng_convert(unsigned char* out, const unsigned char* in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + unsigned w, unsigned h); + +#ifdef LODEPNG_COMPILE_DECODER +/* +Settings for the decoder. This contains settings for the PNG and the Zlib +decoder, but not the Info settings from the Info structs. +*/ +typedef struct LodePNGDecoderSettings { + LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/ + + /* Check LodePNGDecompressSettings for more ignorable errors such as ignore_adler32 */ + unsigned ignore_crc; /*ignore CRC checksums*/ + unsigned ignore_critical; /*ignore unknown critical chunks*/ + unsigned ignore_end; /*ignore issues at end of file if possible (missing IEND chunk, too large chunk, ...)*/ + /* TODO: make a system involving warnings with levels and a strict mode instead. Other potentially recoverable + errors: srgb rendering intent value, size of content of ancillary chunks, more than 79 characters for some + strings, placement/combination rules for ancillary chunks, crc of unknown chunks, allowed characters + in string keys, etc... */ + + unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/ + +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/ + + /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/ + unsigned remember_unknown_chunks; + + /* maximum size for decompressed text chunks. If a text chunk's text is larger than this, an error is returned, + unless reading text chunks is disabled or this limit is set higher or disabled. Set to 0 to allow any size. + By default it is a value that prevents unreasonably large strings from hogging memory. */ + size_t max_text_size; + + /* maximum size for compressed ICC chunks. If the ICC profile is larger than this, an error will be returned. Set to + 0 to allow any size. By default this is a value that prevents ICC profiles that would be much larger than any + legitimate profile could be to hog memory. */ + size_t max_icc_size; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGDecoderSettings; + +void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/ +typedef enum LodePNGFilterStrategy { + /*every filter at zero*/ + LFS_ZERO = 0, + /*every filter at 1, 2, 3 or 4 (paeth), unlike LFS_ZERO not a good choice, but for testing*/ + LFS_ONE = 1, + LFS_TWO = 2, + LFS_THREE = 3, + LFS_FOUR = 4, + /*Use filter that gives minimum sum, as described in the official PNG filter heuristic.*/ + LFS_MINSUM, + /*Use the filter type that gives smallest Shannon entropy for this scanline. Depending + on the image, this is better or worse than minsum.*/ + LFS_ENTROPY, + /* + Brute-force-search PNG filters by compressing each filter for each scanline. + Experimental, very slow, and only rarely gives better compression than MINSUM. + */ + LFS_BRUTE_FORCE, + /*use predefined_filters buffer: you specify the filter type for each scanline*/ + LFS_PREDEFINED +} LodePNGFilterStrategy; + +/*Gives characteristics about the integer RGBA colors of the image (count, alpha channel usage, bit depth, ...), +which helps decide which color model to use for encoding. +Used internally by default if "auto_convert" is enabled. Public because it's useful for custom algorithms.*/ +typedef struct LodePNGColorStats { + unsigned colored; /*not grayscale*/ + unsigned key; /*image is not opaque and color key is possible instead of full alpha*/ + unsigned short key_r; /*key values, always as 16-bit, in 8-bit case the byte is duplicated, e.g. 65535 means 255*/ + unsigned short key_g; + unsigned short key_b; + unsigned alpha; /*image is not opaque and alpha channel or alpha palette required*/ + unsigned numcolors; /*amount of colors, up to 257. Not valid if bits == 16 or allow_palette is disabled.*/ + unsigned char palette[1024]; /*Remembers up to the first 256 RGBA colors, in no particular order, only valid when numcolors is valid*/ + unsigned bits; /*bits per channel (not for palette). 1,2 or 4 for grayscale only. 16 if 16-bit per channel required.*/ + size_t numpixels; + + /*user settings for computing/using the stats*/ + unsigned allow_palette; /*default 1. if 0, disallow choosing palette colortype in auto_choose_color, and don't count numcolors*/ + unsigned allow_greyscale; /*default 1. if 0, choose RGB or RGBA even if the image only has gray colors*/ +} LodePNGColorStats; + +void lodepng_color_stats_init(LodePNGColorStats* stats); + +/*Get a LodePNGColorStats of the image. The stats must already have been inited. +Returns error code (e.g. alloc fail) or 0 if ok.*/ +unsigned lodepng_compute_color_stats(LodePNGColorStats* stats, + const unsigned char* image, unsigned w, unsigned h, + const LodePNGColorMode* mode_in); + +/*Settings for the encoder.*/ +typedef struct LodePNGEncoderSettings { + LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/ + + unsigned auto_convert; /*automatically choose output PNG color type. Default: true*/ + + /*If true, follows the official PNG heuristic: if the PNG uses a palette or lower than + 8 bit depth, set all filters to zero. Otherwise use the filter_strategy. Note that to + completely follow the official PNG heuristic, filter_palette_zero must be true and + filter_strategy must be LFS_MINSUM*/ + unsigned filter_palette_zero; + /*Which filter strategy to use when not using zeroes due to filter_palette_zero. + Set filter_palette_zero to 0 to ensure always using your chosen strategy. Default: LFS_MINSUM*/ + LodePNGFilterStrategy filter_strategy; + /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with + the same length as the amount of scanlines in the image, and each value must <= 5. You + have to cleanup this buffer, LodePNG will never free it. Don't forget that filter_palette_zero + must be set to 0 to ensure this is also used on palette or low bitdepth images.*/ + const unsigned char* predefined_filters; + + /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette). + If colortype is 3, PLTE is _always_ created.*/ + unsigned force_palette; +#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS + /*add LodePNG identifier and version as a text chunk, for debugging*/ + unsigned add_id; + /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/ + unsigned text_compression; +#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ +} LodePNGEncoderSettings; + +void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings); +#endif /*LODEPNG_COMPILE_ENCODER*/ + + +#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) +/*The settings, state and information for extended encoding and decoding.*/ +typedef struct LodePNGState { +#ifdef LODEPNG_COMPILE_DECODER + LodePNGDecoderSettings decoder; /*the decoding settings*/ +#endif /*LODEPNG_COMPILE_DECODER*/ +#ifdef LODEPNG_COMPILE_ENCODER + LodePNGEncoderSettings encoder; /*the encoding settings*/ +#endif /*LODEPNG_COMPILE_ENCODER*/ + LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/ + LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/ + unsigned error; +} LodePNGState; + +/*init, cleanup and copy functions to use with this struct*/ +void lodepng_state_init(LodePNGState* state); +void lodepng_state_cleanup(LodePNGState* state); +void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source); +#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */ + +#ifdef LODEPNG_COMPILE_DECODER +/* +Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and +getting much more information about the PNG image and color mode. +*/ +unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); + +/* +Read the PNG header, but not the actual data. This returns only the information +that is in the IHDR chunk of the PNG, such as width, height and color type. The +information is placed in the info_png field of the LodePNGState. +*/ +unsigned lodepng_inspect(unsigned* w, unsigned* h, + LodePNGState* state, + const unsigned char* in, size_t insize); +#endif /*LODEPNG_COMPILE_DECODER*/ + +/* +Reads one metadata chunk (other than IHDR) of the PNG file and outputs what it +read in the state. Returns error code on failure. +Use lodepng_inspect first with a new state, then e.g. lodepng_chunk_find_const +to find the desired chunk type, and if non null use lodepng_inspect_chunk (with +chunk_pointer - start_of_file as pos). +Supports most metadata chunks from the PNG standard (gAMA, bKGD, tEXt, ...). +Ignores unsupported, unknown, non-metadata or IHDR chunks (without error). +Requirements: &in[pos] must point to start of a chunk, must use regular +lodepng_inspect first since format of most other chunks depends on IHDR, and if +there is a PLTE chunk, that one must be inspected before tRNS or bKGD. +*/ +unsigned lodepng_inspect_chunk(LodePNGState* state, size_t pos, + const unsigned char* in, size_t insize); + +#ifdef LODEPNG_COMPILE_ENCODER +/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/ +unsigned lodepng_encode(unsigned char** out, size_t* outsize, + const unsigned char* image, unsigned w, unsigned h, + LodePNGState* state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +/* +The lodepng_chunk functions are normally not needed, except to traverse the +unknown chunks stored in the LodePNGInfo struct, or add new ones to it. +It also allows traversing the chunks of an encoded PNG file yourself. + +The chunk pointer always points to the beginning of the chunk itself, that is +the first byte of the 4 length bytes. + +In the PNG file format, chunks have the following format: +-4 bytes length: length of the data of the chunk in bytes (chunk itself is 12 bytes longer) +-4 bytes chunk type (ASCII a-z,A-Z only, see below) +-length bytes of data (may be 0 bytes if length was 0) +-4 bytes of CRC, computed on chunk name + data + +The first chunk starts at the 8th byte of the PNG file, the entire rest of the file +exists out of concatenated chunks with the above format. + +PNG standard chunk ASCII naming conventions: +-First byte: uppercase = critical, lowercase = ancillary +-Second byte: uppercase = public, lowercase = private +-Third byte: must be uppercase +-Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy +*/ + +/* +Gets the length of the data of the chunk. Total chunk length has 12 bytes more. +There must be at least 4 bytes to read from. If the result value is too large, +it may be corrupt data. +*/ +unsigned lodepng_chunk_length(const unsigned char* chunk); + +/*puts the 4-byte type in null terminated string*/ +void lodepng_chunk_type(char type[5], const unsigned char* chunk); + +/*check if the type is the given type*/ +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type); + +/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/ +unsigned char lodepng_chunk_ancillary(const unsigned char* chunk); + +/*0: public, 1: private (see PNG standard)*/ +unsigned char lodepng_chunk_private(const unsigned char* chunk); + +/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/ +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk); + +/*get pointer to the data of the chunk, where the input points to the header of the chunk*/ +unsigned char* lodepng_chunk_data(unsigned char* chunk); +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk); + +/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/ +unsigned lodepng_chunk_check_crc(const unsigned char* chunk); + +/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/ +void lodepng_chunk_generate_crc(unsigned char* chunk); + +/* +Iterate to next chunks, allows iterating through all chunks of the PNG file. +Input must be at the beginning of a chunk (result of a previous lodepng_chunk_next call, +or the 8th byte of a PNG file which always has the first chunk), or alternatively may +point to the first byte of the PNG file (which is not a chunk but the magic header, the +function will then skip over it and return the first real chunk). +Will output pointer to the start of the next chunk, or at or beyond end of the file if there +is no more chunk after this or possibly if the chunk is corrupt. +Start this process at the 8th byte of the PNG file. +In a non-corrupt PNG file, the last chunk should have name "IEND". +*/ +unsigned char* lodepng_chunk_next(unsigned char* chunk, unsigned char* end); +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk, const unsigned char* end); + +/*Finds the first chunk with the given type in the range [chunk, end), or returns NULL if not found.*/ +unsigned char* lodepng_chunk_find(unsigned char* chunk, unsigned char* end, const char type[5]); +const unsigned char* lodepng_chunk_find_const(const unsigned char* chunk, const unsigned char* end, const char type[5]); + +/* +Appends chunk to the data in out. The given chunk should already have its chunk header. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returns error code (0 if it went ok) +*/ +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk); + +/* +Appends new chunk to out. The chunk to append is given by giving its length, type +and data separately. The type is a 4-letter string. +The out variable and outsize are updated to reflect the new reallocated buffer. +Returne error code (0 if it went ok) +*/ +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, + const char* type, const unsigned char* data); + + +/*Calculate CRC32 of buffer*/ +unsigned lodepng_crc32(const unsigned char* buf, size_t len); +#endif /*LODEPNG_COMPILE_PNG*/ + + +#ifdef LODEPNG_COMPILE_ZLIB +/* +This zlib part can be used independently to zlib compress and decompress a +buffer. It cannot be used to create gzip files however, and it only supports the +part of zlib that is required for PNG, it does not support dictionaries. +*/ + +#ifdef LODEPNG_COMPILE_DECODER +/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/ +unsigned lodepng_inflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); + +/* +Decompresses Zlib data. Reallocates the out buffer and appends the data. The +data must be according to the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGDecompressSettings* settings); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* +Compresses data with Zlib. Reallocates the out buffer and appends the data. +Zlib adds a small header and trailer around the deflate data. +The data is output in the format of the zlib specification. +Either, *out must be NULL and *outsize must be 0, or, *out must be a valid +buffer and *outsize its size in bytes. out must be freed by user after usage. +*/ +unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +/* +Find length-limited Huffman code for given frequencies. This function is in the +public interface only for tests, it's used internally by lodepng_deflate. +*/ +unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies, + size_t numcodes, unsigned maxbitlen); + +/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/ +unsigned lodepng_deflate(unsigned char** out, size_t* outsize, + const unsigned char* in, size_t insize, + const LodePNGCompressSettings* settings); + +#endif /*LODEPNG_COMPILE_ENCODER*/ +#endif /*LODEPNG_COMPILE_ZLIB*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into buffer. The function allocates the out buffer, and +after usage you should free it. +out: output parameter, contains pointer to loaded buffer. +outsize: output parameter, size of the allocated out buffer +filename: the path to the file to load +return value: error code (0 means ok) +*/ +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename); + +/* +Save a file from buffer to disk. Warning, if it exists, this function overwrites +the file without warning! +buffer: the buffer to write +buffersize: size of the buffer to write +filename: the path to the file to save to +return value: error code (0 means ok) +*/ +unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename); +#endif /*LODEPNG_COMPILE_DISK*/ + +#ifdef LODEPNG_COMPILE_CPP +/* The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers. */ +namespace lodepng { +#ifdef LODEPNG_COMPILE_PNG +class State : public LodePNGState { + public: + State(); + State(const State& other); + ~State(); + State& operator=(const State& other); +}; + +#ifdef LODEPNG_COMPILE_DECODER +/* Same as other lodepng::decode, but using a State for more settings and information. */ +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const unsigned char* in, size_t insize); +unsigned decode(std::vector& out, unsigned& w, unsigned& h, + State& state, + const std::vector& in); +#endif /*LODEPNG_COMPILE_DECODER*/ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Same as other lodepng::encode, but using a State for more settings and information. */ +unsigned encode(std::vector& out, + const unsigned char* in, unsigned w, unsigned h, + State& state); +unsigned encode(std::vector& out, + const std::vector& in, unsigned w, unsigned h, + State& state); +#endif /*LODEPNG_COMPILE_ENCODER*/ + +#ifdef LODEPNG_COMPILE_DISK +/* +Load a file from disk into an std::vector. +return value: error code (0 means ok) +*/ +unsigned load_file(std::vector& buffer, const std::string& filename); + +/* +Save the binary data in an std::vector to a file on disk. The file is overwritten +without warning. +*/ +unsigned save_file(const std::vector& buffer, const std::string& filename); +#endif /* LODEPNG_COMPILE_DISK */ +#endif /* LODEPNG_COMPILE_PNG */ + +#ifdef LODEPNG_COMPILE_ZLIB +#ifdef LODEPNG_COMPILE_DECODER +/* Zlib-decompress an unsigned char buffer */ +unsigned decompress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); + +/* Zlib-decompress an std::vector */ +unsigned decompress(std::vector& out, const std::vector& in, + const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings); +#endif /* LODEPNG_COMPILE_DECODER */ + +#ifdef LODEPNG_COMPILE_ENCODER +/* Zlib-compress an unsigned char buffer */ +unsigned compress(std::vector& out, const unsigned char* in, size_t insize, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); + +/* Zlib-compress an std::vector */ +unsigned compress(std::vector& out, const std::vector& in, + const LodePNGCompressSettings& settings = lodepng_default_compress_settings); +#endif /* LODEPNG_COMPILE_ENCODER */ +#endif /* LODEPNG_COMPILE_ZLIB */ +} /* namespace lodepng */ +#endif /*LODEPNG_COMPILE_CPP*/ + +/* +TODO: +[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often +[.] check compatibility with various compilers - done but needs to be redone for every newer version +[X] converting color to 16-bit per channel types +[X] support color profile chunk types (but never let them touch RGB values by default) +[ ] support all public PNG chunk types (almost done except sBIT, sPLT and hIST) +[ ] make sure encoder generates no chunks with size > (2^31)-1 +[ ] partial decoding (stream processing) +[X] let the "isFullyOpaque" function check color keys and transparent palettes too +[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl" +[ ] allow treating some errors like warnings, when image is recoverable (e.g. 69, 57, 58) +[ ] make warnings like: oob palette, checksum fail, data after iend, wrong/unknown crit chunk, no null terminator in text, ... +[ ] error messages with line numbers (and version) +[ ] errors in state instead of as return code? +[ ] new errors/warnings like suspiciously big decompressed ztxt or iccp chunk +[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes +[ ] allow user to provide custom color conversion functions, e.g. for premultiplied alpha, padding bits or not, ... +[ ] allow user to give data (void*) to custom allocator +[X] provide alternatives for C library functions not present on some platforms (memcpy, ...) +*/ + +#endif /*LV_USE_PNG*/ + +#endif /*LODEPNG_H inclusion guard*/ + +/* +LodePNG Documentation +--------------------- + +0. table of contents +-------------------- + + 1. about + 1.1. supported features + 1.2. features not supported + 2. C and C++ version + 3. security + 4. decoding + 5. encoding + 6. color conversions + 6.1. PNG color types + 6.2. color conversions + 6.3. padding bits + 6.4. A note about 16-bits per channel and endianness + 7. error values + 8. chunks and PNG editing + 9. compiler support + 10. examples + 10.1. decoder C++ example + 10.2. decoder C example + 11. state settings reference + 12. changes + 13. contact information + + +1. about +-------- + +PNG is a file format to store raster images losslessly with good compression, +supporting different color types and alpha channel. + +LodePNG is a PNG codec according to the Portable Network Graphics (PNG) +Specification (Second Edition) - W3C Recommendation 10 November 2003. + +The specifications used are: + +*) Portable Network Graphics (PNG) Specification (Second Edition): + http://www.w3.org/TR/2003/REC-PNG-20031110 +*) RFC 1950 ZLIB Compressed Data Format version 3.3: + http://www.gzip.org/zlib/rfc-zlib.html +*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3: + http://www.gzip.org/zlib/rfc-deflate.html + +The most recent version of LodePNG can currently be found at +http://lodev.org/lodepng/ + +LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds +extra functionality. + +LodePNG exists out of two files: +-lodepng.h: the header file for both C and C++ +-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage + +If you want to start using LodePNG right away without reading this doc, get the +examples from the LodePNG website to see how to use it in code, or check the +smaller examples in chapter 13 here. + +LodePNG is simple but only supports the basic requirements. To achieve +simplicity, the following design choices were made: There are no dependencies +on any external library. There are functions to decode and encode a PNG with +a single function call, and extended versions of these functions taking a +LodePNGState struct allowing to specify or get more information. By default +the colors of the raw image are always RGB or RGBA, no matter what color type +the PNG file uses. To read and write files, there are simple functions to +convert the files to/from buffers in memory. + +This all makes LodePNG suitable for loading textures in games, demos and small +programs, ... It's less suitable for full fledged image editors, loading PNGs +over network (it requires all the image data to be available before decoding can +begin), life-critical systems, ... + +1.1. supported features +----------------------- + +The following features are supported by the decoder: + +*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image, + or the same color type as the PNG +*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image +*) Adam7 interlace and deinterlace for any color type +*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk +*) support for alpha channels, including RGBA color model, translucent palettes and color keying +*) zlib decompression (inflate) +*) zlib compression (deflate) +*) CRC32 and ADLER32 checksums +*) colorimetric color profile conversions: currently experimentally available in lodepng_util.cpp only, + plus alternatively ability to pass on chroma/gamma/ICC profile information to other color management system. +*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks. +*) the following chunks are supported by both encoder and decoder: + IHDR: header information + PLTE: color palette + IDAT: pixel data + IEND: the final chunk + tRNS: transparency for palettized images + tEXt: textual information + zTXt: compressed textual information + iTXt: international textual information + bKGD: suggested background color + pHYs: physical dimensions + tIME: modification time + cHRM: RGB chromaticities + gAMA: RGB gamma correction + iCCP: ICC color profile + sRGB: rendering intent + +1.2. features not supported +--------------------------- + +The following features are _not_ supported: + +*) some features needed to make a conformant PNG-Editor might be still missing. +*) partial loading/stream processing. All data must be available and is processed in one call. +*) The following public chunks are not (yet) supported but treated as unknown chunks by LodePNG: + sBIT + hIST + sPLT + + +2. C and C++ version +-------------------- + +The C version uses buffers allocated with alloc that you need to free() +yourself. You need to use init and cleanup functions for each struct whenever +using a struct from the C version to avoid exploits and memory leaks. + +The C++ version has extra functions with std::vectors in the interface and the +lodepng::State class which is a LodePNGState with constructor and destructor. + +These files work without modification for both C and C++ compilers because all +the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers +ignore it, and the C code is made to compile both with strict ISO C90 and C++. + +To use the C++ version, you need to rename the source file to lodepng.cpp +(instead of lodepng.c), and compile it with a C++ compiler. + +To use the C version, you need to rename the source file to lodepng.c (instead +of lodepng.cpp), and compile it with a C compiler. + + +3. Security +----------- + +Even if carefully designed, it's always possible that LodePNG contains possible +exploits. If you discover one, please let me know, and it will be fixed. + +When using LodePNG, care has to be taken with the C version of LodePNG, as well +as the C-style structs when working with C++. The following conventions are used +for all C-style structs: + +-if a struct has a corresponding init function, always call the init function when making a new one +-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks +-if a struct has a corresponding copy function, use the copy function instead of "=". + The destination must also be inited already. + + +4. Decoding +----------- + +Decoding converts a PNG compressed image to a raw pixel buffer. + +Most documentation on using the decoder is at its declarations in the header +above. For C, simple decoding can be done with functions such as +lodepng_decode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_decode. For C++, all decoding can be done with the +various lodepng::decode functions, and lodepng::State can be used for advanced +features. + +When using the LodePNGState, it uses the following fields for decoding: +*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here +*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get +*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use + +LodePNGInfo info_png +-------------------- + +After decoding, this contains extra information of the PNG image, except the actual +pixels, width and height because these are already gotten directly from the decoder +functions. + +It contains for example the original color type of the PNG image, text comments, +suggested background color, etc... More details about the LodePNGInfo struct are +at its declaration documentation. + +LodePNGColorMode info_raw +------------------------- + +When decoding, here you can specify which color type you want +the resulting raw image to be. If this is different from the colortype of the +PNG, then the decoder will automatically convert the result. This conversion +always works, except if you want it to convert a color PNG to grayscale or to +a palette with missing colors. + +By default, 32-bit color is used for the result. + +LodePNGDecoderSettings decoder +------------------------------ + +The settings can be used to ignore the errors created by invalid CRC and Adler32 +chunks, and to disable the decoding of tEXt chunks. + +There's also a setting color_convert, true by default. If false, no conversion +is done, the resulting data will be as it was in the PNG (after decompression) +and you'll have to puzzle the colors of the pixels together yourself using the +color type information in the LodePNGInfo. + + +5. Encoding +----------- + +Encoding converts a raw pixel buffer to a PNG compressed image. + +Most documentation on using the encoder is at its declarations in the header +above. For C, simple encoding can be done with functions such as +lodepng_encode32, and more advanced decoding can be done with the struct +LodePNGState and lodepng_encode. For C++, all encoding can be done with the +various lodepng::encode functions, and lodepng::State can be used for advanced +features. + +Like the decoder, the encoder can also give errors. However it gives less errors +since the encoder input is trusted, the decoder input (a PNG image that could +be forged by anyone) is not trusted. + +When using the LodePNGState, it uses the following fields for encoding: +*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be. +*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has +*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use + +LodePNGInfo info_png +-------------------- + +When encoding, you use this the opposite way as when decoding: for encoding, +you fill in the values you want the PNG to have before encoding. By default it's +not needed to specify a color type for the PNG since it's automatically chosen, +but it's possible to choose it yourself given the right settings. + +The encoder will not always exactly match the LodePNGInfo struct you give, +it tries as close as possible. Some things are ignored by the encoder. The +encoder uses, for example, the following settings from it when applicable: +colortype and bitdepth, text chunks, time chunk, the color key, the palette, the +background color, the interlace method, unknown chunks, ... + +When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk. +If the palette contains any colors for which the alpha channel is not 255 (so +there are translucent colors in the palette), it'll add a tRNS chunk. + +LodePNGColorMode info_raw +------------------------- + +You specify the color type of the raw image that you give to the input here, +including a possible transparent color key and palette you happen to be using in +your raw image data. + +By default, 32-bit color is assumed, meaning your input has to be in RGBA +format with 4 bytes (unsigned chars) per pixel. + +LodePNGEncoderSettings encoder +------------------------------ + +The following settings are supported (some are in sub-structs): +*) auto_convert: when this option is enabled, the encoder will +automatically choose the smallest possible color mode (including color key) that +can encode the colors of all pixels without information loss. +*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree, + 2 = dynamic huffman tree (best compression). Should be 2 for proper + compression. +*) use_lz77: whether or not to use LZ77 for compressed block types. Should be + true for proper compression. +*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value + 2048 by default, but can be set to 32768 for better, but slow, compression. +*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE + chunk if force_palette is true. This can used as suggested palette to convert + to by viewers that don't support more than 256 colors (if those still exist) +*) add_id: add text chunk "Encoder: LodePNG " to the image. +*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks. + zTXt chunks use zlib compression on the text. This gives a smaller result on + large texts but a larger result on small texts (such as a single program name). + It's all tEXt or all zTXt though, there's no separate setting per text yet. + + +6. color conversions +-------------------- + +An important thing to note about LodePNG, is that the color type of the PNG, and +the color type of the raw image, are completely independent. By default, when +you decode a PNG, you get the result as a raw image in the color type you want, +no matter whether the PNG was encoded with a palette, grayscale or RGBA color. +And if you encode an image, by default LodePNG will automatically choose the PNG +color type that gives good compression based on the values of colors and amount +of colors in the image. It can be configured to let you control it instead as +well, though. + +To be able to do this, LodePNG does conversions from one color mode to another. +It can convert from almost any color type to any other color type, except the +following conversions: RGB to grayscale is not supported, and converting to a +palette when the palette doesn't have a required color is not supported. This is +not supported on purpose: this is information loss which requires a color +reduction algorithm that is beyond the scope of a PNG encoder (yes, RGB to gray +is easy, but there are multiple ways if you want to give some channels more +weight). + +By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB +color, no matter what color type the PNG has. And by default when encoding, +LodePNG automatically picks the best color model for the output PNG, and expects +the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control +the color format of the images yourself, you can skip this chapter. + +6.1. PNG color types +-------------------- + +A PNG image can have many color types, ranging from 1-bit color to 64-bit color, +as well as palettized color modes. After the zlib decompression and unfiltering +in the PNG image is done, the raw pixel data will have that color type and thus +a certain amount of bits per pixel. If you want the output raw image after +decoding to have another color type, a conversion is done by LodePNG. + +The PNG specification gives the following color types: + +0: grayscale, bit depths 1, 2, 4, 8, 16 +2: RGB, bit depths 8 and 16 +3: palette, bit depths 1, 2, 4 and 8 +4: grayscale with alpha, bit depths 8 and 16 +6: RGBA, bit depths 8 and 16 + +Bit depth is the amount of bits per pixel per color channel. So the total amount +of bits per pixel is: amount of channels * bitdepth. + +6.2. color conversions +---------------------- + +As explained in the sections about the encoder and decoder, you can specify +color types and bit depths in info_png and info_raw to change the default +behaviour. + +If, when decoding, you want the raw image to be something else than the default, +you need to set the color type and bit depth you want in the LodePNGColorMode, +or the parameters colortype and bitdepth of the simple decoding function. + +If, when encoding, you use another color type than the default in the raw input +image, you need to specify its color type and bit depth in the LodePNGColorMode +of the raw image, or use the parameters colortype and bitdepth of the simple +encoding function. + +If, when encoding, you don't want LodePNG to choose the output PNG color type +but control it yourself, you need to set auto_convert in the encoder settings +to false, and specify the color type you want in the LodePNGInfo of the +encoder (including palette: it can generate a palette if auto_convert is true, +otherwise not). + +If the input and output color type differ (whether user chosen or auto chosen), +LodePNG will do a color conversion, which follows the rules below, and may +sometimes result in an error. + +To avoid some confusion: +-the decoder converts from PNG to raw image +-the encoder converts from raw image to PNG +-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image +-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG +-when encoding, the color type in LodePNGInfo is ignored if auto_convert + is enabled, it is automatically generated instead +-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original + PNG image, but it can be ignored since the raw image has the color type you requested instead +-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion + between the color types is done if the color types are supported. If it is not + supported, an error is returned. If the types are the same, no conversion is done. +-even though some conversions aren't supported, LodePNG supports loading PNGs from any + colortype and saving PNGs to any colortype, sometimes it just requires preparing + the raw image correctly before encoding. +-both encoder and decoder use the same color converter. + +The function lodepng_convert does the color conversion. It is available in the +interface but normally isn't needed since the encoder and decoder already call +it. + +Non supported color conversions: +-color to grayscale when non-gray pixels are present: no error is thrown, but +the result will look ugly because only the red channel is taken (it assumes all +three channels are the same in this case so ignores green and blue). The reason +no error is given is to allow converting from three-channel grayscale images to +one-channel even if there are numerical imprecisions. +-anything to palette when the palette does not have an exact match for a from-color +in it: in this case an error is thrown + +Supported color conversions: +-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA +-any gray or gray+alpha, to gray or gray+alpha +-anything to a palette, as long as the palette has the requested colors in it +-removing alpha channel +-higher to smaller bitdepth, and vice versa + +If you want no color conversion to be done (e.g. for speed or control): +-In the encoder, you can make it save a PNG with any color type by giving the +raw color mode and LodePNGInfo the same color mode, and setting auto_convert to +false. +-In the decoder, you can make it store the pixel data in the same color type +as the PNG has, by setting the color_convert setting to false. Settings in +info_raw are then ignored. + +6.3. padding bits +----------------- + +In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines +have a bit amount that isn't a multiple of 8, then padding bits are used so that each +scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output. +The raw input image you give to the encoder, and the raw output image you get from the decoder +will NOT have these padding bits, e.g. in the case of a 1-bit image with a width +of 7 pixels, the first pixel of the second scanline will the 8th bit of the first byte, +not the first bit of a new byte. + +6.4. A note about 16-bits per channel and endianness +---------------------------------------------------- + +LodePNG uses unsigned char arrays for 16-bit per channel colors too, just like +for any other color format. The 16-bit values are stored in big endian (most +significant byte first) in these arrays. This is the opposite order of the +little endian used by x86 CPU's. + +LodePNG always uses big endian because the PNG file format does so internally. +Conversions to other formats than PNG uses internally are not supported by +LodePNG on purpose, there are myriads of formats, including endianness of 16-bit +colors, the order in which you store R, G, B and A, and so on. Supporting and +converting to/from all that is outside the scope of LodePNG. + +This may mean that, depending on your use case, you may want to convert the big +endian output of LodePNG to little endian with a for loop. This is certainly not +always needed, many applications and libraries support big endian 16-bit colors +anyway, but it means you cannot simply cast the unsigned char* buffer to an +unsigned short* buffer on x86 CPUs. + + +7. error values +--------------- + +All functions in LodePNG that return an error code, return 0 if everything went +OK, or a non-zero code if there was an error. + +The meaning of the LodePNG error values can be retrieved with the function +lodepng_error_text: given the numerical error code, it returns a description +of the error in English as a string. + +Check the implementation of lodepng_error_text to see the meaning of each code. + +It is not recommended to use the numerical values to programmatically make +different decisions based on error types as the numbers are not guaranteed to +stay backwards compatible. They are for human consumption only. Programmatically +only 0 or non-0 matter. + + +8. chunks and PNG editing +------------------------- + +If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG +editor that should follow the rules about handling of unknown chunks, or if your +program is able to read other types of chunks than the ones handled by LodePNG, +then that's possible with the chunk functions of LodePNG. + +A PNG chunk has the following layout: + +4 bytes length +4 bytes type name +length bytes data +4 bytes CRC + +8.1. iterating through chunks +----------------------------- + +If you have a buffer containing the PNG image data, then the first chunk (the +IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the +signature of the PNG and are not part of a chunk. But if you start at byte 8 +then you have a chunk, and can check the following things of it. + +NOTE: none of these functions check for memory buffer boundaries. To avoid +exploits, always make sure the buffer contains all the data of the chunks. +When using lodepng_chunk_next, make sure the returned value is within the +allocated memory. + +unsigned lodepng_chunk_length(const unsigned char* chunk): + +Get the length of the chunk's data. The total chunk length is this length + 12. + +void lodepng_chunk_type(char type[5], const unsigned char* chunk): +unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type): + +Get the type of the chunk or compare if it's a certain type + +unsigned char lodepng_chunk_critical(const unsigned char* chunk): +unsigned char lodepng_chunk_private(const unsigned char* chunk): +unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk): + +Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are). +Check if the chunk is private (public chunks are part of the standard, private ones not). +Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical +chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your +program doesn't handle that type of unknown chunk. + +unsigned char* lodepng_chunk_data(unsigned char* chunk): +const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk): + +Get a pointer to the start of the data of the chunk. + +unsigned lodepng_chunk_check_crc(const unsigned char* chunk): +void lodepng_chunk_generate_crc(unsigned char* chunk): + +Check if the crc is correct or generate a correct one. + +unsigned char* lodepng_chunk_next(unsigned char* chunk): +const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk): + +Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these +functions do no boundary checking of the allocated data whatsoever, so make sure there is enough +data available in the buffer to be able to go to the next chunk. + +unsigned lodepng_chunk_append(unsigned char** out, size_t* outsize, const unsigned char* chunk): +unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length, + const char* type, const unsigned char* data): + +These functions are used to create new chunks that are appended to the data in *out that has +length *outsize. The append function appends an existing chunk to the new data. The create +function creates a new chunk with the given parameters and appends it. Type is the 4-letter +name of the chunk. + +8.2. chunks in info_png +----------------------- + +The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3 +buffers (each with size) to contain 3 types of unknown chunks: +the ones that come before the PLTE chunk, the ones that come between the PLTE +and the IDAT chunks, and the ones that come after the IDAT chunks. +It's necessary to make the distinction between these 3 cases because the PNG +standard forces to keep the ordering of unknown chunks compared to the critical +chunks, but does not force any other ordering rules. + +info_png.unknown_chunks_data[0] is the chunks before PLTE +info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT +info_png.unknown_chunks_data[2] is the chunks after IDAT + +The chunks in these 3 buffers can be iterated through and read by using the same +way described in the previous subchapter. + +When using the decoder to decode a PNG, you can make it store all unknown chunks +if you set the option settings.remember_unknown_chunks to 1. By default, this +option is off (0). + +The encoder will always encode unknown chunks that are stored in the info_png. +If you need it to add a particular chunk that isn't known by LodePNG, you can +use lodepng_chunk_append or lodepng_chunk_create to the chunk data in +info_png.unknown_chunks_data[x]. + +Chunks that are known by LodePNG should not be added in that way. E.g. to make +LodePNG add a bKGD chunk, set background_defined to true and add the correct +parameters there instead. + + +9. compiler support +------------------- + +No libraries other than the current standard C library are needed to compile +LodePNG. For the C++ version, only the standard C++ library is needed on top. +Add the files lodepng.c(pp) and lodepng.h to your project, include +lodepng.h where needed, and your program can read/write PNG files. + +It is compatible with C90 and up, and C++03 and up. + +If performance is important, use optimization when compiling! For both the +encoder and decoder, this makes a large difference. + +Make sure that LodePNG is compiled with the same compiler of the same version +and with the same settings as the rest of the program, or the interfaces with +std::vectors and std::strings in C++ can be incompatible. + +CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets. + +*) gcc and g++ + +LodePNG is developed in gcc so this compiler is natively supported. It gives no +warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++ +version 4.7.1 on Linux, 32-bit and 64-bit. + +*) Clang + +Fully supported and warning-free. + +*) Mingw + +The Mingw compiler (a port of gcc for Windows) should be fully supported by +LodePNG. + +*) Visual Studio and Visual C++ Express Edition + +LodePNG should be warning-free with warning level W4. Two warnings were disabled +with pragmas though: warning 4244 about implicit conversions, and warning 4996 +where it wants to use a non-standard function fopen_s instead of the standard C +fopen. + +Visual Studio may want "stdafx.h" files to be included in each source file and +give an error "unexpected end of file while looking for precompiled header". +This is not standard C++ and will not be added to the stock LodePNG. You can +disable it for lodepng.cpp only by right clicking it, Properties, C/C++, +Precompiled Headers, and set it to Not Using Precompiled Headers there. + +NOTE: Modern versions of VS should be fully supported, but old versions, e.g. +VS6, are not guaranteed to work. + +*) Compilers on Macintosh + +LodePNG has been reported to work both with gcc and LLVM for Macintosh, both for +C and C++. + +*) Other Compilers + +If you encounter problems on any compilers, feel free to let me know and I may +try to fix it if the compiler is modern and standards compliant. + + +10. examples +------------ + +This decoder example shows the most basic usage of LodePNG. More complex +examples can be found on the LodePNG website. + +10.1. decoder C++ example +------------------------- + +#include "lodepng.h" +#include + +int main(int argc, char *argv[]) { + const char* filename = argc > 1 ? argv[1] : "test.png"; + + //load and decode + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, filename); + + //if there's an error, display it + if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl; + + //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ... +} + +10.2. decoder C example +----------------------- + +#include "lodepng.h" + +int main(int argc, char *argv[]) { + unsigned error; + unsigned char* image; + size_t width, height; + const char* filename = argc > 1 ? argv[1] : "test.png"; + + error = lodepng_decode32_file(&image, &width, &height, filename); + + if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error)); + + / * use image here * / + + free(image); + return 0; +} + +11. state settings reference +---------------------------- + +A quick reference of some settings to set on the LodePNGState + +For decoding: + +state.decoder.zlibsettings.ignore_adler32: ignore ADLER32 checksums +state.decoder.zlibsettings.custom_...: use custom inflate function +state.decoder.ignore_crc: ignore CRC checksums +state.decoder.ignore_critical: ignore unknown critical chunks +state.decoder.ignore_end: ignore missing IEND chunk. May fail if this corruption causes other errors +state.decoder.color_convert: convert internal PNG color to chosen one +state.decoder.read_text_chunks: whether to read in text metadata chunks +state.decoder.remember_unknown_chunks: whether to read in unknown chunks +state.info_raw.colortype: desired color type for decoded image +state.info_raw.bitdepth: desired bit depth for decoded image +state.info_raw....: more color settings, see struct LodePNGColorMode +state.info_png....: no settings for decoder but ouput, see struct LodePNGInfo + +For encoding: + +state.encoder.zlibsettings.btype: disable compression by setting it to 0 +state.encoder.zlibsettings.use_lz77: use LZ77 in compression +state.encoder.zlibsettings.windowsize: tweak LZ77 windowsize +state.encoder.zlibsettings.minmatch: tweak min LZ77 length to match +state.encoder.zlibsettings.nicematch: tweak LZ77 match where to stop searching +state.encoder.zlibsettings.lazymatching: try one more LZ77 matching +state.encoder.zlibsettings.custom_...: use custom deflate function +state.encoder.auto_convert: choose optimal PNG color type, if 0 uses info_png +state.encoder.filter_palette_zero: PNG filter strategy for palette +state.encoder.filter_strategy: PNG filter strategy to encode with +state.encoder.force_palette: add palette even if not encoding to one +state.encoder.add_id: add LodePNG identifier and version as a text chunk +state.encoder.text_compression: use compressed text chunks for metadata +state.info_raw.colortype: color type of raw input image you provide +state.info_raw.bitdepth: bit depth of raw input image you provide +state.info_raw: more color settings, see struct LodePNGColorMode +state.info_png.color.colortype: desired color type if auto_convert is false +state.info_png.color.bitdepth: desired bit depth if auto_convert is false +state.info_png.color....: more color settings, see struct LodePNGColorMode +state.info_png....: more PNG related settings, see struct LodePNGInfo + + +12. changes +----------- + +The version number of LodePNG is the date of the change given in the format +yyyymmdd. + +Some changes aren't backwards compatible. Those are indicated with a (!) +symbol. + +Not all changes are listed here, the commit history in github lists more: +https://github.com/lvandeve/lodepng + +*) 17 okt 2020: prevent decoding too large text/icc chunks by default. +*) 06 mar 2020: simplified some of the dynamic memory allocations. +*) 12 jan 2020: (!) added 'end' argument to lodepng_chunk_next to allow correct + overflow checks. +*) 14 aug 2019: around 25% faster decoding thanks to huffman lookup tables. +*) 15 jun 2019: (!) auto_choose_color API changed (for bugfix: don't use palette + if gray ICC profile) and non-ICC LodePNGColorProfile renamed to + LodePNGColorStats. +*) 30 dec 2018: code style changes only: removed newlines before opening braces. +*) 10 sep 2018: added way to inspect metadata chunks without full decoding. +*) 19 aug 2018: (!) fixed color mode bKGD is encoded with and made it use + palette index in case of palette. +*) 10 aug 2018: (!) added support for gAMA, cHRM, sRGB and iCCP chunks. This + change is backwards compatible unless you relied on unknown_chunks for those. +*) 11 jun 2018: less restrictive check for pixel size integer overflow +*) 14 jan 2018: allow optionally ignoring a few more recoverable errors +*) 17 sep 2017: fix memory leak for some encoder input error cases +*) 27 nov 2016: grey+alpha auto color model detection bugfix +*) 18 apr 2016: Changed qsort to custom stable sort (for platforms w/o qsort). +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). +*) 08 dec 2015: Made load_file function return error if file can't be opened. +*) 24 okt 2015: Bugfix with decoding to palette output. +*) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. +*) 24 aug 2014: Moved to github +*) 23 aug 2014: Reduced needless memory usage of decoder. +*) 28 jun 2014: Removed fix_png setting, always support palette OOB for + simplicity. Made ColorProfile public. +*) 09 jun 2014: Faster encoder by fixing hash bug and more zeros optimization. +*) 22 dec 2013: Power of two windowsize required for optimization. +*) 15 apr 2013: Fixed bug with LAC_ALPHA and color key. +*) 25 mar 2013: Added an optional feature to ignore some PNG errors (fix_png). +*) 11 mar 2013: (!) Bugfix with custom free. Changed from "my" to "lodepng_" + prefix for the custom allocators and made it possible with a new #define to + use custom ones in your project without needing to change lodepng's code. +*) 28 jan 2013: Bugfix with color key. +*) 27 okt 2012: Tweaks in text chunk keyword length error handling. +*) 8 okt 2012: (!) Added new filter strategy (entropy) and new auto color mode. + (no palette). Better deflate tree encoding. New compression tweak settings. + Faster color conversions while decoding. Some internal cleanups. +*) 23 sep 2012: Reduced warnings in Visual Studio a little bit. +*) 1 sep 2012: (!) Removed #define's for giving custom (de)compression functions + and made it work with function pointers instead. +*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc + and free functions and toggle #defines from compiler flags. Small fixes. +*) 6 may 2012: (!) Made plugging in custom zlib/deflate functions more flexible. +*) 22 apr 2012: (!) Made interface more consistent, renaming a lot. Removed + redundant C++ codec classes. Reduced amount of structs. Everything changed, + but it is cleaner now imho and functionality remains the same. Also fixed + several bugs and shrunk the implementation code. Made new samples. +*) 6 nov 2011: (!) By default, the encoder now automatically chooses the best + PNG color model and bit depth, based on the amount and type of colors of the + raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color. +*) 9 okt 2011: simpler hash chain implementation for the encoder. +*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching. +*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking. + A bug with the PNG filtertype heuristic was fixed, so that it chooses much + better ones (it's quite significant). A setting to do an experimental, slow, + brute force search for PNG filter types is added. +*) 17 aug 2011: (!) changed some C zlib related function names. +*) 16 aug 2011: made the code less wide (max 120 characters per line). +*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors. +*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled. +*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman + to optimize long sequences of zeros. +*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and + LodePNG_InfoColor_canHaveAlpha functions for convenience. +*) 7 nov 2010: added LodePNG_error_text function to get error code description. +*) 30 okt 2010: made decoding slightly faster +*) 26 okt 2010: (!) changed some C function and struct names (more consistent). + Reorganized the documentation and the declaration order in the header. +*) 08 aug 2010: only changed some comments and external samples. +*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version. +*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers. +*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could + read by ignoring the problem but windows apps couldn't. +*) 06 jun 2008: added more error checks for out of memory cases. +*) 26 apr 2008: added a few more checks here and there to ensure more safety. +*) 06 mar 2008: crash with encoding of strings fixed +*) 02 feb 2008: support for international text chunks added (iTXt) +*) 23 jan 2008: small cleanups, and #defines to divide code in sections +*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor. +*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder. +*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added + Also various fixes, such as in the deflate and the padding bits code. +*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved + filtering code of encoder. +*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A + C++ wrapper around this provides an interface almost identical to before. + Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code + are together in these files but it works both for C and C++ compilers. +*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks +*) 30 aug 2007: bug fixed which makes this Borland C++ compatible +*) 09 aug 2007: some VS2005 warnings removed again +*) 21 jul 2007: deflate code placed in new namespace separate from zlib code +*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images +*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing + invalid std::vector element [0] fixed, and level 3 and 4 warnings removed +*) 02 jun 2007: made the encoder add a tag with version by default +*) 27 may 2007: zlib and png code separated (but still in the same file), + simple encoder/decoder functions added for more simple usage cases +*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69), + moved some examples from here to lodepng_examples.cpp +*) 12 may 2007: palette decoding bug fixed +*) 24 apr 2007: changed the license from BSD to the zlib license +*) 11 mar 2007: very simple addition: ability to encode bKGD chunks. +*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding + palettized PNG images. Plus little interface change with palette and texts. +*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes. + Fixed a bug where the end code of a block had length 0 in the Huffman tree. +*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented + and supported by the encoder, resulting in smaller PNGs at the output. +*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone. +*) 24 jan 2007: gave encoder an error interface. Added color conversion from any + greyscale type to 8-bit greyscale with or without alpha. +*) 21 jan 2007: (!) Totally changed the interface. It allows more color types + to convert to and is more uniform. See the manual for how it works now. +*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days: + encode/decode custom tEXt chunks, separate classes for zlib & deflate, and + at last made the decoder give errors for incorrect Adler32 or Crc. +*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel. +*) 29 dec 2006: Added support for encoding images without alpha channel, and + cleaned out code as well as making certain parts faster. +*) 28 dec 2006: Added "Settings" to the encoder. +*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now. + Removed some code duplication in the decoder. Fixed little bug in an example. +*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter. + Fixed a bug of the decoder with 16-bit per color. +*) 15 okt 2006: Changed documentation structure +*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the + given image buffer, however for now it's not compressed. +*) 08 sep 2006: (!) Changed to interface with a Decoder class +*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different + way. Renamed decodePNG to decodePNGGeneric. +*) 29 jul 2006: (!) Changed the interface: image info is now returned as a + struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy. +*) 28 jul 2006: Cleaned the code and added new error checks. + Corrected terminology "deflate" into "inflate". +*) 23 jun 2006: Added SDL example in the documentation in the header, this + example allows easy debugging by displaying the PNG and its transparency. +*) 22 jun 2006: (!) Changed way to obtain error value. Added + loadFile function for convenience. Made decodePNG32 faster. +*) 21 jun 2006: (!) Changed type of info vector to unsigned. + Changed position of palette in info vector. Fixed an important bug that + happened on PNGs with an uncompressed block. +*) 16 jun 2006: Internally changed unsigned into unsigned where + needed, and performed some optimizations. +*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them + in LodePNG namespace. Changed the order of the parameters. Rewrote the + documentation in the header. Renamed files to lodepng.cpp and lodepng.h +*) 22 apr 2006: Optimized and improved some code +*) 07 sep 2005: (!) Changed to std::vector interface +*) 12 aug 2005: Initial release (C++, decoder only) + + +13. contact information +----------------------- + +Feel free to contact me with suggestions, problems, comments, ... concerning +LodePNG. If you encounter a PNG image that doesn't work properly with this +decoder, feel free to send it and I'll use it to find and fix the problem. + +My email address is (puzzle the account and domain together with an @ symbol): +Domain: gmail dot com. +Account: lode dot vandevenne. + + +Copyright (c) 2005-2020 Lode Vandevenne +*/ diff --git a/include/liblvgl/extra/libs/png/lv_png.h b/include/liblvgl/extra/libs/png/lv_png.h new file mode 100644 index 0000000..ef63454 --- /dev/null +++ b/include/liblvgl/extra/libs/png/lv_png.h @@ -0,0 +1,46 @@ +/** + * @file lv_png.h + * + */ + +#ifndef LV_PNG_H +#define LV_PNG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#if LV_USE_PNG + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register the PNG decoder functions in LVGL + */ +void lv_png_init(void); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_PNG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PNG_H*/ diff --git a/include/liblvgl/extra/libs/qrcode/lv_qrcode.h b/include/liblvgl/extra/libs/qrcode/lv_qrcode.h new file mode 100644 index 0000000..c8db4e5 --- /dev/null +++ b/include/liblvgl/extra/libs/qrcode/lv_qrcode.h @@ -0,0 +1,69 @@ +/** + * @file lv_qrcode + * + */ + +#ifndef LV_QRCODE_H +#define LV_QRCODE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" +#if LV_USE_QRCODE + +/********************* + * DEFINES + *********************/ + +extern const lv_obj_class_t lv_qrcode_class; + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an empty QR code (an `lv_canvas`) object. + * @param parent point to an object where to create the QR code + * @param size width and height of the QR code + * @param dark_color dark color of the QR code + * @param light_color light color of the QR code + * @return pointer to the created QR code object + */ +lv_obj_t * lv_qrcode_create(lv_obj_t * parent, lv_coord_t size, lv_color_t dark_color, lv_color_t light_color); + +/** + * Set the data of a QR code object + * @param qrcode pointer to aQ code object + * @param data data to display + * @param data_len length of data in bytes + * @return LV_RES_OK: if no error; LV_RES_INV: on error + */ +lv_res_t lv_qrcode_update(lv_obj_t * qrcode, const void * data, uint32_t data_len); + +/** + * DEPRECATED: Use normal lv_obj_del instead + * Delete a QR code object + * @param qrcode pointer to a QR code object + */ +void lv_qrcode_delete(lv_obj_t * qrcode); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_QRCODE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_QRCODE_H*/ diff --git a/include/liblvgl/extra/libs/qrcode/qrcodegen.h b/include/liblvgl/extra/libs/qrcode/qrcodegen.h new file mode 100644 index 0000000..b484e91 --- /dev/null +++ b/include/liblvgl/extra/libs/qrcode/qrcodegen.h @@ -0,0 +1,319 @@ +/* + * QR Code generator library (C) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#pragma once + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * This library creates QR Code symbols, which is a type of two-dimension barcode. + * Invented by Denso Wave and described in the ISO/IEC 18004 standard. + * A QR Code structure is an immutable square grid of black and white cells. + * The library provides functions to create a QR Code from text or binary data. + * The library covers the QR Code Model 2 specification, supporting all versions (sizes) + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. + * + * Ways to create a QR Code object: + * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). + * - Low level: Custom-make the list of segments and call + * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). + * (Note that all ways require supplying the desired error correction level and various byte buffers.) + */ + + +/*---- Enum and struct types----*/ + +/* + * The error correction level in a QR Code symbol. + */ +enum qrcodegen_Ecc { + // Must be declared in ascending order of error protection + // so that an internal qrcodegen function works properly + qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords + qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords + qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords + qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords +}; + + +/* + * The mask pattern used in a QR Code symbol. + */ +enum qrcodegen_Mask { + // A special value to tell the QR Code encoder to + // automatically select an appropriate mask pattern + qrcodegen_Mask_AUTO = -1, + // The eight actual mask patterns + qrcodegen_Mask_0 = 0, + qrcodegen_Mask_1, + qrcodegen_Mask_2, + qrcodegen_Mask_3, + qrcodegen_Mask_4, + qrcodegen_Mask_5, + qrcodegen_Mask_6, + qrcodegen_Mask_7, +}; + + +/* + * Describes how a segment's data bits are interpreted. + */ +enum qrcodegen_Mode { + qrcodegen_Mode_NUMERIC = 0x1, + qrcodegen_Mode_ALPHANUMERIC = 0x2, + qrcodegen_Mode_BYTE = 0x4, + qrcodegen_Mode_KANJI = 0x8, + qrcodegen_Mode_ECI = 0x7, +}; + + +/* + * A segment of character/binary/control data in a QR Code symbol. + * The mid-level way to create a segment is to take the payload data + * and call a factory function such as qrcodegen_makeNumeric(). + * The low-level way to create a segment is to custom-make the bit buffer + * and initialize a qrcodegen_Segment struct with appropriate values. + * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. + * Any segment longer than this is meaningless for the purpose of generating QR Codes. + * Moreover, the maximum allowed bit length is 32767 because + * the largest QR Code (version 40) has 31329 modules. + */ +struct qrcodegen_Segment { + // The mode indicator of this segment. + enum qrcodegen_Mode mode; + + // The length of this segment's unencoded data. Measured in characters for + // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. + // Always zero or positive. Not the same as the data's bit length. + int numChars; + + // The data bits of this segment, packed in bitwise big endian. + // Can be null if the bit length is zero. + uint8_t *data; + + // The number of valid data bits used in the buffer. Requires + // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. + // The character count (numChars) must agree with the mode and the bit buffer length. + int bitLength; +}; + + + +/*---- Macro constants and functions ----*/ + +#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard +#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard + +// Calculates the number of bytes needed to store any QR Code up to and including the given version number, +// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' +// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). +// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. +#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) + +// The worst-case number of bytes needed to store one QR Code, up to and including +// version 40. This value equals 3918, which is just under 4 kilobytes. +// Use this more convenient value to avoid calculating tighter memory bounds for buffers. +#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) + + + +/*---- Functions (high level) to generate QR Codes ----*/ + +/* + * Encodes the given text string to a QR Code, returning true if encoding succeeded. + * If the data is too long to fit in any version in the given range + * at the given ECC level, then false is returned. + * - The input text must be encoded in UTF-8 and contain no NULs. + * - The variables ecl and mask must correspond to enum constant values. + * - Requires 1 <= minVersion <= maxVersion <= 40. + * - The arrays tempBuffer and qrcode must each have a length + * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). + * - After the function returns, tempBuffer contains no useful data. + * - If successful, the resulting QR Code may use numeric, + * alphanumeric, or byte mode to encode the text. + * - In the most optimistic case, a QR Code at version 40 with low ECC + * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string + * up to 4296 characters, or any digit string up to 7089 characters. + * These numbers represent the hard upper limit of the QR Code standard. + * - Please consult the QR Code specification for information on + * data capacities per version, ECC level, and text encoding mode. + */ +bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); + + +/* + * Encodes the given binary data to a QR Code, returning true if encoding succeeded. + * If the data is too long to fit in any version in the given range + * at the given ECC level, then false is returned. + * - The input array range dataAndTemp[0 : dataLen] should normally be + * valid UTF-8 text, but is not required by the QR Code standard. + * - The variables ecl and mask must correspond to enum constant values. + * - Requires 1 <= minVersion <= maxVersion <= 40. + * - The arrays dataAndTemp and qrcode must each have a length + * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). + * - After the function returns, the contents of dataAndTemp may have changed, + * and does not represent useful data anymore. + * - If successful, the resulting QR Code will use byte mode to encode the data. + * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte + * sequence up to length 2953. This is the hard upper limit of the QR Code standard. + * - Please consult the QR Code specification for information on + * data capacities per version, ECC level, and text encoding mode. + */ +bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); + + +/*---- Functions (low level) to generate QR Codes ----*/ + +/* + * Renders a QR Code representing the given segments at the given error correction level. + * The smallest possible QR Code version is automatically chosen for the output. Returns true if + * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level + * of the result may be higher than the ecl argument if it can be done without increasing the version. + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). + * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will + * result in them being clobbered, but the QR Code output will still be correct. + * But the qrcode array must not overlap tempBuffer or any segment's data buffer. + */ +bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, + enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); + + +/* + * Renders a QR Code representing the given segments with the given encoding parameters. + * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. + * The smallest possible QR Code version within the given range is automatically + * chosen for the output. Iff boostEcl is true, then the ECC level of the result + * may be higher than the ecl argument if it can be done without increasing the + * version. The mask number is either between 0 to 7 (inclusive) to force that + * mask, or -1 to automatically choose an appropriate mask (which may be slow). + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). + * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will + * result in them being clobbered, but the QR Code output will still be correct. + * But the qrcode array must not overlap tempBuffer or any segment's data buffer. + */ +bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, + int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]); + + +/* + * Tests whether the given string can be encoded as a segment in alphanumeric mode. + * A string is encodable iff each character is in the following set: 0 to 9, A to Z + * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ +bool qrcodegen_isAlphanumeric(const char *text); + + +/* + * Tests whether the given string can be encoded as a segment in numeric mode. + * A string is encodable iff each character is in the range 0 to 9. + */ +bool qrcodegen_isNumeric(const char *text); + + +/* + * Returns the number of bytes (uint8_t) needed for the data buffer of a segment + * containing the given number of characters using the given mode. Notes: + * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or + * the number of needed bits exceeds INT16_MAX (i.e. 32767). + * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. + * - It is okay for the user to allocate more bytes for the buffer than needed. + * - For byte mode, numChars measures the number of bytes, not Unicode code points. + * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. + * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. + */ +size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); + + +/* + * Returns a segment representing the given binary data encoded in + * byte mode. All input byte arrays are acceptable. Any text string + * can be converted to UTF-8 bytes and encoded as a byte mode segment. + */ +struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); + + +/* + * Returns a segment representing the given string of decimal digits encoded in numeric mode. + */ +struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); + + +/* + * Returns a segment representing the given text string encoded in alphanumeric mode. + * The characters allowed are: 0 to 9, A to Z (uppercase only), space, + * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ +struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); + + +/* + * Returns a segment representing an Extended Channel Interpretation + * (ECI) designator with the given assignment value. + */ +struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); + + +/*---- Functions to extract raw data from QR Codes ----*/ + +/* + * Returns the side length of the given QR Code, assuming that encoding succeeded. + * The result is in the range [21, 177]. Note that the length of the array buffer + * is related to the side length - every 'uint8_t qrcode[]' must have length at least + * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). + */ +int qrcodegen_getSize(const uint8_t qrcode[]); + + +/* + * Returns the color of the module (pixel) at the given coordinates, which is false + * for white or true for black. The top left corner has the coordinates (x=0, y=0). + * If the given coordinates are out of bounds, then false (white) is returned. + */ +bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); + +/* + * Returns the qrcode size of the specified version. Returns -1 on failure + */ +int qrcodegen_version2size(int version); +/* + * Returns the min version of the data that can be stored. Returns -1 on failure + */ +int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, size_t dataLen); + +#ifdef __cplusplus +} +#endif diff --git a/include/liblvgl/extra/libs/rlottie/lv_rlottie.h b/include/liblvgl/extra/libs/rlottie/lv_rlottie.h new file mode 100644 index 0000000..a8aca7b --- /dev/null +++ b/include/liblvgl/extra/libs/rlottie/lv_rlottie.h @@ -0,0 +1,75 @@ +/** + * @file lv_rlottie.h + * + */ + +#ifndef LV_RLOTTIE_H +#define LV_RLOTTIE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" +#if LV_USE_RLOTTIE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef enum { + LV_RLOTTIE_CTRL_FORWARD = 0, + LV_RLOTTIE_CTRL_BACKWARD = 1, + LV_RLOTTIE_CTRL_PAUSE = 2, + LV_RLOTTIE_CTRL_PLAY = 0, /* Yes, play = 0 is the default mode */ + LV_RLOTTIE_CTRL_LOOP = 8, +} lv_rlottie_ctrl_t; + +/** definition in lottieanimation_capi.c */ +struct Lottie_Animation_S; +typedef struct { + lv_img_t img_ext; + struct Lottie_Animation_S * animation; + lv_timer_t * task; + lv_img_dsc_t imgdsc; + size_t total_frames; + size_t current_frame; + size_t framerate; + uint32_t * allocated_buf; + size_t allocated_buffer_size; + size_t scanline_width; + lv_rlottie_ctrl_t play_ctrl; + size_t dest_frame; +} lv_rlottie_t; + +extern const lv_obj_class_t lv_rlottie_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_rlottie_create_from_file(lv_obj_t * parent, lv_coord_t width, lv_coord_t height, const char * path); + +lv_obj_t * lv_rlottie_create_from_raw(lv_obj_t * parent, lv_coord_t width, lv_coord_t height, + const char * rlottie_desc); + +void lv_rlottie_set_play_mode(lv_obj_t * rlottie, const lv_rlottie_ctrl_t ctrl); +void lv_rlottie_set_current_frame(lv_obj_t * rlottie, const size_t goto_frame); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_RLOTTIE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_RLOTTIE_H*/ diff --git a/include/liblvgl/extra/libs/sjpg/lv_sjpg.h b/include/liblvgl/extra/libs/sjpg/lv_sjpg.h new file mode 100644 index 0000000..d06e80d --- /dev/null +++ b/include/liblvgl/extra/libs/sjpg/lv_sjpg.h @@ -0,0 +1,43 @@ +/** + * @file lv_sjpg.h + * + */ + +#ifndef LV_SJPEG_H +#define LV_SJPEG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#if LV_USE_SJPG + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_split_jpeg_init(void); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SJPG*/ + +#ifdef __cplusplus +} +#endif + +#endif /* LV_SJPEG_H */ diff --git a/include/liblvgl/extra/libs/sjpg/tjpgd.h b/include/liblvgl/extra/libs/sjpg/tjpgd.h new file mode 100644 index 0000000..866e6b3 --- /dev/null +++ b/include/liblvgl/extra/libs/sjpg/tjpgd.h @@ -0,0 +1,93 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor R0.03 include file (C)ChaN, 2021 +/----------------------------------------------------------------------------*/ +#ifndef DEF_TJPGDEC +#define DEF_TJPGDEC + +#ifdef __cplusplus +extern "C" { +#endif + +#include "liblvgl/lv_conf_internal.h" +#if LV_USE_SJPG + +#include "tjpgdcnf.h" +#include +#include + +#if JD_FASTDECODE >= 1 +typedef int16_t jd_yuv_t; +#else +typedef uint8_t jd_yuv_t; +#endif + + +/* Error code */ +typedef enum { + JDR_OK = 0, /* 0: Succeeded */ + JDR_INTR, /* 1: Interrupted by output function */ + JDR_INP, /* 2: Device error or wrong termination of input stream */ + JDR_MEM1, /* 3: Insufficient memory pool for the image */ + JDR_MEM2, /* 4: Insufficient stream input buffer */ + JDR_PAR, /* 5: Parameter error */ + JDR_FMT1, /* 6: Data format error (may be broken data) */ + JDR_FMT2, /* 7: Right format but not supported */ + JDR_FMT3 /* 8: Not supported JPEG standard */ +} JRESULT; + +/* Rectangular region in the output image */ +typedef struct { + uint16_t left; /* Left end */ + uint16_t right; /* Right end */ + uint16_t top; /* Top end */ + uint16_t bottom; /* Bottom end */ +} JRECT; + +/* Decompressor object structure */ +typedef struct JDEC JDEC; +struct JDEC { + size_t dctr; /* Number of bytes available in the input buffer */ + uint8_t* dptr; /* Current data read ptr */ + uint8_t* inbuf; /* Bit stream input buffer */ + uint8_t dbit; /* Number of bits availavble in wreg or reading bit mask */ + uint8_t scale; /* Output scaling ratio */ + uint8_t msx, msy; /* MCU size in unit of block (width, height) */ + uint8_t qtid[3]; /* Quantization table ID of each component, Y, Cb, Cr */ + uint8_t ncomp; /* Number of color components 1:grayscale, 3:color */ + int16_t dcv[3]; /* Previous DC element of each component */ + uint16_t nrst; /* Restart inverval */ + uint16_t width, height; /* Size of the input image (pixel) */ + uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ + uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ + uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ + int32_t* qttbl[4]; /* Dequantizer tables [id] */ +#if JD_FASTDECODE >= 1 + uint32_t wreg; /* Working shift register */ + uint8_t marker; /* Detected marker (0:None) */ +#if JD_FASTDECODE == 2 + uint8_t longofs[2][2]; /* Table offset of long code [id][dcac] */ + uint16_t* hufflut_ac[2]; /* Fast huffman decode tables for AC short code [id] */ + uint8_t* hufflut_dc[2]; /* Fast huffman decode tables for DC short code [id] */ +#endif +#endif + void* workbuf; /* Working buffer for IDCT and RGB output */ + jd_yuv_t* mcubuf; /* Working buffer for the MCU */ + void* pool; /* Pointer to available memory pool */ + size_t sz_pool; /* Size of momory pool (bytes available) */ + size_t (*infunc)(JDEC*, uint8_t*, size_t); /* Pointer to jpeg stream input function */ + void* device; /* Pointer to I/O device identifiler for the session */ +}; + + + +/* TJpgDec API functions */ +JRESULT jd_prepare (JDEC* jd, size_t (*infunc)(JDEC*,uint8_t*,size_t), void* pool, size_t sz_pool, void* dev); +JRESULT jd_decomp (JDEC* jd, int (*outfunc)(JDEC*,void*,JRECT*), uint8_t scale); + +#endif /*LV_USE_SJPG*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _TJPGDEC */ diff --git a/include/liblvgl/extra/libs/sjpg/tjpgdcnf.h b/include/liblvgl/extra/libs/sjpg/tjpgdcnf.h new file mode 100644 index 0000000..6d425e6 --- /dev/null +++ b/include/liblvgl/extra/libs/sjpg/tjpgdcnf.h @@ -0,0 +1,33 @@ +/*----------------------------------------------*/ +/* TJpgDec System Configurations R0.03 */ +/*----------------------------------------------*/ + +#define JD_SZBUF 512 +/* Specifies size of stream input buffer */ + +#define JD_FORMAT 0 +/* Specifies output pixel format. +/ 0: RGB888 (24-bit/pix) +/ 1: RGB565 (16-bit/pix) +/ 2: Grayscale (8-bit/pix) +*/ + +#define JD_USE_SCALE 1 +/* Switches output descaling feature. +/ 0: Disable +/ 1: Enable +*/ + +#define JD_TBLCLIP 1 +/* Use table conversion for saturation arithmetic. A bit faster, but increases 1 KB of code size. +/ 0: Disable +/ 1: Enable +*/ + +#define JD_FASTDECODE 0 +/* Optimization level +/ 0: Basic optimization. Suitable for 8/16-bit MCUs. +/ 1: + 32-bit barrel shifter. Suitable for 32-bit MCUs. +/ 2: + Table conversion for huffman decoding (wants 6 << HUFF_BIT bytes of RAM) +*/ + diff --git a/include/liblvgl/extra/lv_extra.h b/include/liblvgl/extra/lv_extra.h new file mode 100644 index 0000000..c0306a9 --- /dev/null +++ b/include/liblvgl/extra/lv_extra.h @@ -0,0 +1,48 @@ +/** + * @file lv_extra.h + * + */ + +#ifndef LV_EXTRA_H +#define LV_EXTRA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "layouts/lv_layouts.h" +#include "libs/lv_libs.h" +#include "others/lv_others.h" +#include "themes/lv_themes.h" +#include "widgets/lv_widgets.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the extra components + */ +void lv_extra_init(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_EXTRA_H*/ diff --git a/include/liblvgl/extra/others/fragment/lv_fragment.h b/include/liblvgl/extra/others/fragment/lv_fragment.h new file mode 100644 index 0000000..9b7312f --- /dev/null +++ b/include/liblvgl/extra/others/fragment/lv_fragment.h @@ -0,0 +1,339 @@ +/** + * Public header for Fragment + * @file lv_fragment.h + */ + +#ifndef LV_FRAGMENT_H +#define LV_FRAGMENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_FRAGMENT + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct _lv_fragment_manager_t lv_fragment_manager_t; + +typedef struct _lv_fragment_t lv_fragment_t; +typedef struct _lv_fragment_class_t lv_fragment_class_t; +typedef struct _lv_fragment_managed_states_t lv_fragment_managed_states_t; + +struct _lv_fragment_t { + /** + * Class of this fragment + */ + const lv_fragment_class_t * cls; + /** + * Managed fragment states. If not null, then this fragment is managed. + * + * @warning Don't modify values inside this struct! + */ + lv_fragment_managed_states_t * managed; + /** + * Child fragment manager + */ + lv_fragment_manager_t * child_manager; + /** + * lv_obj returned by create_obj_cb + */ + lv_obj_t * obj; + +}; + +struct _lv_fragment_class_t { + /** + * Constructor function for fragment class + * @param self Fragment instance + * @param args Arguments assigned by fragment manager + */ + void (*constructor_cb)(lv_fragment_t * self, void * args); + + /** + * Destructor function for fragment class + * @param self Fragment instance, will be freed after this call + */ + void (*destructor_cb)(lv_fragment_t * self); + + /** + * Fragment attached to manager + * @param self Fragment instance + */ + void (*attached_cb)(lv_fragment_t * self); + + /** + * Fragment detached from manager + * @param self Fragment instance + */ + void (*detached_cb)(lv_fragment_t * self); + + /** + * Create objects + * @param self Fragment instance + * @param container Container of the objects should be created upon + * @return Created object, NULL if multiple objects has been created + */ + lv_obj_t * (*create_obj_cb)(lv_fragment_t * self, lv_obj_t * container); + + /** + * + * @param self Fragment instance + * @param obj lv_obj returned by create_obj_cb + */ + void (*obj_created_cb)(lv_fragment_t * self, lv_obj_t * obj); + + /** + * Called before objects in the fragment will be deleted. + * + * @param self Fragment instance + * @param obj object with this fragment + */ + void (*obj_will_delete_cb)(lv_fragment_t * self, lv_obj_t * obj); + + /** + * Called when the object created by fragment received `LV_EVENT_DELETE` event + * @param self Fragment instance + * @param obj object with this fragment + */ + void (*obj_deleted_cb)(lv_fragment_t * self, lv_obj_t * obj); + + /** + * Handle event + * @param self Fragment instance + * @param which User-defined ID of event + * @param data1 User-defined data + * @param data2 User-defined data + */ + bool (*event_cb)(lv_fragment_t * self, int code, void * userdata); + + /** + * *REQUIRED*: Allocation size of fragment + */ + size_t instance_size; +}; + +/** + * Fragment states + */ +typedef struct _lv_fragment_managed_states_t { + /** + * Class of the fragment + */ + const lv_fragment_class_t * cls; + /** + * Manager the fragment attached to + */ + lv_fragment_manager_t * manager; + /** + * Container object the fragment adding view to + */ + lv_obj_t * const * container; + /** + * Fragment instance + */ + lv_fragment_t * instance; + /** + * true between `create_obj_cb` and `obj_deleted_cb` + */ + bool obj_created; + /** + * true before `lv_fragment_del_obj` is called. Don't touch any object if this is true + */ + bool destroying_obj; + /** + * true if this fragment is in navigation stack that can be popped + */ + bool in_stack; +} lv_fragment_managed_states_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create fragment manager instance + * @param parent Parent fragment if this manager is placed inside another fragment, can be null. + * @return Fragment manager instance + */ +lv_fragment_manager_t * lv_fragment_manager_create(lv_fragment_t * parent); + +/** + * Destroy fragment manager instance + * @param manager Fragment manager instance + */ +void lv_fragment_manager_del(lv_fragment_manager_t * manager); + +/** + * Create object of all fragments managed by this manager. + * @param manager Fragment manager instance + */ +void lv_fragment_manager_create_obj(lv_fragment_manager_t * manager); + +/** + * Delete object created by all fragments managed by this manager. Instance of fragments will not be deleted. + * @param manager Fragment manager instance + */ +void lv_fragment_manager_del_obj(lv_fragment_manager_t * manager); + +/** + * Attach fragment to manager, and add to container. + * @param manager Fragment manager instance + * @param fragment Fragment instance + * @param container Pointer to container object for manager to add objects to + */ +void lv_fragment_manager_add(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container); + +/** + * Detach and destroy fragment. If fragment is in navigation stack, remove from it. + * @param manager Fragment manager instance + * @param fragment Fragment instance + */ +void lv_fragment_manager_remove(lv_fragment_manager_t * manager, lv_fragment_t * fragment); + +/** + * Attach fragment to manager and add to navigation stack. + * @param manager Fragment manager instance + * @param fragment Fragment instance + * @param container Pointer to container object for manager to add objects to + */ +void lv_fragment_manager_push(lv_fragment_manager_t * manager, lv_fragment_t * fragment, lv_obj_t * const * container); + +/** + * Remove the top-most fragment for stack + * @param manager Fragment manager instance + * @return true if there is fragment to pop + */ +bool lv_fragment_manager_pop(lv_fragment_manager_t * manager); + +/** + * Replace fragment. Old item in the stack will be removed. + * @param manager Fragment manager instance + * @param fragment Fragment instance + * @param container Pointer to container object for manager to add objects to + */ +void lv_fragment_manager_replace(lv_fragment_manager_t * manager, lv_fragment_t * fragment, + lv_obj_t * const * container); + +/** + * Send event to top-most fragment + * @param manager Fragment manager instance + * @param code User-defined ID of event + * @param userdata User-defined data + * @return true if fragment returned true + */ +bool lv_fragment_manager_send_event(lv_fragment_manager_t * manager, int code, void * userdata); + +/** + * Get stack size of this fragment manager + * @param manager Fragment manager instance + * @return Stack size of this fragment manager + */ +size_t lv_fragment_manager_get_stack_size(lv_fragment_manager_t * manager); + +/** + * Get top most fragment instance + * @param manager Fragment manager instance + * @return Top most fragment instance + */ +lv_fragment_t * lv_fragment_manager_get_top(lv_fragment_manager_t * manager); + +/** + * Find first fragment instance in the container + * @param manager Fragment manager instance + * @param container Container which target fragment added to + * @return First fragment instance in the container + */ +lv_fragment_t * lv_fragment_manager_find_by_container(lv_fragment_manager_t * manager, const lv_obj_t * container); + +/** + * Get parent fragment + * @param manager Fragment manager instance + * @return Parent fragment instance + */ +lv_fragment_t * lv_fragment_manager_get_parent_fragment(lv_fragment_manager_t * manager); + + +/** + * Create a fragment instance. + * + * @param cls Fragment class. This fragment must return non null object. + * @param args Arguments assigned by fragment manager + * @return Fragment instance + */ +lv_fragment_t * lv_fragment_create(const lv_fragment_class_t * cls, void * args); + +/** + * Destroy a fragment. + * @param fragment Fragment instance. + */ +void lv_fragment_del(lv_fragment_t * fragment); + +/** + * Get associated manager of this fragment + * @param fragment Fragment instance + * @return Fragment manager instance + */ +lv_fragment_manager_t * lv_fragment_get_manager(lv_fragment_t * fragment); + +/** + * Get container object of this fragment + * @param fragment Fragment instance + * @return Reference to container object + */ +lv_obj_t * const * lv_fragment_get_container(lv_fragment_t * fragment); + +/** + * Get parent fragment of this fragment + * @param fragment Fragment instance + * @return Parent fragment + */ +lv_fragment_t * lv_fragment_get_parent(lv_fragment_t * fragment); + +/** + * Create object by fragment. + * + * @param fragment Fragment instance. + * @param container Container of the objects should be created upon. + * @return Created object + */ +lv_obj_t * lv_fragment_create_obj(lv_fragment_t * fragment, lv_obj_t * container); + +/** + * Delete created object of a fragment + * + * @param fragment Fragment instance. + */ +void lv_fragment_del_obj(lv_fragment_t * fragment); + +/** + * Destroy obj in fragment, and recreate them. + * @param fragment Fragment instance + */ +void lv_fragment_recreate_obj(lv_fragment_t * fragment); + + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_FRAGMENT*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FRAGMENT_H*/ diff --git a/include/liblvgl/extra/others/gridnav/lv_gridnav.h b/include/liblvgl/extra/others/gridnav/lv_gridnav.h new file mode 100644 index 0000000..8939120 --- /dev/null +++ b/include/liblvgl/extra/others/gridnav/lv_gridnav.h @@ -0,0 +1,123 @@ +/** + * @file lv_templ.c + * + */ + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*This typedef exists purely to keep -Wpedantic happy when the file is empty.*/ +/*It can be removed.*/ +typedef int _keep_pedantic_happy; + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ +/** + * @file lv_gridnav.h + * + */ + +#ifndef LV_GRIDFOCUS_H +#define LV_GRIDFOCUS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_GRIDNAV + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef enum { + LV_GRIDNAV_CTRL_NONE = 0x0, + + /** + * If there is no next/previous object in a direction, + * the focus goes to the object in the next/previous row (on left/right keys) + * or first/last row (on up/down keys) + */ + LV_GRIDNAV_CTRL_ROLLOVER = 0x1, + + /** + * If an arrow is pressed and the focused object can be scrolled in that direction + * then it will be scrolled instead of going to the next/previous object. + * If there is no more room for scrolling the next/previous object will be focused normally */ + LV_GRIDNAV_CTRL_SCROLL_FIRST = 0x2, + +} lv_gridnav_ctrl_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Add grid navigation feature to an object. It expects the children to be arranged + * into a grid-like layout. Although it's not required to have pixel perfect alignment. + * This feature makes possible to use keys to navigate among the children and focus them. + * The keys other than arrows and press/release related events + * are forwarded to the focused child. + * @param obj pointer to an object on which navigation should be applied. + * @param ctrl control flags from `lv_gridnav_ctrl_t`. + */ +void lv_gridnav_add(lv_obj_t * obj, lv_gridnav_ctrl_t ctrl); + +/** + * Remove the grid navigation support from an object + * @param obj pointer to an object + */ +void lv_gridnav_remove(lv_obj_t * obj); + +/** + * Manually focus an object on gridnav container + * @param cont pointer to a gridnav container + * @param to_focus pointer to an object to focus + * @param anim_en LV_ANIM_ON/OFF + */ +void lv_gridnav_set_focused(lv_obj_t * cont, lv_obj_t * to_focus, lv_anim_enable_t anim_en); + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GRIDNAV*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GRIDFOCUS_H*/ diff --git a/include/liblvgl/extra/others/ime/lv_ime_pinyin.h b/include/liblvgl/extra/others/ime/lv_ime_pinyin.h new file mode 100644 index 0000000..2d70d29 --- /dev/null +++ b/include/liblvgl/extra/others/ime/lv_ime_pinyin.h @@ -0,0 +1,145 @@ +/** + * @file lv_ime_pinyin.h + * + */ +#ifndef LV_IME_PINYIN_H +#define LV_IME_PINYIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_IME_PINYIN != 0 + +/********************* + * DEFINES + *********************/ +#define LV_IME_PINYIN_K9_MAX_INPUT 7 + +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_IME_PINYIN_MODE_K26, + LV_IME_PINYIN_MODE_K9, +} lv_ime_pinyin_mode_t; + +/*Data of pinyin_dict*/ +typedef struct { + const char * const py; + const char * const py_mb; +} lv_pinyin_dict_t; + +/*Data of 9-key input(k9) mode*/ +typedef struct { + char py_str[7]; +} ime_pinyin_k9_py_str_t; + +/*Data of lv_ime_pinyin*/ +typedef struct { + lv_obj_t obj; + lv_obj_t * kb; + lv_obj_t * cand_panel; + lv_pinyin_dict_t * dict; + lv_ll_t k9_legal_py_ll; + char * cand_str; /* Candidate string */ + char input_char[16]; /* Input box character */ +#if LV_IME_PINYIN_USE_K9_MODE + char k9_input_str[LV_IME_PINYIN_K9_MAX_INPUT]; /* 9-key input(k9) mode input string */ + uint16_t k9_py_ll_pos; /* Current pinyin map pages(k9) */ + uint16_t k9_legal_py_count; /* Count of legal Pinyin numbers(k9) */ + uint16_t k9_input_str_len; /* 9-key input(k9) mode input string max len */ +#endif + uint16_t ta_count; /* The number of characters entered in the text box this time */ + uint16_t cand_num; /* Number of candidates */ + uint16_t py_page; /* Current pinyin map pages(k26) */ + uint16_t py_num[26]; /* Number and length of Pinyin */ + uint16_t py_pos[26]; /* Pinyin position */ + uint8_t mode : 1; /* Set mode, 1: 26-key input(k26), 0: 9-key input(k9). Default: 1. */ +} lv_ime_pinyin_t; + +/*********************** + * GLOBAL VARIABLES + ***********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +lv_obj_t * lv_ime_pinyin_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the keyboard of Pinyin input method. + * @param obj pointer to a Pinyin input method object + * @param dict pointer to a Pinyin input method keyboard + */ +void lv_ime_pinyin_set_keyboard(lv_obj_t * obj, lv_obj_t * kb); + +/** + * Set the dictionary of Pinyin input method. + * @param obj pointer to a Pinyin input method object + * @param dict pointer to a Pinyin input method dictionary + */ +void lv_ime_pinyin_set_dict(lv_obj_t * obj, lv_pinyin_dict_t * dict); + +/** + * Set mode, 26-key input(k26) or 9-key input(k9). + * @param obj pointer to a Pinyin input method object + * @param mode the mode from 'lv_ime_pinyin_mode_t' + */ +void lv_ime_pinyin_set_mode(lv_obj_t * obj, lv_ime_pinyin_mode_t mode); + + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the dictionary of Pinyin input method. + * @param obj pointer to a Pinyin IME object + * @return pointer to the Pinyin IME keyboard + */ +lv_obj_t * lv_ime_pinyin_get_kb(lv_obj_t * obj); + + +/** + * Set the dictionary of Pinyin input method. + * @param obj pointer to a Pinyin input method object + * @return pointer to the Pinyin input method candidate panel + */ +lv_obj_t * lv_ime_pinyin_get_cand_panel(lv_obj_t * obj); + + +/** + * Set the dictionary of Pinyin input method. + * @param obj pointer to a Pinyin input method object + * @return pointer to the Pinyin input method dictionary + */ +lv_pinyin_dict_t * lv_ime_pinyin_get_dict(lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_IME_PINYIN*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_USE_IME_PINYIN*/ + + diff --git a/include/liblvgl/extra/others/imgfont/lv_imgfont.h b/include/liblvgl/extra/others/imgfont/lv_imgfont.h new file mode 100644 index 0000000..4fb6f78 --- /dev/null +++ b/include/liblvgl/extra/others/imgfont/lv_imgfont.h @@ -0,0 +1,60 @@ +/** + * @file lv_imgfont.h + * + */ + +#ifndef LV_IMGFONT_H +#define LV_IMGFONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_IMGFONT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* gets the image path name of this character */ +typedef bool (*lv_get_imgfont_path_cb_t)(const lv_font_t * font, void * img_src, + uint16_t len, uint32_t unicode, uint32_t unicode_next); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Creates a image font with info parameter specified. + * @param height font size + * @param path_cb a function to get the image path name of character. + * @return pointer to the new imgfont or NULL if create error. + */ +lv_font_t * lv_imgfont_create(uint16_t height, lv_get_imgfont_path_cb_t path_cb); + +/** + * Destroy a image font that has been created. + * @param font pointer to image font handle. + */ +void lv_imgfont_destroy(lv_font_t * font); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_IMGFONT*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /* LV_IMGFONT_H */ diff --git a/include/liblvgl/extra/others/lv_others.h b/include/liblvgl/extra/others/lv_others.h new file mode 100644 index 0000000..106d85e --- /dev/null +++ b/include/liblvgl/extra/others/lv_others.h @@ -0,0 +1,44 @@ +/** + * @file lv_others.h + * + */ + +#ifndef LV_OTHERS_H +#define LV_OTHERS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "snapshot/lv_snapshot.h" +#include "monkey/lv_monkey.h" +#include "gridnav/lv_gridnav.h" +#include "fragment/lv_fragment.h" +#include "imgfont/lv_imgfont.h" +#include "msg/lv_msg.h" +#include "ime/lv_ime_pinyin.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_OTHERS_H*/ diff --git a/include/liblvgl/extra/others/monkey/lv_monkey.h b/include/liblvgl/extra/others/monkey/lv_monkey.h new file mode 100644 index 0000000..589daf1 --- /dev/null +++ b/include/liblvgl/extra/others/monkey/lv_monkey.h @@ -0,0 +1,118 @@ +/** + * @file lv_monkey.h + * + */ +#ifndef LV_MONKEY_H +#define LV_MONKEY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_MONKEY != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_monkey; +typedef struct _lv_monkey lv_monkey_t; + +typedef struct { + /**< Input device type*/ + lv_indev_type_t type; + + /**< Monkey execution period*/ + struct { + uint32_t min; + uint32_t max; + } period_range; + + /**< The range of input value*/ + struct { + int32_t min; + int32_t max; + } input_range; +} lv_monkey_config_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a monkey config with default values + * @param config pointer to 'lv_monkey_config_t' variable to initialize + */ +void lv_monkey_config_init(lv_monkey_config_t * config); + +/** + * Create monkey for test + * @param config pointer to 'lv_monkey_config_t' variable + * @return pointer to the created monkey + */ +lv_monkey_t * lv_monkey_create(const lv_monkey_config_t * config); + +/** + * Get monkey input device + * @param monkey pointer to a monkey + * @return pointer to the input device + */ +lv_indev_t * lv_monkey_get_indev(lv_monkey_t * monkey); + +/** + * Enable monkey + * @param monkey pointer to a monkey + * @param en set to true to enable + */ +void lv_monkey_set_enable(lv_monkey_t * monkey, bool en); + +/** + * Get whether monkey is enabled + * @param monkey pointer to a monkey + * @return return true if monkey enabled + */ +bool lv_monkey_get_enable(lv_monkey_t * monkey); + +#if LV_USE_USER_DATA + +/** + * Set the user_data field of the monkey + * @param monkey pointer to a monkey + * @param user_data pointer to the new user_data. + */ +void lv_monkey_set_user_data(lv_monkey_t * monkey, void * user_data); + +/** + * Get the user_data field of the monkey + * @param monkey pointer to a monkey + * @return the pointer to the user_data of the monkey + */ +void * lv_monkey_get_user_data(lv_monkey_t * monkey); + +#endif/*LV_USE_USER_DATA*/ + +/** + * Delete monkey + * @param monkey pointer to monkey + */ +void lv_monkey_del(lv_monkey_t * monkey); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_MONKEY*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_MONKEY_H*/ diff --git a/include/liblvgl/extra/others/msg/lv_msg.h b/include/liblvgl/extra/others/msg/lv_msg.h new file mode 100644 index 0000000..64dc0d4 --- /dev/null +++ b/include/liblvgl/extra/others/msg/lv_msg.h @@ -0,0 +1,124 @@ +/** + * @file lv_msg.h + * + */ + +#ifndef LV_MSG_H +#define LV_MSG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#if LV_USE_MSG + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint32_t id; /*Identifier of the message*/ + void * user_data; /*Set the the user_data set in `lv_msg_subscribe`*/ + void * _priv_data; /*Used internally*/ + const void * payload; /*Pointer to the data of the message*/ +} lv_msg_t; + +typedef void (*lv_msg_subscribe_cb_t)(void * s, lv_msg_t * msg); + +typedef void (*lv_msg_request_cb_t)(void * r, uint32_t msg_id); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Called internally to initialize the message module + */ +void lv_msg_init(void); + +/** + * Subscribe to an `msg_id` + * @param msg_id the message ID to listen to + * @param cb callback to call if a message with `msg_id` was sent + * @param user_data arbitrary data which will be available in `cb` too + * @return pointer to a "subscribe object". It can be used the unsubscribe. + */ +void * lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data); + +/** + * Subscribe an `lv_obj` to a message. + * `LV_EVENT_MSG_RECEIVED` will be triggered if a message with matching ID was sent + * @param msg_id the message ID to listen to + * @param obj pointer to an `lv_obj` + * @param user_data arbitrary data which will be available in `cb` too + * @return pointer to a "subscribe object". It can be used the unsubscribe. + */ +void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data); + +/** + * Cancel a previous subscription + * @param s pointer to a "subscibe object". + * Return value of `lv_msg_subsribe` or `lv_msg_subsribe_obj` + */ +void lv_msg_unsubscribe(void * s); + +/** + * Send a message with a given ID and payload + * @param msg_id ID of the message to send + * @param data pointer to the data to send + */ +void lv_msg_send(uint32_t msg_id, const void * payload); + +/** + * Get the ID of a message object. Typically used in the subscriber callback. + * @param m pointer to a message object + * @return the ID of the message + */ +uint32_t lv_msg_get_id(lv_msg_t * m); + +/** + * Get the payload of a message object. Typically used in the subscriber callback. + * @param m pointer to a message object + * @return the payload of the message + */ +const void * lv_msg_get_payload(lv_msg_t * m); + +/** + * Get the user data of a message object. Typically used in the subscriber callback. + * @param m pointer to a message object + * @return the user data of the message + */ +void * lv_msg_get_user_data(lv_msg_t * m); + +/** + * Get the message object from an event object. Can be used in `LV_EVENT_MSG_RECEIVED` events. + * @param e pointer to an event object + * @return the message object or NULL if called with unrelated event code. + */ +lv_msg_t * lv_event_get_msg(lv_event_t * e); + +/********************** + * GLOBAL VARIABLES + **********************/ + +extern lv_event_code_t LV_EVENT_MSG_RECEIVED; + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_MSG*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_MSG_H*/ diff --git a/include/liblvgl/extra/others/snapshot/lv_snapshot.h b/include/liblvgl/extra/others/snapshot/lv_snapshot.h new file mode 100644 index 0000000..33d9741 --- /dev/null +++ b/include/liblvgl/extra/others/snapshot/lv_snapshot.h @@ -0,0 +1,84 @@ +/** + * @file lv_snapshot.h + * + */ + +#ifndef LV_SNAPSHOT_H +#define LV_SNAPSHOT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include + +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +#if LV_USE_SNAPSHOT +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** Take snapshot for object with its children. + * + * @param obj The object to generate snapshot. + * @param cf color format for generated image. + * + * @return a pointer to an image descriptor, or NULL if failed. + */ +lv_img_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_img_cf_t cf); + +/** Free the snapshot image returned by @ref lv_snapshot_take + * + * It will firstly free the data image takes, then the image descriptor. + * + * @param dsc The image descriptor generated by lv_snapshot_take. + * + */ +void lv_snapshot_free(lv_img_dsc_t * dsc); + +/** Get the buffer needed for object snapshot image. + * + * @param obj The object to generate snapshot. + * @param cf color format for generated image. + * + * @return the buffer size needed in bytes + */ +uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_img_cf_t cf); + +/** Take snapshot for object with its children, save image info to provided buffer. + * + * @param obj The object to generate snapshot. + * @param cf color format for generated image. + * @param dsc image descriptor to store the image result. + * @param buff the buffer to store image data. + * @param buff_size provided buffer size in bytes. + * + * @return LV_RES_OK on success, LV_RES_INV on error. + */ +lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc, void * buf, uint32_t buff_size); + + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_SNAPSHOT*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/extra/themes/basic/lv_theme_basic.h b/include/liblvgl/extra/themes/basic/lv_theme_basic.h new file mode 100644 index 0000000..06d6828 --- /dev/null +++ b/include/liblvgl/extra/themes/basic/lv_theme_basic.h @@ -0,0 +1,55 @@ +/** + * @file lv_theme_basic.h + * + */ + +#ifndef LV_THEME_BASIC_H +#define LV_THEME_BASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_THEME_BASIC + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the theme + * @param disp pointer to display to attach the theme + * @return a pointer to reference this theme later + */ +lv_theme_t * lv_theme_basic_init(lv_disp_t * disp); + +/** +* Check if the theme is initialized +* @return true if default theme is initialized, false otherwise +*/ +bool lv_theme_basic_is_inited(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_THEME_BASIC_H*/ diff --git a/include/liblvgl/extra/themes/default/lv_theme_default.h b/include/liblvgl/extra/themes/default/lv_theme_default.h new file mode 100644 index 0000000..7fab5be --- /dev/null +++ b/include/liblvgl/extra/themes/default/lv_theme_default.h @@ -0,0 +1,64 @@ +/** + * @file lv_theme_default.h + * + */ + +#ifndef LV_THEME_DEFAULT_H +#define LV_THEME_DEFAULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_THEME_DEFAULT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the theme + * @param color_primary the primary color of the theme + * @param color_secondary the secondary color for the theme + * @param font pointer to a font to use. + * @return a pointer to reference this theme later + */ +lv_theme_t * lv_theme_default_init(lv_disp_t * disp, lv_color_t color_primary, lv_color_t color_secondary, bool dark, + const lv_font_t * font); + +/** + * Get default theme + * @return a pointer to default theme, or NULL if this is not initialized + */ +lv_theme_t * lv_theme_default_get(void); + +/** + * Check if default theme is initialized + * @return true if default theme is initialized, false otherwise + */ +bool lv_theme_default_is_inited(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_THEME_DEFAULT_H*/ diff --git a/include/liblvgl/extra/themes/lv_themes.h b/include/liblvgl/extra/themes/lv_themes.h new file mode 100644 index 0000000..372f626 --- /dev/null +++ b/include/liblvgl/extra/themes/lv_themes.h @@ -0,0 +1,40 @@ +/** + * @file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "default/lv_theme_default.h" +#include "mono/lv_theme_mono.h" +#include "basic/lv_theme_basic.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/include/liblvgl/extra/themes/mono/lv_theme_mono.h b/include/liblvgl/extra/themes/mono/lv_theme_mono.h new file mode 100644 index 0000000..3d907ff --- /dev/null +++ b/include/liblvgl/extra/themes/mono/lv_theme_mono.h @@ -0,0 +1,57 @@ +/** + * @file lv_theme_mono.h + * + */ + +#ifndef LV_USE_THEME_MONO_H +#define LV_USE_THEME_MONO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_THEME_MONO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the theme + * @param color_primary the primary color of the theme + * @param color_secondary the secondary color for the theme + * @param font pointer to a font to use. + * @return a pointer to reference this theme later + */ +lv_theme_t * lv_theme_mono_init(lv_disp_t * disp, bool dark_bg, const lv_font_t * font); + +/** +* Check if the theme is initialized +* @return true if default theme is initialized, false otherwise +*/ +bool lv_theme_mono_is_inited(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_USE_THEME_MONO_H*/ diff --git a/include/liblvgl/extra/widgets/animimg/lv_animimg.h b/include/liblvgl/extra/widgets/animimg/lv_animimg.h new file mode 100644 index 0000000..9ffe621 --- /dev/null +++ b/include/liblvgl/extra/widgets/animimg/lv_animimg.h @@ -0,0 +1,103 @@ +/** + * @file lv_animimg.h + * + */ + +#ifndef LV_ANIM_IMG_H +#define LV_ANIM_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_ANIMIMG != 0 + +/*Testing of dependencies*/ +#if LV_USE_IMG == 0 +#error "lv_animimg: lv_img is required. Enable it in lv_conf.h (LV_USE_IMG 1)" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +extern const lv_obj_class_t lv_animimg_class; + +/*Data of image*/ +typedef struct { + lv_img_t img; + lv_anim_t anim; + /*picture sequence */ + lv_img_dsc_t ** dsc; + int8_t pic_count; +} lv_animimg_t; + + +/*Image parts*/ +enum { + LV_ANIM_IMG_PART_MAIN, +}; +typedef uint8_t lv_animimg_part_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an animation image objects + * @param parent pointer to an object, it will be the parent of the new button + * @return pointer to the created animation image object + */ +lv_obj_t * lv_animimg_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the image animation images source. + * @param img pointer to an animation image object + * @param dsc pointer to a series images + * @param num images' number + */ +void lv_animimg_set_src(lv_obj_t * img, lv_img_dsc_t * dsc[], uint8_t num); + +/** + * Startup the image animation. + * @param obj pointer to an animation image object + */ +void lv_animimg_start(lv_obj_t * obj); + +/** + * Set the image animation duration time. unit:ms + * @param img pointer to an animation image object + */ +void lv_animimg_set_duration(lv_obj_t * img, uint32_t duration); + +/** + * Set the image animation reapeatly play times. + * @param img pointer to an animation image object + * @param count the number of times to repeat the animation + */ +void lv_animimg_set_repeat_count(lv_obj_t * img, uint16_t count); + +/*===================== + * Getter functions + *====================*/ + +#endif /*LV_USE_ANIMIMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_IMG_H*/ diff --git a/include/liblvgl/extra/widgets/calendar/lv_calendar.h b/include/liblvgl/extra/widgets/calendar/lv_calendar.h new file mode 100644 index 0000000..ad157bf --- /dev/null +++ b/include/liblvgl/extra/widgets/calendar/lv_calendar.h @@ -0,0 +1,164 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/widgets/lv_btnmatrix.h" + +#if LV_USE_CALENDAR + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Represents a date on the calendar object (platform-agnostic). + */ +typedef struct { + uint16_t year; + int8_t month; /** 1..12*/ + int8_t day; /** 1..31*/ +} lv_calendar_date_t; + +/*Data of calendar*/ +typedef struct { + lv_obj_t obj; + lv_obj_t * btnm; + /*New data for this type*/ + lv_calendar_date_t today; /*Date of today*/ + lv_calendar_date_t showed_date; /*Currently visible month (day is ignored)*/ + lv_calendar_date_t * + highlighted_dates; /*Apply different style on these days (pointer to an array defined by the user)*/ + uint16_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + const char * map[8 * 7]; + char nums [7 * 6][4]; +} lv_calendar_t; + +extern const lv_obj_class_t lv_calendar_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_calendar_create(lv_obj_t * parent); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the today's date + * @param obj pointer to a calendar object + * @param year today's year + * @param month today's month [1..12] + * @param day today's day [1..31] + */ +void lv_calendar_set_today_date(lv_obj_t * obj, uint32_t year, uint32_t month, uint32_t day); + +/** + * Set the currently showed + * @param obj pointer to a calendar object + * @param year today's year + * @param month today's month [1..12] + */ +void lv_calendar_set_showed_date(lv_obj_t * obj, uint32_t year, uint32_t month); + +/** + * Set the highlighted dates + * @param obj pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * obj, lv_calendar_date_t highlighted[], uint16_t date_num); + +/** + * Set the name of the days + * @param obj pointer to a calendar object + * @param day_names pointer to an array with the names. + * E.g. `const char * days[7] = {"Sun", "Mon", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_day_names(lv_obj_t * obj, const char ** day_names); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the button matrix object of the calendar. + * It shows the dates and day names. + * @param obj pointer to a calendar object + * @return pointer to a the button matrix + */ +lv_obj_t * lv_calendar_get_btnmatrix(const lv_obj_t * obj); + +/** + * Get the today's date + * @param calendar pointer to a calendar object + * @return return pointer to an `lv_calendar_date_t` variable containing the date of today. + */ +const lv_calendar_date_t * lv_calendar_get_today_date(const lv_obj_t * calendar); + +/** + * Get the currently showed + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the date is being shown. + */ +const lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the highlighted dates + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` array containing the dates. + */ +lv_calendar_date_t * lv_calendar_get_highlighted_dates(const lv_obj_t * calendar); + +/** + * Get the number of the highlighted dates + * @param calendar pointer to a calendar object + * @return number of highlighted days + */ +uint16_t lv_calendar_get_highlighted_dates_num(const lv_obj_t * calendar); + +/** + * Get the currently pressed day + * @param calendar pointer to a calendar object + * @param date store the pressed date here + * @return LV_RES_OK: there is a valid pressed date; LV_RES_INV: there is no pressed data + */ +lv_res_t lv_calendar_get_pressed_date(const lv_obj_t * calendar, lv_calendar_date_t * date); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CALENDAR*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/include/liblvgl/extra/widgets/calendar/lv_calendar_header_arrow.h b/include/liblvgl/extra/widgets/calendar/lv_calendar_header_arrow.h new file mode 100644 index 0000000..30639e8 --- /dev/null +++ b/include/liblvgl/extra/widgets/calendar/lv_calendar_header_arrow.h @@ -0,0 +1,49 @@ +/** + * @file lv_calendar_header_arrow.h + * + */ + +#ifndef LV_CALENDAR_HEADER_ARROW_H +#define LV_CALENDAR_HEADER_ARROW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#if LV_USE_CALENDAR_HEADER_ARROW + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +extern const lv_obj_class_t lv_calendar_header_arrow_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar header with drop-drowns to select the year and month + * @param parent pointer to a calendar object. + * @return the created header + */ +lv_obj_t * lv_calendar_header_arrow_create(lv_obj_t * parent); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CALENDAR_HEADER_ARROW*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CALENDAR_HEADER_ARROW_H*/ diff --git a/include/liblvgl/extra/widgets/calendar/lv_calendar_header_dropdown.h b/include/liblvgl/extra/widgets/calendar/lv_calendar_header_dropdown.h new file mode 100644 index 0000000..ba926a0 --- /dev/null +++ b/include/liblvgl/extra/widgets/calendar/lv_calendar_header_dropdown.h @@ -0,0 +1,49 @@ +/** + * @file lv_calendar_header_dropdown.h + * + */ + +#ifndef LV_CALENDAR_HEADER_DROPDOWN_H +#define LV_CALENDAR_HEADER_DROPDOWN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#if LV_USE_CALENDAR_HEADER_DROPDOWN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +extern const lv_obj_class_t lv_calendar_header_dropdown_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar header with drop-drowns to select the year and month + * @param parent pointer to a calendar object. + * @return the created header + */ +lv_obj_t * lv_calendar_header_dropdown_create(lv_obj_t * parent); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CALENDAR_HEADER_ARROW*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CALENDAR_HEADER_DROPDOWN_H*/ diff --git a/include/liblvgl/extra/widgets/chart/lv_chart.h b/include/liblvgl/extra/widgets/chart/lv_chart.h new file mode 100644 index 0000000..14d70b9 --- /dev/null +++ b/include/liblvgl/extra/widgets/chart/lv_chart.h @@ -0,0 +1,460 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_CHART != 0 + +/********************* + * DEFINES + *********************/ + +/**Default value of points. Can be used to not draw a point*/ +#if LV_USE_LARGE_COORD +#define LV_CHART_POINT_NONE (INT32_MAX) +#else +#define LV_CHART_POINT_NONE (INT16_MAX) +#endif +LV_EXPORT_CONST_INT(LV_CHART_POINT_NONE); + +/********************** + * TYPEDEFS + **********************/ + +/** + * Chart types + */ +enum { + LV_CHART_TYPE_NONE, /**< Don't draw the series*/ + LV_CHART_TYPE_LINE, /**< Connect the points with lines*/ + LV_CHART_TYPE_BAR, /**< Draw columns*/ + LV_CHART_TYPE_SCATTER, /**< Draw points and lines in 2D (x,y coordinates)*/ +}; +typedef uint8_t lv_chart_type_t; + +/** + * Chart update mode for `lv_chart_set_next` + */ +enum { + LV_CHART_UPDATE_MODE_SHIFT, /**< Shift old data to the left and add the new one the right*/ + LV_CHART_UPDATE_MODE_CIRCULAR, /**< Add the new data in a circular way*/ +}; +typedef uint8_t lv_chart_update_mode_t; + +/** + * Enumeration of the axis' + */ +enum { + LV_CHART_AXIS_PRIMARY_Y = 0x00, + LV_CHART_AXIS_SECONDARY_Y = 0x01, + LV_CHART_AXIS_PRIMARY_X = 0x02, + LV_CHART_AXIS_SECONDARY_X = 0x04, + _LV_CHART_AXIS_LAST +}; +typedef uint8_t lv_chart_axis_t; + +/** + * Descriptor a chart series + */ +typedef struct { + lv_coord_t * x_points; + lv_coord_t * y_points; + lv_color_t color; + uint16_t start_point; + uint8_t hidden : 1; + uint8_t x_ext_buf_assigned : 1; + uint8_t y_ext_buf_assigned : 1; + uint8_t x_axis_sec : 1; + uint8_t y_axis_sec : 1; +} lv_chart_series_t; + +typedef struct { + lv_point_t pos; + lv_coord_t point_id; + lv_color_t color; + lv_chart_series_t * ser; + lv_dir_t dir; + uint8_t pos_set: 1; /*1: pos is set; 0: point_id is set*/ +} lv_chart_cursor_t; + +typedef struct { + lv_coord_t major_len; + lv_coord_t minor_len; + lv_coord_t draw_size; + uint32_t minor_cnt : 15; + uint32_t major_cnt : 15; + uint32_t label_en : 1; +} lv_chart_tick_dsc_t; + + +typedef struct { + lv_obj_t obj; + lv_ll_t series_ll; /**< Linked list for the series (stores lv_chart_series_t)*/ + lv_ll_t cursor_ll; /**< Linked list for the cursors (stores lv_chart_cursor_t)*/ + lv_chart_tick_dsc_t tick[4]; + lv_coord_t ymin[2]; + lv_coord_t ymax[2]; + lv_coord_t xmin[2]; + lv_coord_t xmax[2]; + lv_coord_t pressed_point_id; + uint16_t hdiv_cnt; /**< Number of horizontal division lines*/ + uint16_t vdiv_cnt; /**< Number of vertical division lines*/ + uint16_t point_cnt; /**< Point number in a data line*/ + uint16_t zoom_x; + uint16_t zoom_y; + lv_chart_type_t type : 3; /**< Line or column chart*/ + lv_chart_update_mode_t update_mode : 1; +} lv_chart_t; + +extern const lv_obj_class_t lv_chart_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_chart_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_CHART_DRAW_PART_DIV_LINE_INIT, /**< Used before/after drawn the div lines*/ + LV_CHART_DRAW_PART_DIV_LINE_HOR, /**< Used for each horizontal division lines*/ + LV_CHART_DRAW_PART_DIV_LINE_VER, /**< Used for each vertical division lines*/ + LV_CHART_DRAW_PART_LINE_AND_POINT, /**< Used on line and scatter charts for lines and points*/ + LV_CHART_DRAW_PART_BAR, /**< Used on bar charts for the rectangles*/ + LV_CHART_DRAW_PART_CURSOR, /**< Used on cursor lines and points*/ + LV_CHART_DRAW_PART_TICK_LABEL, /**< Used on tick lines and labels*/ +} lv_chart_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart object + * @param parent pointer to an object, it will be the parent of the new chart + * @return pointer to the created chart + */ +lv_obj_t * lv_chart_create(lv_obj_t * parent); + +/** + * Set a new type for a chart + * @param obj pointer to a chart object + * @param type new type of the chart (from 'lv_chart_type_t' enum) + */ +void lv_chart_set_type(lv_obj_t * obj, lv_chart_type_t type); +/** + * Set the number of points on a data line on a chart + * @param obj pointer to a chart object + * @param cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * obj, uint16_t cnt); + +/** + * Set the minimal and maximal y values on an axis + * @param obj pointer to a chart object + * @param axis `LV_CHART_AXIS_PRIMARY_Y` or `LV_CHART_AXIS_SECONDARY_Y` + * @param min minimum value of the y axis + * @param max maximum value of the y axis + */ +void lv_chart_set_range(lv_obj_t * obj, lv_chart_axis_t axis, lv_coord_t min, lv_coord_t max); + +/** + * Set update mode of the chart object. Affects + * @param obj pointer to a chart object + * @param mode the update mode + */ +void lv_chart_set_update_mode(lv_obj_t * obj, lv_chart_update_mode_t update_mode); + +/** + * Set the number of horizontal and vertical division lines + * @param obj pointer to a chart object + * @param hdiv number of horizontal division lines + * @param vdiv number of vertical division lines + */ +void lv_chart_set_div_line_count(lv_obj_t * obj, uint8_t hdiv, uint8_t vdiv); + +/** + * Zoom into the chart in X direction + * @param obj pointer to a chart object + * @param zoom_x zoom in x direction. LV_ZOOM_NONE or 256 for no zoom, 512 double zoom + */ +void lv_chart_set_zoom_x(lv_obj_t * obj, uint16_t zoom_x); + +/** + * Zoom into the chart in Y direction + * @param obj pointer to a chart object + * @param zoom_y zoom in y direction. LV_ZOOM_NONE or 256 for no zoom, 512 double zoom + */ +void lv_chart_set_zoom_y(lv_obj_t * obj, uint16_t zoom_y); + +/** + * Get X zoom of a chart + * @param obj pointer to a chart object + * @return the X zoom value + */ +uint16_t lv_chart_get_zoom_x(const lv_obj_t * obj); + +/** + * Get Y zoom of a chart + * @param obj pointer to a chart object + * @return the Y zoom value + */ +uint16_t lv_chart_get_zoom_y(const lv_obj_t * obj); + +/** + * Set the number of tick lines on an axis + * @param obj pointer to a chart object + * @param axis an axis which ticks count should be set + * @param major_len length of major ticks + * @param minor_len length of minor ticks + * @param major_cnt number of major ticks on the axis + * @param minor_cnt number of minor ticks between two major ticks + * @param label_en true: enable label drawing on major ticks + * @param draw_size extra size required to draw the tick and labels + * (start with 20 px and increase if the ticks/labels are clipped) + */ +void lv_chart_set_axis_tick(lv_obj_t * obj, lv_chart_axis_t axis, lv_coord_t major_len, lv_coord_t minor_len, + lv_coord_t major_cnt, lv_coord_t minor_cnt, bool label_en, lv_coord_t draw_size); + +/** + * Get the type of a chart + * @param obj pointer to chart object + * @return type of the chart (from 'lv_chart_t' enum) + */ +lv_chart_type_t lv_chart_get_type(const lv_obj_t * obj); + +/** + * Get the data point number per data line on chart + * @param chart pointer to chart object + * @return point number on each data line + */ +uint16_t lv_chart_get_point_count(const lv_obj_t * obj); + +/** + * Get the current index of the x-axis start point in the data array + * @param chart pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @return the index of the current x start point in the data array + */ +uint16_t lv_chart_get_x_start_point(const lv_obj_t * obj, lv_chart_series_t * ser); + +/** + * Get the position of a point to the chart. + * @param chart pointer to a chart object + * @param ser pointer to series + * @param id the index. + * @param p_out store the result position here + */ +void lv_chart_get_point_pos_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint16_t id, lv_point_t * p_out); + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * obj); + +/*====================== + * Series + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param obj pointer to a chart object + * @param color color of the data series + * @param axis the y axis to which the series should be attached (::LV_CHART_AXIS_PRIMARY_Y or ::LV_CHART_AXIS_SECONDARY_Y) + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * obj, lv_color_t color, lv_chart_axis_t axis); + +/** + * Deallocate and remove a data series from a chart + * @param chart pointer to a chart object + * @param series pointer to a data series on 'chart' + */ +void lv_chart_remove_series(lv_obj_t * obj, lv_chart_series_t * series); + +/** + * Hide/Unhide a single series of a chart. + * @param obj pointer to a chart object. + * @param series pointer to a series object + * @param hide true: hide the series + */ +void lv_chart_hide_series(lv_obj_t * chart, lv_chart_series_t * series, bool hide); + +/** + * Change the color of a series + * @param obj pointer to a chart object. + * @param series pointer to a series object + * @param color the new color of the series + */ +void lv_chart_set_series_color(lv_obj_t * chart, lv_chart_series_t * series, lv_color_t color); + +/** + * Set the index of the x-axis start point in the data array. + * This point will be considers the first (left) point and the other points will be drawn after it. + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @param id the index of the x point in the data array + */ +void lv_chart_set_x_start_point(lv_obj_t * obj, lv_chart_series_t * ser, uint16_t id); + +/** + * Get the next series. + * @param chart pointer to a chart + * @param ser the previous series or NULL to get the first + * @return the next series or NULL if there is no more. + */ +lv_chart_series_t * lv_chart_get_series_next(const lv_obj_t * chart, const lv_chart_series_t * ser); + + + +/*===================== + * Cursor + *====================*/ + +/** + * Add a cursor with a given color + * @param obj pointer to chart object + * @param color color of the cursor + * @param dir direction of the cursor. `LV_DIR_RIGHT/LEFT/TOP/DOWN/HOR/VER/ALL`. OR-ed values are possible + * @return pointer to the created cursor + */ +lv_chart_cursor_t * lv_chart_add_cursor(lv_obj_t * obj, lv_color_t color, lv_dir_t dir); + +/** + * Set the coordinate of the cursor with respect to the paddings + * @param obj pointer to a chart object + * @param cursor pointer to the cursor + * @param pos the new coordinate of cursor relative to the chart + */ +void lv_chart_set_cursor_pos(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_point_t * pos); + +/** + * Stick the cursor to a point + * @param obj pointer to a chart object + * @param cursor pointer to the cursor + * @param ser pointer to a series + * @param point_id the point's index or `LV_CHART_POINT_NONE` to not assign to any points. + */ +void lv_chart_set_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor, lv_chart_series_t * ser, + uint16_t point_id); + +/** + * Get the coordinate of the cursor with respect to the paddings + * @param obj pointer to a chart object + * @param cursor pointer to cursor + * @return coordinate of the cursor as lv_point_t + */ +lv_point_t lv_chart_get_cursor_point(lv_obj_t * chart, lv_chart_cursor_t * cursor); + +/*===================== + * Set/Get value(s) + *====================*/ + +/** + * Initialize all data points of a series with a value + * @param obj pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param value the new value for all points. `LV_CHART_POINT_NONE` can be used to hide the points. + */ +void lv_chart_set_all_value(lv_obj_t * obj, lv_chart_series_t * ser, lv_coord_t value); + +/** + * Set the next point's Y value according to the update mode policy. + * @param obj pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param value the new value of the next data + */ +void lv_chart_set_next_value(lv_obj_t * obj, lv_chart_series_t * ser, lv_coord_t value); + +/** + * Set the next point's X and Y value according to the update mode policy. + * @param obj pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param x_value the new X value of the next data + * @param y_value the new Y value of the next data + */ +void lv_chart_set_next_value2(lv_obj_t * obj, lv_chart_series_t * ser, lv_coord_t x_value, lv_coord_t y_value); + +/** + * Set an individual point's y value of a chart's series directly based on its index + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @param id the index of the x point in the array + * @param value value to assign to array point + */ +void lv_chart_set_value_by_id(lv_obj_t * obj, lv_chart_series_t * ser, uint16_t id, lv_coord_t value); + +/** + * Set an individual point's x and y value of a chart's series directly based on its index + * Can be used only with `LV_CHART_TYPE_SCATTER`. + * @param obj pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param id the index of the x point in the array + * @param x_value the new X value of the next data + * @param y_value the new Y value of the next data + */ +void lv_chart_set_value_by_id2(lv_obj_t * obj, lv_chart_series_t * ser, uint16_t id, lv_coord_t x_value, + lv_coord_t y_value); + +/** + * Set an external array for the y data points to use for the chart + * NOTE: It is the users responsibility to make sure the `point_cnt` matches the external array size. + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @param array external array of points for chart + */ +void lv_chart_set_ext_y_array(lv_obj_t * obj, lv_chart_series_t * ser, lv_coord_t array[]); + +/** + * Set an external array for the x data points to use for the chart + * NOTE: It is the users responsibility to make sure the `point_cnt` matches the external array size. + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @param array external array of points for chart + */ +void lv_chart_set_ext_x_array(lv_obj_t * obj, lv_chart_series_t * ser, lv_coord_t array[]); + +/** + * Get the array of y values of a series + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @return the array of values with 'point_count' elements + */ +lv_coord_t * lv_chart_get_y_array(const lv_obj_t * obj, lv_chart_series_t * ser); + +/** + * Get the array of x values of a series + * @param obj pointer to a chart object + * @param ser pointer to a data series on 'chart' + * @return the array of values with 'point_count' elements + */ +lv_coord_t * lv_chart_get_x_array(const lv_obj_t * obj, lv_chart_series_t * ser); + +/** + * Get the index of the currently pressed point. It's the same for every series. + * @param obj pointer to a chart object + * @return the index of the point [0 .. point count] or LV_CHART_POINT_ID_NONE if no point is being pressed + */ +uint32_t lv_chart_get_pressed_point(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CHART*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CHART_H*/ diff --git a/include/liblvgl/extra/widgets/colorwheel/lv_colorwheel.h b/include/liblvgl/extra/widgets/colorwheel/lv_colorwheel.h new file mode 100644 index 0000000..38266d0 --- /dev/null +++ b/include/liblvgl/extra/widgets/colorwheel/lv_colorwheel.h @@ -0,0 +1,142 @@ +/** + * @file lv_colorwheel.h + * + */ + +#ifndef LV_COLORWHEEL_H +#define LV_COLORWHEEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_COLORWHEEL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_COLORWHEEL_MODE_HUE, + LV_COLORWHEEL_MODE_SATURATION, + LV_COLORWHEEL_MODE_VALUE +}; +typedef uint8_t lv_colorwheel_mode_t; + + +/*Data of color picker*/ +typedef struct { + lv_obj_t obj; + lv_color_hsv_t hsv; + struct { + lv_point_t pos; + uint8_t recolor : 1; + } knob; + uint32_t last_click_time; + uint32_t last_change_time; + lv_point_t last_press_point; + lv_colorwheel_mode_t mode : 2; + uint8_t mode_fixed : 1; +} lv_colorwheel_t; + +extern const lv_obj_class_t lv_colorwheel_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a color picker object with disc shape + * @param parent pointer to an object, it will be the parent of the new color picker + * @param knob_recolor true: set the knob's color to the current color + * @return pointer to the created color picker + */ +lv_obj_t * lv_colorwheel_create(lv_obj_t * parent, bool knob_recolor); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the current hsv of a color wheel. + * @param colorwheel pointer to color wheel object + * @param color current selected hsv + * @return true if changed, otherwise false + */ +bool lv_colorwheel_set_hsv(lv_obj_t * obj, lv_color_hsv_t hsv); + +/** + * Set the current color of a color wheel. + * @param colorwheel pointer to color wheel object + * @param color current selected color + * @return true if changed, otherwise false + */ +bool lv_colorwheel_set_rgb(lv_obj_t * obj, lv_color_t color); + +/** + * Set the current color mode. + * @param colorwheel pointer to color wheel object + * @param mode color mode (hue/sat/val) + */ +void lv_colorwheel_set_mode(lv_obj_t * obj, lv_colorwheel_mode_t mode); + +/** + * Set if the color mode is changed on long press on center + * @param colorwheel pointer to color wheel object + * @param fixed color mode cannot be changed on long press + */ +void lv_colorwheel_set_mode_fixed(lv_obj_t * obj, bool fixed); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current selected hsv of a color wheel. + * @param colorwheel pointer to color wheel object + * @return current selected hsv + */ +lv_color_hsv_t lv_colorwheel_get_hsv(lv_obj_t * obj); + +/** + * Get the current selected color of a color wheel. + * @param colorwheel pointer to color wheel object + * @return color current selected color + */ +lv_color_t lv_colorwheel_get_rgb(lv_obj_t * obj); + +/** + * Get the current color mode. + * @param colorwheel pointer to color wheel object + * @return color mode (hue/sat/val) + */ +lv_colorwheel_mode_t lv_colorwheel_get_color_mode(lv_obj_t * obj); + +/** + * Get if the color mode is changed on long press on center + * @param colorwheel pointer to color wheel object + * @return mode cannot be changed on long press + */ +bool lv_colorwheel_get_color_mode_fixed(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_COLORWHEEL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_COLORWHEEL_H*/ + diff --git a/include/liblvgl/extra/widgets/imgbtn/lv_imgbtn.h b/include/liblvgl/extra/widgets/imgbtn/lv_imgbtn.h new file mode 100644 index 0000000..38bcc03 --- /dev/null +++ b/include/liblvgl/extra/widgets/imgbtn/lv_imgbtn.h @@ -0,0 +1,131 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_IMGBTN != 0 + +/********************* + * DEFINES + *********************/ +typedef enum { + LV_IMGBTN_STATE_RELEASED, + LV_IMGBTN_STATE_PRESSED, + LV_IMGBTN_STATE_DISABLED, + LV_IMGBTN_STATE_CHECKED_RELEASED, + LV_IMGBTN_STATE_CHECKED_PRESSED, + LV_IMGBTN_STATE_CHECKED_DISABLED, + _LV_IMGBTN_STATE_NUM, +} lv_imgbtn_state_t; + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_obj_t obj; + const void * img_src_mid[_LV_IMGBTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_left[_LV_IMGBTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_right[_LV_IMGBTN_STATE_NUM]; /*Store right side images to each state*/ + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_t; + +extern const lv_obj_class_t lv_imgbtn_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image button object + * @param parent pointer to an object, it will be the parent of the new image button + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * parent); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set images for a state of the image button + * @param imgbtn pointer to an image button object + * @param state for which state set the new image + * @param src_left pointer to an image source for the left side of the button (a C array or path to + * a file) + * @param src_mid pointer to an image source for the middle of the button (ideally 1px wide) (a C + * array or path to a file) + * @param src_right pointer to an image source for the right side of the button (a C array or path + * to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_imgbtn_state_t state, const void * src_left, const void * src_mid, + const void * src_right); + + +/** + * Use this function instead of `lv_obj_add/clear_state` to set a state manually + * @param imgbtn pointer to an image button object + * @param state the new state + */ +void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_imgbtn_state_t state); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the left image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_left(lv_obj_t * imgbtn, lv_imgbtn_state_t state); + +/** + * Get the middle image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the middle image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_middle(lv_obj_t * imgbtn, lv_imgbtn_state_t state); + +/** + * Get the right image in a given state + * @param imgbtn pointer to an image button object + * @param state the state where to get the image (from `lv_btn_state_t`) ` + * @return pointer to the left image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src_right(lv_obj_t * imgbtn, lv_imgbtn_state_t state); + + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_IMGBTN*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/include/liblvgl/extra/widgets/keyboard/lv_keyboard.h b/include/liblvgl/extra/widgets/keyboard/lv_keyboard.h new file mode 100644 index 0000000..64356a3 --- /dev/null +++ b/include/liblvgl/extra/widgets/keyboard/lv_keyboard.h @@ -0,0 +1,187 @@ +/** + * @file lv_keyboard.h + * + */ + +#ifndef LV_KEYBOARD_H +#define LV_KEYBOARD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/widgets/lv_btnmatrix.h" + +#if LV_USE_KEYBOARD + +/*Testing of dependencies*/ +#if LV_USE_BTNMATRIX == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (LV_USE_BTNMATRIX 1) " +#endif + +#if LV_USE_TEXTAREA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (LV_USE_TEXTAREA 1) " +#endif + +/********************* + * DEFINES + *********************/ +#define LV_KEYBOARD_CTRL_BTN_FLAGS (LV_BTNMATRIX_CTRL_NO_REPEAT | LV_BTNMATRIX_CTRL_CLICK_TRIG | LV_BTNMATRIX_CTRL_CHECKED) + +/********************** + * TYPEDEFS + **********************/ + +/** Current keyboard mode.*/ +enum { + LV_KEYBOARD_MODE_TEXT_LOWER, + LV_KEYBOARD_MODE_TEXT_UPPER, + LV_KEYBOARD_MODE_SPECIAL, + LV_KEYBOARD_MODE_NUMBER, + LV_KEYBOARD_MODE_USER_1, + LV_KEYBOARD_MODE_USER_2, + LV_KEYBOARD_MODE_USER_3, + LV_KEYBOARD_MODE_USER_4, +}; +typedef uint8_t lv_keyboard_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnmatrix_t btnm; + lv_obj_t * ta; /*Pointer to the assigned text area*/ + lv_keyboard_mode_t mode; /*Key map type*/ + uint8_t popovers : 1; /*Show button titles in popovers on press*/ +} lv_keyboard_t; + +extern const lv_obj_class_t lv_keyboard_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a Keyboard object + * @param parent pointer to an object, it will be the parent of the new keyboard + * @return pointer to the created keyboard + */ +lv_obj_t * lv_keyboard_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @param ta pointer to a Text Area object to write there + */ +void lv_keyboard_set_textarea(lv_obj_t * kb, lv_obj_t * ta); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @param mode the mode from 'lv_keyboard_mode_t' + */ +void lv_keyboard_set_mode(lv_obj_t * kb, lv_keyboard_mode_t mode); + +/** + * Show the button title in a popover when pressed. + * @param kb pointer to a Keyboard object + * @param en whether "popovers" mode is enabled + */ +void lv_keyboard_set_popovers(lv_obj_t * kb, bool en); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param mode keyboard map to alter 'lv_keyboard_mode_t' + * @param map pointer to a string array to describe the map. + * See 'lv_btnmatrix_set_map()' for more info. + */ +void lv_keyboard_set_map(lv_obj_t * kb, lv_keyboard_mode_t mode, const char * map[], + const lv_btnmatrix_ctrl_t ctrl_map[]); + +/*===================== + * Getter functions + *====================*/ + +/** + * Assign a Text Area to the Keyboard. The pressed characters will be put there. + * @param kb pointer to a Keyboard object + * @return pointer to the assigned Text Area object + */ +lv_obj_t * lv_keyboard_get_textarea(const lv_obj_t * kb); + +/** + * Set a new a mode (text or number map) + * @param kb pointer to a Keyboard object + * @return the current mode from 'lv_keyboard_mode_t' + */ +lv_keyboard_mode_t lv_keyboard_get_mode(const lv_obj_t * kb); + +/** + * Tell whether "popovers" mode is enabled or not. + * @param kb pointer to a Keyboard object + * @return true: "popovers" mode is enabled; false: disabled + */ +bool lv_btnmatrix_get_popovers(const lv_obj_t * obj); + +/** + * Get the current map of a keyboard + * @param kb pointer to a keyboard object + * @return the current map + */ +static inline const char ** lv_keyboard_get_map_array(const lv_obj_t * kb) +{ + return lv_btnmatrix_get_map(kb); +} + +/** + * Get the index of the lastly "activated" button by the user (pressed, released, focused etc) + * Useful in the `event_cb` to get the text of the button, check if hidden etc. + * @param obj pointer to button matrix object + * @return index of the last released button (LV_BTNMATRIX_BTN_NONE: if unset) + */ +static inline uint16_t lv_keyboard_get_selected_btn(const lv_obj_t * obj) +{ + return lv_btnmatrix_get_selected_btn(obj); +} + +/** + * Get the button's text + * @param obj pointer to button matrix object + * @param btn_id the index a button not counting new line characters. + * @return text of btn_index` button + */ +static inline const char * lv_keyboard_get_btn_text(const lv_obj_t * obj, uint16_t btn_id) +{ + return lv_btnmatrix_get_btn_text(obj, btn_id); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Default keyboard event to add characters to the Text area and change the map. + * If a custom `event_cb` is added to the keyboard this function can be called from it to handle the + * button clicks + * @param kb pointer to a keyboard + * @param event the triggering event + */ +void lv_keyboard_def_event_cb(lv_event_t * e); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_KEYBOARD*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_KEYBOARD_H*/ diff --git a/include/liblvgl/extra/widgets/led/lv_led.h b/include/liblvgl/extra/widgets/led/lv_led.h new file mode 100644 index 0000000..f188b8e --- /dev/null +++ b/include/liblvgl/extra/widgets/led/lv_led.h @@ -0,0 +1,116 @@ +/** + * @file lv_led.h + * + */ + +#ifndef LV_LED_H +#define LV_LED_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_LED + + +/********************* + * DEFINES + *********************/ +/** Brightness when the LED if OFF */ +#ifndef LV_LED_BRIGHT_MIN +# define LV_LED_BRIGHT_MIN 80 +#endif + +/** Brightness when the LED if ON */ +#ifndef LV_LED_BRIGHT_MAX +# define LV_LED_BRIGHT_MAX 255 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct { + lv_obj_t obj; + lv_color_t color; + uint8_t bright; /**< Current brightness of the LED (0..255)*/ +} lv_led_t; + +extern const lv_obj_class_t lv_led_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_led_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_LED_DRAW_PART_RECTANGLE, /**< The main rectangle*/ +} lv_led_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led object + * @param parent pointer to an object, it will be the parent of the new led + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * parent); + +/** + * Set the color of the LED + * @param led pointer to a LED object + * @param color the color of the LED + */ +void lv_led_set_color(lv_obj_t * led, lv_color_t color); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright LV_LED_BRIGHT_MIN (max. dark) ... LV_LED_BRIGHT_MAX (max. light) + */ +void lv_led_set_brightness(lv_obj_t * led, uint8_t bright); + +/** + * Light on a LED + * @param led pointer to a LED object + */ +void lv_led_on(lv_obj_t * led); + +/** + * Light off a LED + * @param led pointer to a LED object + */ +void lv_led_off(lv_obj_t * led); + +/** + * Toggle the state of a LED + * @param led pointer to a LED object + */ +void lv_led_toggle(lv_obj_t * led); + +/** + * Get the brightness of a LEd object + * @param led pointer to LED object + * @return bright 0 (max. dark) ... 255 (max. light) + */ +uint8_t lv_led_get_brightness(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_LED*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + + +#endif /*LV_LED_H*/ diff --git a/include/liblvgl/extra/widgets/list/lv_list.h b/include/liblvgl/extra/widgets/list/lv_list.h new file mode 100644 index 0000000..e9bb626 --- /dev/null +++ b/include/liblvgl/extra/widgets/list/lv_list.h @@ -0,0 +1,54 @@ +/** + * @file lv_win.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/extra/layouts/flex/lv_flex.h" + +#if LV_USE_LIST + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +extern const lv_obj_class_t lv_list_class; +extern const lv_obj_class_t lv_list_text_class; +extern const lv_obj_class_t lv_list_btn_class; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_list_create(lv_obj_t * parent); + +lv_obj_t * lv_list_add_text(lv_obj_t * list, const char * txt); + +lv_obj_t * lv_list_add_btn(lv_obj_t * list, const void * icon, const char * txt); + +const char * lv_list_get_btn_text(lv_obj_t * list, lv_obj_t * btn); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_LIST*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LIST_H*/ diff --git a/include/liblvgl/extra/widgets/lv_widgets.h b/include/liblvgl/extra/widgets/lv_widgets.h new file mode 100644 index 0000000..1141810 --- /dev/null +++ b/include/liblvgl/extra/widgets/lv_widgets.h @@ -0,0 +1,56 @@ +/** + * @file lv_widgets.h + * + */ + +#ifndef LV_WIDGETS_H +#define LV_WIDGETS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "animimg/lv_animimg.h" +#include "calendar/lv_calendar.h" +#include "calendar/lv_calendar_header_arrow.h" +#include "calendar/lv_calendar_header_dropdown.h" +#include "chart/lv_chart.h" +#include "keyboard/lv_keyboard.h" +#include "list/lv_list.h" +#include "menu/lv_menu.h" +#include "msgbox/lv_msgbox.h" +#include "meter/lv_meter.h" +#include "spinbox/lv_spinbox.h" +#include "spinner/lv_spinner.h" +#include "tabview/lv_tabview.h" +#include "tileview/lv_tileview.h" +#include "win/lv_win.h" +#include "colorwheel/lv_colorwheel.h" +#include "led/lv_led.h" +#include "imgbtn/lv_imgbtn.h" +#include "span/lv_span.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_WIDGETS_H*/ diff --git a/include/liblvgl/extra/widgets/menu/lv_menu.h b/include/liblvgl/extra/widgets/menu/lv_menu.h new file mode 100644 index 0000000..4209979 --- /dev/null +++ b/include/liblvgl/extra/widgets/menu/lv_menu.h @@ -0,0 +1,233 @@ +/** + * @file lv_menu.h + * + */ + +#ifndef LV_MENU_H +#define LV_MENU_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_MENU + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_MENU_HEADER_TOP_FIXED, /* Header is positioned at the top */ + LV_MENU_HEADER_TOP_UNFIXED, /* Header is positioned at the top and can be scrolled out of view*/ + LV_MENU_HEADER_BOTTOM_FIXED /* Header is positioned at the bottom */ +}; +typedef uint8_t lv_menu_mode_header_t; + +enum { + LV_MENU_ROOT_BACK_BTN_DISABLED, + LV_MENU_ROOT_BACK_BTN_ENABLED +}; +typedef uint8_t lv_menu_mode_root_back_btn_t; + +typedef struct lv_menu_load_page_event_data_t { + lv_obj_t * menu; + lv_obj_t * page; +} lv_menu_load_page_event_data_t; + +typedef struct { + lv_obj_t * page; +} lv_menu_history_t; + +typedef struct { + lv_obj_t obj; + lv_obj_t * storage; /* a pointer to obj that is the parent of all pages not displayed */ + lv_obj_t * main; + lv_obj_t * main_page; + lv_obj_t * main_header; + lv_obj_t * + main_header_back_btn; /* a pointer to obj that on click triggers back btn event handler, can be same as 'main_header' */ + lv_obj_t * main_header_title; + lv_obj_t * sidebar; + lv_obj_t * sidebar_page; + lv_obj_t * sidebar_header; + lv_obj_t * + sidebar_header_back_btn; /* a pointer to obj that on click triggers back btn event handler, can be same as 'sidebar_header' */ + lv_obj_t * sidebar_header_title; + lv_obj_t * selected_tab; + lv_ll_t history_ll; + uint8_t cur_depth; + uint8_t prev_depth; + uint8_t sidebar_generated : 1; + lv_menu_mode_header_t mode_header : 2; + lv_menu_mode_root_back_btn_t mode_root_back_btn : 1; +} lv_menu_t; + +typedef struct { + lv_obj_t obj; + char * title; +} lv_menu_page_t; + +extern const lv_obj_class_t lv_menu_class; +extern const lv_obj_class_t lv_menu_page_class; +extern const lv_obj_class_t lv_menu_cont_class; +extern const lv_obj_class_t lv_menu_section_class; +extern const lv_obj_class_t lv_menu_separator_class; +extern const lv_obj_class_t lv_menu_sidebar_cont_class; +extern const lv_obj_class_t lv_menu_main_cont_class; +extern const lv_obj_class_t lv_menu_sidebar_header_cont_class; +extern const lv_obj_class_t lv_menu_main_header_cont_class; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a menu object + * @param parent pointer to an object, it will be the parent of the new menu + * @return pointer to the created menu + */ +lv_obj_t * lv_menu_create(lv_obj_t * parent); + +/** + * Create a menu page object + * @param parent pointer to menu object + * @param title pointer to text for title in header (NULL to not display title) + * @return pointer to the created menu page + */ +lv_obj_t * lv_menu_page_create(lv_obj_t * parent, char * title); + +/** + * Create a menu cont object + * @param parent pointer to an object, it will be the parent of the new menu cont object + * @return pointer to the created menu cont + */ +lv_obj_t * lv_menu_cont_create(lv_obj_t * parent); + +/** + * Create a menu section object + * @param parent pointer to an object, it will be the parent of the new menu section object + * @return pointer to the created menu section + */ +lv_obj_t * lv_menu_section_create(lv_obj_t * parent); + +/** + * Create a menu separator object + * @param parent pointer to an object, it will be the parent of the new menu separator object + * @return pointer to the created menu separator + */ +lv_obj_t * lv_menu_separator_create(lv_obj_t * parent); +/*===================== + * Setter functions + *====================*/ +/** + * Set menu page to display in main + * @param obj pointer to the menu + * @param page pointer to the menu page to set (NULL to clear main and clear menu history) + */ +void lv_menu_set_page(lv_obj_t * obj, lv_obj_t * page); + +/** + * Set menu page to display in sidebar + * @param obj pointer to the menu + * @param page pointer to the menu page to set (NULL to clear sidebar) + */ +void lv_menu_set_sidebar_page(lv_obj_t * obj, lv_obj_t * page); + +/** + * Set the how the header should behave and its position + * @param obj pointer to a menu + * @param mode_header + */ +void lv_menu_set_mode_header(lv_obj_t * obj, lv_menu_mode_header_t mode_header); + +/** + * Set whether back button should appear at root + * @param obj pointer to a menu + * @param mode_root_back_btn + */ +void lv_menu_set_mode_root_back_btn(lv_obj_t * obj, lv_menu_mode_root_back_btn_t mode_root_back_btn); + +/** + * Add menu to the menu item + * @param menu pointer to the menu + * @param obj pointer to the obj + * @param page pointer to the page to load when obj is clicked + */ +void lv_menu_set_load_page_event(lv_obj_t * menu, lv_obj_t * obj, lv_obj_t * page); + +/*===================== + * Getter functions + *====================*/ +/** +* Get a pointer to menu page that is currently displayed in main +* @param obj pointer to the menu +* @return pointer to current page +*/ +lv_obj_t * lv_menu_get_cur_main_page(lv_obj_t * obj); + +/** +* Get a pointer to menu page that is currently displayed in sidebar +* @param obj pointer to the menu +* @return pointer to current page +*/ +lv_obj_t * lv_menu_get_cur_sidebar_page(lv_obj_t * obj); + +/** +* Get a pointer to main header obj +* @param obj pointer to the menu +* @return pointer to main header obj +*/ +lv_obj_t * lv_menu_get_main_header(lv_obj_t * obj); + +/** +* Get a pointer to main header back btn obj +* @param obj pointer to the menu +* @return pointer to main header back btn obj +*/ +lv_obj_t * lv_menu_get_main_header_back_btn(lv_obj_t * obj); + +/** +* Get a pointer to sidebar header obj +* @param obj pointer to the menu +* @return pointer to sidebar header obj +*/ +lv_obj_t * lv_menu_get_sidebar_header(lv_obj_t * obj); + +/** +* Get a pointer to sidebar header obj +* @param obj pointer to the menu +* @return pointer to sidebar header back btn obj +*/ +lv_obj_t * lv_menu_get_sidebar_header_back_btn(lv_obj_t * obj); + +/** + * Check if an obj is a root back btn + * @param menu pointer to the menu + * @return true if it is a root back btn + */ +bool lv_menu_back_btn_is_root(lv_obj_t * menu, lv_obj_t * obj); + +/** + * Clear menu history + * @param obj pointer to the menu + */ +void lv_menu_clear_history(lv_obj_t * obj); +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_MENU*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_MENU_H*/ diff --git a/include/liblvgl/extra/widgets/meter/lv_meter.h b/include/liblvgl/extra/widgets/meter/lv_meter.h new file mode 100644 index 0000000..d64ad0d --- /dev/null +++ b/include/liblvgl/extra/widgets/meter/lv_meter.h @@ -0,0 +1,267 @@ +/** + * @file lv_meter.h + * + */ + +#ifndef LV_METER_H +#define LV_METER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_METER != 0 + +/*Testing of dependencies*/ +#if LV_DRAW_COMPLEX == 0 +#error "lv_meter: Complex drawing is required. Enable it in lv_conf.h (LV_DRAW_COMPLEX 1)" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_color_t tick_color; + uint16_t tick_cnt; + uint16_t tick_length; + uint16_t tick_width; + + lv_color_t tick_major_color; + uint16_t tick_major_nth; + uint16_t tick_major_length; + uint16_t tick_major_width; + + int16_t label_gap; + int16_t label_color; + + int32_t min; + int32_t max; + int16_t r_mod; + uint16_t angle_range; + int16_t rotation; +} lv_meter_scale_t; + +enum { + LV_METER_INDICATOR_TYPE_NEEDLE_IMG, + LV_METER_INDICATOR_TYPE_NEEDLE_LINE, + LV_METER_INDICATOR_TYPE_SCALE_LINES, + LV_METER_INDICATOR_TYPE_ARC, +}; +typedef uint8_t lv_meter_indicator_type_t; + +typedef struct { + lv_meter_scale_t * scale; + lv_meter_indicator_type_t type; + lv_opa_t opa; + int32_t start_value; + int32_t end_value; + union { + struct { + const void * src; + lv_point_t pivot; + } needle_img; + struct { + uint16_t width; + int16_t r_mod; + lv_color_t color; + } needle_line; + struct { + uint16_t width; + const void * src; + lv_color_t color; + int16_t r_mod; + } arc; + struct { + int16_t width_mod; + lv_color_t color_start; + lv_color_t color_end; + uint8_t local_grad : 1; + } scale_lines; + } type_data; +} lv_meter_indicator_t; + +/*Data of line meter*/ +typedef struct { + lv_obj_t obj; + lv_ll_t scale_ll; + lv_ll_t indicator_ll; +} lv_meter_t; + +extern const lv_obj_class_t lv_meter_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_meter_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_METER_DRAW_PART_ARC, /**< The arc indicator*/ + LV_METER_DRAW_PART_NEEDLE_LINE, /**< The needle lines*/ + LV_METER_DRAW_PART_NEEDLE_IMG, /**< The needle images*/ + LV_METER_DRAW_PART_TICK, /**< The tick lines and labels*/ +} lv_meter_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a Meter object + * @param parent pointer to an object, it will be the parent of the new bar. + * @return pointer to the created meter + */ +lv_obj_t * lv_meter_create(lv_obj_t * parent); + +/*===================== + * Add scale + *====================*/ + +/** + * Add a new scale to the meter. + * @param obj pointer to a meter object + * @return the new scale + * @note Indicators can be attached to scales. + */ +lv_meter_scale_t * lv_meter_add_scale(lv_obj_t * obj); + +/** + * Set the properties of the ticks of a scale + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param cnt number of tick lines + * @param width width of tick lines + * @param len length of tick lines + * @param color color of tick lines + */ +void lv_meter_set_scale_ticks(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t cnt, uint16_t width, uint16_t len, + lv_color_t color); + +/** + * Make some "normal" ticks major ticks and set their attributes. + * Texts with the current value are also added to the major ticks. + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param nth make every Nth normal tick major tick. (start from the first on the left) + * @param width width of the major ticks + * @param len length of the major ticks + * @param color color of the major ticks + * @param label_gap gap between the major ticks and the labels + */ +void lv_meter_set_scale_major_ticks(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t nth, uint16_t width, + uint16_t len, lv_color_t color, int16_t label_gap); + +/** + * Set the value and angular range of a scale. + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param min the minimum value + * @param max the maximal value + * @param angle_range the angular range of the scale + * @param rotation the angular offset from the 3 o'clock position (clock-wise) + */ +void lv_meter_set_scale_range(lv_obj_t * obj, lv_meter_scale_t * scale, int32_t min, int32_t max, uint32_t angle_range, + uint32_t rotation); + +/*===================== + * Add indicator + *====================*/ + +/** + * Add a needle line indicator the scale + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param width width of the line + * @param color color of the line + * @param r_mod the radius modifier (added to the scale's radius) to get the lines length + * @return the new indicator + */ +lv_meter_indicator_t * lv_meter_add_needle_line(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t width, + lv_color_t color, int16_t r_mod); + +/** + * Add a needle image indicator the scale + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param src the image source of the indicator. path or pointer to ::lv_img_dsc_t + * @param pivot_x the X pivot point of the needle + * @param pivot_y the Y pivot point of the needle + * @return the new indicator + * @note the needle image should point to the right, like -O-----> + */ +lv_meter_indicator_t * lv_meter_add_needle_img(lv_obj_t * obj, lv_meter_scale_t * scale, const void * src, + lv_coord_t pivot_x, lv_coord_t pivot_y); + +/** + * Add an arc indicator the scale + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param width width of the arc + * @param color color of the arc + * @param r_mod the radius modifier (added to the scale's radius) to get the outer radius of the arc + * @return the new indicator + */ +lv_meter_indicator_t * lv_meter_add_arc(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t width, lv_color_t color, + int16_t r_mod); + + +/** + * Add a scale line indicator the scale. It will modify the ticks. + * @param obj pointer to a meter object + * @param scale pointer to scale (added to `meter`) + * @param color_start the start color + * @param color_end the end color + * @param local tell how to map start and end color. true: the indicator's start and end_value; false: the scale's min max value + * @param width_mod add this the affected tick's width + * @return the new indicator + */ +lv_meter_indicator_t * lv_meter_add_scale_lines(lv_obj_t * obj, lv_meter_scale_t * scale, lv_color_t color_start, + lv_color_t color_end, bool local, int16_t width_mod); + +/*===================== + * Set indicator value + *====================*/ + +/** + * Set the value of the indicator. It will set start and and value to the same value + * @param obj pointer to a meter object + * @param indic pointer to an indicator + * @param value the new value + */ +void lv_meter_set_indicator_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value); + +/** + * Set the start value of the indicator. + * @param obj pointer to a meter object + * @param indic pointer to an indicator + * @param value the new value + */ +void lv_meter_set_indicator_start_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value); + +/** + * Set the start value of the indicator. + * @param obj pointer to a meter object + * @param indic pointer to an indicator + * @param value the new value + */ +void lv_meter_set_indicator_end_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_METER*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_METER_H*/ diff --git a/include/liblvgl/extra/widgets/msgbox/lv_msgbox.h b/include/liblvgl/extra/widgets/msgbox/lv_msgbox.h new file mode 100644 index 0000000..6b8ccd6 --- /dev/null +++ b/include/liblvgl/extra/widgets/msgbox/lv_msgbox.h @@ -0,0 +1,99 @@ +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MSGBOX_H +#define LV_MSGBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_MSGBOX + +/*Testing of dependencies*/ +#if LV_USE_BTNMATRIX == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (LV_USE_BTNMATRIX 1) " +#endif + +#if LV_USE_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1) " +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + lv_obj_t * title; + lv_obj_t * close_btn; + lv_obj_t * content; + lv_obj_t * text; + lv_obj_t * btns; +} lv_msgbox_t; + +extern const lv_obj_class_t lv_msgbox_class; +extern const lv_obj_class_t lv_msgbox_content_class; +extern const lv_obj_class_t lv_msgbox_backdrop_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box object + * @param parent pointer to parent or NULL to create a full screen modal message box + * @param title the title of the message box + * @param txt the text of the message box + * @param btn_txts the buttons as an array of texts terminated by an "" element. E.g. {"btn1", "btn2", ""} + * @param add_close_btn true: add a close button + * @return pointer to the message box object + */ +lv_obj_t * lv_msgbox_create(lv_obj_t * parent, const char * title, const char * txt, const char * btn_txts[], + bool add_close_btn); + +lv_obj_t * lv_msgbox_get_title(lv_obj_t * obj); + +lv_obj_t * lv_msgbox_get_close_btn(lv_obj_t * obj); + +lv_obj_t * lv_msgbox_get_text(lv_obj_t * obj); + +lv_obj_t * lv_msgbox_get_content(lv_obj_t * obj); + +lv_obj_t * lv_msgbox_get_btns(lv_obj_t * obj); + +/** + * Get the index of the selected button + * @param mbox message box object + * @return index of the button (LV_BTNMATRIX_BTN_NONE: if unset) + */ +uint16_t lv_msgbox_get_active_btn(lv_obj_t * mbox); + +const char * lv_msgbox_get_active_btn_text(lv_obj_t * mbox); + +void lv_msgbox_close(lv_obj_t * mbox); + +void lv_msgbox_close_async(lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_MSGBOX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_MSGBOX_H*/ diff --git a/include/liblvgl/extra/widgets/span/lv_span.h b/include/liblvgl/extra/widgets/span/lv_span.h new file mode 100644 index 0000000..bbf65ac --- /dev/null +++ b/include/liblvgl/extra/widgets/span/lv_span.h @@ -0,0 +1,245 @@ +/** + * @file lv_span.h + * + */ + +#ifndef LV_SPAN_H +#define LV_SPAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_SPAN != 0 + +/********************* + * DEFINES + *********************/ +#ifndef LV_SPAN_SNIPPET_STACK_SIZE +#define LV_SPAN_SNIPPET_STACK_SIZE 64 +#endif + +/********************** + * TYPEDEFS + **********************/ +enum { + LV_SPAN_OVERFLOW_CLIP, + LV_SPAN_OVERFLOW_ELLIPSIS, +}; +typedef uint8_t lv_span_overflow_t; + +enum { + LV_SPAN_MODE_FIXED, /**< fixed the obj size*/ + LV_SPAN_MODE_EXPAND, /**< Expand the object size to the text size*/ + LV_SPAN_MODE_BREAK, /**< Keep width, break the too long lines and expand height*/ +}; +typedef uint8_t lv_span_mode_t; + +typedef struct { + char * txt; /* a pointer to display text */ + lv_obj_t * spangroup; /* a pointer to spangroup */ + lv_style_t style; /* display text style */ + uint8_t static_flag : 1;/* the text is static flag */ +} lv_span_t; + +/** Data of label*/ +typedef struct { + lv_obj_t obj; + int32_t lines; + lv_coord_t indent; /* first line indent */ + lv_coord_t cache_w; /* the cache automatically calculates the width */ + lv_coord_t cache_h; /* similar cache_w */ + lv_ll_t child_ll; + uint8_t mode : 2; /* details see lv_span_mode_t */ + uint8_t overflow : 1; /* details see lv_span_overflow_t */ + uint8_t refresh : 1; /* the spangroup need refresh cache_w and cache_h */ +} lv_spangroup_t; + +extern const lv_obj_class_t lv_spangroup_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spangroup object + * @param par pointer to an object, it will be the parent of the new spangroup + * @return pointer to the created spangroup + */ +lv_obj_t * lv_spangroup_create(lv_obj_t * par); + +/** + * Create a span string descriptor and add to spangroup. + * @param obj pointer to a spangroup object. + * @return pointer to the created span. + */ +lv_span_t * lv_spangroup_new_span(lv_obj_t * obj); + +/** + * Remove the span from the spangroup and free memory. + * @param obj pointer to a spangroup object. + * @param span pointer to a span. + */ +void lv_spangroup_del_span(lv_obj_t * obj, lv_span_t * span); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a span. Memory will be allocated to store the text by the span. + * @param span pointer to a span. + * @param text pointer to a text. + */ +void lv_span_set_text(lv_span_t * span, const char * text); + +/** + * Set a static text. It will not be saved by the span so the 'text' variable + * has to be 'alive' while the span exist. + * @param span pointer to a span. + * @param text pointer to a text. + */ +void lv_span_set_text_static(lv_span_t * span, const char * text); + +/** + * Set the align of the spangroup. + * @param obj pointer to a spangroup object. + * @param align see lv_text_align_t for details. + */ +void lv_spangroup_set_align(lv_obj_t * obj, lv_text_align_t align); + +/** + * Set the overflow of the spangroup. + * @param obj pointer to a spangroup object. + * @param overflow see lv_span_overflow_t for details. + */ +void lv_spangroup_set_overflow(lv_obj_t * obj, lv_span_overflow_t overflow); + +/** + * Set the indent of the spangroup. + * @param obj pointer to a spangroup object. + * @param indent The first line indentation + */ +void lv_spangroup_set_indent(lv_obj_t * obj, lv_coord_t indent); + +/** + * Set the mode of the spangroup. + * @param obj pointer to a spangroup object. + * @param mode see lv_span_mode_t for details. + */ +void lv_spangroup_set_mode(lv_obj_t * obj, lv_span_mode_t mode); + +/** + * Set lines of the spangroup. + * @param obj pointer to a spangroup object. + * @param lines max lines that can be displayed in LV_SPAN_MODE_BREAK mode. < 0 means no limit. + */ +void lv_spangroup_set_lines(lv_obj_t * obj, int32_t lines); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get a spangroup child by its index. + * + * @param obj The spangroup object + * @param id the index of the child. + * 0: the oldest (firstly created) child + * 1: the second oldest + * child count-1: the youngest + * -1: the youngest + * -2: the second youngest + * @return The child span at index `id`, or NULL if the ID does not exist + */ +lv_span_t * lv_spangroup_get_child(const lv_obj_t * obj, int32_t id); + +/** + * + * @param obj The spangroup object to get the child count of. + * @return The span count of the spangroup. + */ +uint32_t lv_spangroup_get_child_cnt(const lv_obj_t * obj); + +/** + * get the align of the spangroup. + * @param obj pointer to a spangroup object. + * @return the align value. + */ +lv_text_align_t lv_spangroup_get_align(lv_obj_t * obj); + +/** + * get the overflow of the spangroup. + * @param obj pointer to a spangroup object. + * @return the overflow value. + */ +lv_span_overflow_t lv_spangroup_get_overflow(lv_obj_t * obj); + +/** + * get the indent of the spangroup. + * @param obj pointer to a spangroup object. + * @return the indent value. + */ +lv_coord_t lv_spangroup_get_indent(lv_obj_t * obj); + +/** + * get the mode of the spangroup. + * @param obj pointer to a spangroup object. + */ +lv_span_mode_t lv_spangroup_get_mode(lv_obj_t * obj); + +/** + * get lines of the spangroup. + * @param obj pointer to a spangroup object. + * @return the lines value. + */ +int32_t lv_spangroup_get_lines(lv_obj_t * obj); + +/** + * get max line height of all span in the spangroup. + * @param obj pointer to a spangroup object. + */ +lv_coord_t lv_spangroup_get_max_line_h(lv_obj_t * obj); + +/** + * get the text content width when all span of spangroup on a line. + * @param obj pointer to a spangroup object. + * @param max_width if text content width >= max_width, return max_width + * to reduce computation, if max_width == 0, returns the text content width. + * @return text content width or max_width. + */ +uint32_t lv_spangroup_get_expand_width(lv_obj_t * obj, uint32_t max_width); + +/** + * get the text content height with width fixed. + * @param obj pointer to a spangroup object. + */ +lv_coord_t lv_spangroup_get_expand_height(lv_obj_t * obj, lv_coord_t width); + + +/*===================== + * Other functions + *====================*/ + +/** + * update the mode of the spangroup. + * @param obj pointer to a spangroup object. + */ +void lv_spangroup_refr_mode(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SPAN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPAN_H*/ diff --git a/include/liblvgl/extra/widgets/spinbox/lv_spinbox.h b/include/liblvgl/extra/widgets/spinbox/lv_spinbox.h new file mode 100644 index 0000000..830178f --- /dev/null +++ b/include/liblvgl/extra/widgets/spinbox/lv_spinbox.h @@ -0,0 +1,182 @@ +/** + * @file lv_spinbox.h + * + */ + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_SPINBOX + +/*Testing of dependencies*/ +#if LV_USE_TEXTAREA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (LV_USE_TEXTAREA 1) " +#endif + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 10 + +/********************** + * TYPEDEFS + **********************/ + +/*Data of spinbox*/ +typedef struct { + lv_textarea_t ta; /*Ext. of ancestor*/ + /*New data for this type*/ + int32_t value; + int32_t range_max; + int32_t range_min; + int32_t step; + uint16_t digit_count : 4; + uint16_t dec_point_pos : 4; /*if 0, there is no separator and the number is an integer*/ + uint16_t rollover : 1; // Set to true for rollover functionality + uint16_t digit_step_dir : 2; // the direction the digit will step on encoder button press when editing +} lv_spinbox_t; + +extern const lv_obj_class_t lv_spinbox_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a Spinbox object + * @param parent pointer to an object, it will be the parent of the new spinbox + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set spinbox value + * @param obj pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * obj, int32_t i); + +/** + * Set spinbox rollover function + * @param obj pointer to spinbox + * @param b true or false to enable or disable (default) + */ +void lv_spinbox_set_rollover(lv_obj_t * obj, bool b); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param obj pointer to spinbox + * @param digit_count number of digit excluding the decimal separator and the sign + * @param separator_position number of digit before the decimal point. If 0, decimal point is not + * shown + */ +void lv_spinbox_set_digit_format(lv_obj_t * obj, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param obj pointer to spinbox + * @param step steps on increment/decrement. Can be 1, 10, 100, 1000, etc the digit that will change. + */ +void lv_spinbox_set_step(lv_obj_t * obj, uint32_t step); + +/** + * Set spinbox value range + * @param obj pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * obj, int32_t range_min, int32_t range_max); + +/** + * Set cursor position to a specific digit for edition + * @param obj pointer to spinbox + * @param pos selected position in spinbox + */ +void lv_spinbox_set_cursor_pos(lv_obj_t * obj, uint8_t pos); + +/** + * Set direction of digit step when clicking an encoder button while in editing mode + * @param obj pointer to spinbox + * @param direction the direction (LV_DIR_RIGHT or LV_DIR_LEFT) + */ +void lv_spinbox_set_digit_step_direction(lv_obj_t * obj, lv_dir_t direction); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get spinbox rollover function status + * @param obj pointer to spinbox + */ +bool lv_spinbox_get_rollover(lv_obj_t * obj); + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param obj pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * obj); + +/** + * Get the spinbox step value (user has to convert to float according to its digit format) + * @param obj pointer to spinbox + * @return value integer step value of the spinbox + */ +int32_t lv_spinbox_get_step(lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param obj pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * obj); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param obj pointer to spinbox + */ +void lv_spinbox_step_prev(lv_obj_t * obj); + +/** + * Increment spinbox value by one step + * @param obj pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * obj); + +/** + * Decrement spinbox value by one step + * @param obj pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +/* It was ambiguous in MicroPython. See https://github.com/lvgl/lvgl/issues/3301 + * TODO remove in v9*/ +#define lv_spinbox_set_pos lv_spinbox_set_cursor_pos + +#endif /*LV_USE_SPINBOX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif +#endif /*LV_SPINBOX_H*/ diff --git a/include/liblvgl/extra/widgets/spinner/lv_spinner.h b/include/liblvgl/extra/widgets/spinner/lv_spinner.h new file mode 100644 index 0000000..794f736 --- /dev/null +++ b/include/liblvgl/extra/widgets/spinner/lv_spinner.h @@ -0,0 +1,50 @@ +/** + * @file lv_spinner.h + * + */ + +#ifndef LV_SPINNER_H +#define LV_SPINNER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_SPINNER + +/*Testing of dependencies*/ +#if LV_USE_ARC == 0 +#error "lv_spinner: lv_arc is required. Enable it in lv_conf.h (LV_USE_ARC 1) " +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +extern const lv_obj_class_t lv_spinner_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_spinner_create(lv_obj_t * parent, uint32_t time, uint32_t arc_length); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SPINNER*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_SPINNER_H*/ diff --git a/include/liblvgl/extra/widgets/tabview/lv_tabview.h b/include/liblvgl/extra/widgets/tabview/lv_tabview.h new file mode 100644 index 0000000..bcee5a1 --- /dev/null +++ b/include/liblvgl/extra/widgets/tabview/lv_tabview.h @@ -0,0 +1,65 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +#if LV_USE_TABVIEW + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + char ** map; + uint16_t tab_cnt; + uint16_t tab_cur; + lv_dir_t tab_pos; +} lv_tabview_t; + +extern const lv_obj_class_t lv_tabview_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, lv_coord_t tab_size); + +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tv, const char * name); + +void lv_tabview_rename_tab(lv_obj_t * obj, uint32_t tab_id, const char * new_name); + +lv_obj_t * lv_tabview_get_content(lv_obj_t * tv); + +lv_obj_t * lv_tabview_get_tab_btns(lv_obj_t * tv); + +void lv_tabview_set_act(lv_obj_t * obj, uint32_t id, lv_anim_enable_t anim_en); + +uint16_t lv_tabview_get_tab_act(lv_obj_t * tv); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_TABVIEW*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/include/liblvgl/extra/widgets/tileview/lv_tileview.h b/include/liblvgl/extra/widgets/tileview/lv_tileview.h new file mode 100644 index 0000000..34a1bf1 --- /dev/null +++ b/include/liblvgl/extra/widgets/tileview/lv_tileview.h @@ -0,0 +1,72 @@ +/** + * @file lv_tileview.h + * + */ + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_TILEVIEW + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_obj_t obj; + lv_obj_t * tile_act; +} lv_tileview_t; + +typedef struct { + lv_obj_t obj; + lv_dir_t dir; +} lv_tileview_tile_t; + +extern const lv_obj_class_t lv_tileview_class; +extern const lv_obj_class_t lv_tileview_tile_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a Tileview object + * @param parent pointer to an object, it will be the parent of the new tileview + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * parent); + +lv_obj_t * lv_tileview_add_tile(lv_obj_t * tv, uint8_t col_id, uint8_t row_id, lv_dir_t dir); + +void lv_obj_set_tile(lv_obj_t * tv, lv_obj_t * tile_obj, lv_anim_enable_t anim_en); +void lv_obj_set_tile_id(lv_obj_t * tv, uint32_t col_id, uint32_t row_id, lv_anim_enable_t anim_en); + +lv_obj_t * lv_tileview_get_tile_act(lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_TILEVIEW*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/include/liblvgl/extra/widgets/win/lv_win.h b/include/liblvgl/extra/widgets/win/lv_win.h new file mode 100644 index 0000000..2ea907d --- /dev/null +++ b/include/liblvgl/extra/widgets/win/lv_win.h @@ -0,0 +1,51 @@ +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_obj_t obj; +} lv_win_t; + +extern const lv_obj_class_t lv_win_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_obj_t * lv_win_create(lv_obj_t * parent, lv_coord_t header_height); + + +lv_obj_t * lv_win_add_title(lv_obj_t * win, const char * txt); +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * icon, lv_coord_t btn_w); + +lv_obj_t * lv_win_get_header(lv_obj_t * win); +lv_obj_t * lv_win_get_content(lv_obj_t * win); +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_WIN_H*/ diff --git a/include/liblvgl/font/lv_font.h b/include/liblvgl/font/lv_font.h new file mode 100644 index 0000000..3c0a689 --- /dev/null +++ b/include/liblvgl/font/lv_font.h @@ -0,0 +1,287 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include +#include +#include + +#include "lv_symbol_def.h" +#include "liblvgl/misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/* imgfont identifier */ +#define LV_IMGFONT_BPP 9 + +/********************** + * TYPEDEFS + **********************/ + +/*------------------ + * General types + *-----------------*/ + +struct _lv_font_t; +/** Describes the properties of a glyph.*/ +typedef struct { + const struct _lv_font_t * + resolved_font; /**< Pointer to a font where the glyph was actually found after handling fallbacks*/ + uint16_t adv_w; /**< The glyph needs this space. Draw the next glyph after this width.*/ + uint16_t box_w; /**< Width of the glyph's bounding box*/ + uint16_t box_h; /**< Height of the glyph's bounding box*/ + int16_t ofs_x; /**< x offset of the bounding box*/ + int16_t ofs_y; /**< y offset of the bounding box*/ + uint8_t bpp: 4; /**< Bit-per-pixel: 1, 2, 4, 8*/ + uint8_t is_placeholder: 1; /** Glyph is missing. But placeholder will still be displayed */ +} lv_font_glyph_dsc_t; + +/** The bitmaps might be upscaled by 3 to achieve subpixel rendering.*/ +enum { + LV_FONT_SUBPX_NONE, + LV_FONT_SUBPX_HOR, + LV_FONT_SUBPX_VER, + LV_FONT_SUBPX_BOTH, +}; + +typedef uint8_t lv_font_subpx_t; + +/** Describe the properties of a font*/ +typedef struct _lv_font_t { + /** Get a glyph's descriptor from a font*/ + bool (*get_glyph_dsc)(const struct _lv_font_t *, lv_font_glyph_dsc_t *, uint32_t letter, uint32_t letter_next); + + /** Get a glyph's bitmap from a font*/ + const uint8_t * (*get_glyph_bitmap)(const struct _lv_font_t *, uint32_t); + + /*Pointer to the font in a font pack (must have the same line height)*/ + lv_coord_t line_height; /**< The real line height where any text fits*/ + lv_coord_t base_line; /**< Base line measured from the top of the line_height*/ + uint8_t subpx : 2; /**< An element of `lv_font_subpx_t`*/ + + int8_t underline_position; /**< Distance between the top of the underline and base line (< 0 means below the base line)*/ + int8_t underline_thickness; /**< Thickness of the underline*/ + + const void * dsc; /**< Store implementation specific or run_time data or caching here*/ + const struct _lv_font_t * fallback; /**< Fallback font for missing glyph. Resolved recursively */ +#if LV_USE_USER_DATA + void * user_data; /**< Custom user data for font.*/ +#endif +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter a UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_glyph_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the descriptor of a glyph + * @param font_p pointer to font + * @param dsc_out store the result descriptor here + * @param letter a UNICODE letter code + * @param letter_next the next letter after `letter`. Used for kerning + * @return true: descriptor is successfully loaded into `dsc_out`. + * false: the letter was not found, no data is loaded to `dsc_out` + */ +bool lv_font_get_glyph_dsc(const lv_font_t * font_p, lv_font_glyph_dsc_t * dsc_out, uint32_t letter, + uint32_t letter_next); + +/** + * Get the width of a glyph with kerning + * @param font pointer to a font + * @param letter a UNICODE letter + * @param letter_next the next letter after `letter`. Used for kerning + * @return the width of the glyph + */ +uint16_t lv_font_get_glyph_width(const lv_font_t * font, uint32_t letter, uint32_t letter_next); + +/** + * Get the line height of a font. All characters fit into this height + * @param font_p pointer to a font + * @return the height of a font + */ +static inline lv_coord_t lv_font_get_line_height(const lv_font_t * font_p) +{ + return font_p->line_height; +} + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern const lv_font_t font_name; + +#if LV_FONT_MONTSERRAT_8 +LV_FONT_DECLARE(lv_font_montserrat_8) +#endif + +#if LV_FONT_MONTSERRAT_10 +LV_FONT_DECLARE(lv_font_montserrat_10) +#endif + +#if LV_FONT_MONTSERRAT_12 +LV_FONT_DECLARE(lv_font_montserrat_12) +#endif + +#if LV_FONT_MONTSERRAT_14 +LV_FONT_DECLARE(lv_font_montserrat_14) +#endif + +#if LV_FONT_MONTSERRAT_16 +LV_FONT_DECLARE(lv_font_montserrat_16) +#endif + +#if LV_FONT_MONTSERRAT_18 +LV_FONT_DECLARE(lv_font_montserrat_18) +#endif + +#if LV_FONT_MONTSERRAT_20 +LV_FONT_DECLARE(lv_font_montserrat_20) +#endif + +#if LV_FONT_MONTSERRAT_22 +LV_FONT_DECLARE(lv_font_montserrat_22) +#endif + +#if LV_FONT_MONTSERRAT_24 +LV_FONT_DECLARE(lv_font_montserrat_24) +#endif + +#if LV_FONT_MONTSERRAT_26 +LV_FONT_DECLARE(lv_font_montserrat_26) +#endif + +#if LV_FONT_MONTSERRAT_28 +LV_FONT_DECLARE(lv_font_montserrat_28) +#endif + +#if LV_FONT_MONTSERRAT_30 +LV_FONT_DECLARE(lv_font_montserrat_30) +#endif + +#if LV_FONT_MONTSERRAT_32 +LV_FONT_DECLARE(lv_font_montserrat_32) +#endif + +#if LV_FONT_MONTSERRAT_34 +LV_FONT_DECLARE(lv_font_montserrat_34) +#endif + +#if LV_FONT_MONTSERRAT_36 +LV_FONT_DECLARE(lv_font_montserrat_36) +#endif + +#if LV_FONT_MONTSERRAT_38 +LV_FONT_DECLARE(lv_font_montserrat_38) +#endif + +#if LV_FONT_MONTSERRAT_40 +LV_FONT_DECLARE(lv_font_montserrat_40) +#endif + +#if LV_FONT_MONTSERRAT_42 +LV_FONT_DECLARE(lv_font_montserrat_42) +#endif + +#if LV_FONT_MONTSERRAT_44 +LV_FONT_DECLARE(lv_font_montserrat_44) +#endif + +#if LV_FONT_MONTSERRAT_46 +LV_FONT_DECLARE(lv_font_montserrat_46) +#endif + +#if LV_FONT_MONTSERRAT_48 +LV_FONT_DECLARE(lv_font_montserrat_48) +#endif + +#if LV_FONT_MONTSERRAT_12_SUBPX +LV_FONT_DECLARE(lv_font_montserrat_12_subpx) +#endif + +#if LV_FONT_MONTSERRAT_28_COMPRESSED +LV_FONT_DECLARE(lv_font_montserrat_28_compressed) +#endif + +#if LV_FONT_DEJAVU_16_PERSIAN_HEBREW +LV_FONT_DECLARE(lv_font_dejavu_16_persian_hebrew) +#endif + +#if LV_FONT_SIMSUN_16_CJK +LV_FONT_DECLARE(lv_font_simsun_16_cjk) +#endif + +#if LV_FONT_UNSCII_8 +LV_FONT_DECLARE(lv_font_unscii_8) +#endif + +#if LV_FONT_UNSCII_16 +LV_FONT_DECLARE(lv_font_unscii_16) +#endif + +// TODO: reimplement some of the '_LATIN_SUP' fonts as custom fonts + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif +#if USE_PROS_FONT_DEJAVU_MONO_10 +LV_FONT_DECLARE(pros_font_dejavu_mono_10); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_10_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_18 +LV_FONT_DECLARE(pros_font_dejavu_mono_18); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_18_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_18_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30 +LV_FONT_DECLARE(pros_font_dejavu_mono_30); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_30_latin_sup); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40 +LV_FONT_DECLARE(pros_font_dejavu_mono_40); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_40_latin_sup); +#endif + +/** + * Just a wrapper around LV_FONT_DEFAULT because it might be more convenient to use a function in some cases + * @return pointer to LV_FONT_DEFAULT + */ +static inline const lv_font_t * lv_font_default(void) +{ + return LV_FONT_DEFAULT; +} + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*USE_FONT*/ diff --git a/include/liblvgl/font/lv_font_fmt_txt.h b/include/liblvgl/font/lv_font_fmt_txt.h new file mode 100644 index 0000000..86546a3 --- /dev/null +++ b/include/liblvgl/font/lv_font_fmt_txt.h @@ -0,0 +1,240 @@ +/** + * @file lv_font_fmt_txt.h + * + */ + +#ifndef LV_FONT_FMT_TXT_H +#define LV_FONT_FMT_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include +#include "lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** This describes a glyph.*/ +typedef struct { +#if LV_FONT_FMT_TXT_LARGE == 0 + uint32_t bitmap_index : 20; /**< Start index of the bitmap. A font can be max 1 MB.*/ + uint32_t adv_w : 12; /**< Draw the next glyph after this width. 8.4 format (real_value * 16 is stored).*/ + uint8_t box_w; /**< Width of the glyph's bounding box*/ + uint8_t box_h; /**< Height of the glyph's bounding box*/ + int8_t ofs_x; /**< x offset of the bounding box*/ + int8_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/ +#else + uint32_t bitmap_index; /**< Start index of the bitmap. A font can be max 4 GB.*/ + uint32_t adv_w; /**< Draw the next glyph after this width. 28.4 format (real_value * 16 is stored).*/ + uint16_t box_w; /**< Width of the glyph's bounding box*/ + uint16_t box_h; /**< Height of the glyph's bounding box*/ + int16_t ofs_x; /**< x offset of the bounding box*/ + int16_t ofs_y; /**< y offset of the bounding box. Measured from the top of the line*/ +#endif +} lv_font_fmt_txt_glyph_dsc_t; + +/** Format of font character map.*/ +enum { + LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL, + LV_FONT_FMT_TXT_CMAP_SPARSE_FULL, + LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY, + LV_FONT_FMT_TXT_CMAP_SPARSE_TINY, +}; + +typedef uint8_t lv_font_fmt_txt_cmap_type_t; + +/** + * Map codepoints to a `glyph_dsc`s + * Several formats are supported to optimize memory usage + * See https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md + */ +typedef struct { + /** First Unicode character for this range*/ + uint32_t range_start; + + /** Number of Unicode characters related to this range. + * Last Unicode character = range_start + range_length - 1*/ + uint16_t range_length; + + /** First glyph ID (array index of `glyph_dsc`) for this range*/ + uint16_t glyph_id_start; + + /* + According the specification there are 4 formats: + https://github.com/lvgl/lv_font_conv/blob/master/doc/font_spec.md + + For simplicity introduce "relative code point": + rcp = codepoint - range_start + + and a search function: + search a "value" in an "array" and returns the index of "value". + + Format 0 tiny + unicode_list == NULL && glyph_id_ofs_list == NULL + glyph_id = glyph_id_start + rcp + + Format 0 full + unicode_list == NULL && glyph_id_ofs_list != NULL + glyph_id = glyph_id_start + glyph_id_ofs_list[rcp] + + Sparse tiny + unicode_list != NULL && glyph_id_ofs_list == NULL + glyph_id = glyph_id_start + search(unicode_list, rcp) + + Sparse full + unicode_list != NULL && glyph_id_ofs_list != NULL + glyph_id = glyph_id_start + glyph_id_ofs_list[search(unicode_list, rcp)] + */ + + const uint16_t * unicode_list; + + /** if(type == LV_FONT_FMT_TXT_CMAP_FORMAT0_...) it's `uint8_t *` + * if(type == LV_FONT_FMT_TXT_CMAP_SPARSE_...) it's `uint16_t *` + */ + const void * glyph_id_ofs_list; + + /** Length of `unicode_list` and/or `glyph_id_ofs_list`*/ + uint16_t list_length; + + /** Type of this character map*/ + lv_font_fmt_txt_cmap_type_t type; +} lv_font_fmt_txt_cmap_t; + +/** A simple mapping of kern values from pairs*/ +typedef struct { + /*To get a kern value of two code points: + 1. Get the `glyph_id_left` and `glyph_id_right` from `lv_font_fmt_txt_cmap_t + 2. for(i = 0; i < pair_cnt * 2; i += 2) + if(gylph_ids[i] == glyph_id_left && + gylph_ids[i+1] == glyph_id_right) + return values[i / 2]; + */ + const void * glyph_ids; + const int8_t * values; + uint32_t pair_cnt : 30; + uint32_t glyph_ids_size : 2; /*0: `glyph_ids` is stored as `uint8_t`; 1: as `uint16_t`*/ +} lv_font_fmt_txt_kern_pair_t; + +/** More complex but more optimal class based kern value storage*/ +typedef struct { + /*To get a kern value of two code points: + 1. Get the `glyph_id_left` and `glyph_id_right` from `lv_font_fmt_txt_cmap_t + 2. Get the class of the left and right glyphs as `left_class` and `right_class` + left_class = left_class_mapping[glyph_id_left]; + right_class = right_class_mapping[glyph_id_right]; + 3. value = class_pair_values[(left_class-1)*right_class_cnt + (right_class-1)] + */ + + const int8_t * class_pair_values; /*left_class_cnt * right_class_cnt value*/ + const uint8_t * left_class_mapping; /*Map the glyph_ids to classes: index -> glyph_id -> class_id*/ + const uint8_t * right_class_mapping; /*Map the glyph_ids to classes: index -> glyph_id -> class_id*/ + uint8_t left_class_cnt; + uint8_t right_class_cnt; +} lv_font_fmt_txt_kern_classes_t; + +/** Bitmap formats*/ +typedef enum { + LV_FONT_FMT_TXT_PLAIN = 0, + LV_FONT_FMT_TXT_COMPRESSED = 1, + LV_FONT_FMT_TXT_COMPRESSED_NO_PREFILTER = 1, +} lv_font_fmt_txt_bitmap_format_t; + +typedef struct { + uint32_t last_letter; + uint32_t last_glyph_id; +} lv_font_fmt_txt_glyph_cache_t; + +/*Describe store additional data for fonts*/ +typedef struct { + /*The bitmaps of all glyphs*/ + const uint8_t * glyph_bitmap; + + /*Describe the glyphs*/ + const lv_font_fmt_txt_glyph_dsc_t * glyph_dsc; + + /*Map the glyphs to Unicode characters. + *Array of `lv_font_cmap_fmt_txt_t` variables*/ + const lv_font_fmt_txt_cmap_t * cmaps; + + /** + * Store kerning values. + * Can be `lv_font_fmt_txt_kern_pair_t * or `lv_font_kern_classes_fmt_txt_t *` + * depending on `kern_classes` + */ + const void * kern_dsc; + + /*Scale kern values in 12.4 format*/ + uint16_t kern_scale; + + /*Number of cmap tables*/ + uint16_t cmap_num : 9; + + /*Bit per pixel: 1, 2, 3, 4, 8*/ + uint16_t bpp : 4; + + /*Type of `kern_dsc`*/ + uint16_t kern_classes : 1; + + /* + * storage format of the bitmap + * from `lv_font_fmt_txt_bitmap_format_t` + */ + uint16_t bitmap_format : 2; + + /*Cache the last letter and is glyph id*/ + lv_font_fmt_txt_glyph_cache_t * cache; +} lv_font_fmt_txt_dsc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Used as `get_glyph_bitmap` callback in LittelvGL's native font format if the font is uncompressed. + * @param font pointer to font + * @param unicode_letter a unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_fmt_txt(const lv_font_t * font, uint32_t letter); + +/** + * Used as `get_glyph_dsc` callback in LittelvGL's native font format if the font is uncompressed. + * @param font_p pointer to font + * @param dsc_out store the result descriptor here + * @param letter a UNICODE letter code + * @return true: descriptor is successfully loaded into `dsc_out`. + * false: the letter was not found, no data is loaded to `dsc_out` + */ +bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, + uint32_t unicode_letter_next); + +/** + * Free the allocated memories. + */ +void _lv_font_clean_up_fmt_txt(void); + +/********************** + * MACROS + **********************/ + +/********************** + * ADD BUILT IN FONTS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FONT_FMT_TXT_H*/ diff --git a/include/liblvgl/font/lv_font_loader.h b/include/liblvgl/font/lv_font_loader.h new file mode 100644 index 0000000..783cb2e --- /dev/null +++ b/include/liblvgl/font/lv_font_loader.h @@ -0,0 +1,40 @@ +/** + * @file lv_font_loader.h + * + */ + +#ifndef LV_FONT_LOADER_H +#define LV_FONT_LOADER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_font_t * lv_font_load(const char * fontName); +void lv_font_free(lv_font_t * font); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FONT_LOADER_H*/ diff --git a/include/liblvgl/font/lv_symbol_def.h b/include/liblvgl/font/lv_symbol_def.h new file mode 100644 index 0000000..1055392 --- /dev/null +++ b/include/liblvgl/font/lv_symbol_def.h @@ -0,0 +1,353 @@ +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "liblvgl/lv_conf_internal.h" + +/*------------------------------- + * Symbols from "normal" font + *-----------------------------*/ +#if !defined LV_SYMBOL_BULLET +#define LV_SYMBOL_BULLET "\xE2\x80\xA2" /*20042, 0x2022*/ +#endif + +/*------------------------------- + * Symbols from FontAwesome font + *-----------------------------*/ + +/*In the font converter use this list as range: + 61441, 61448, 61451, 61452, 61453, 61457, 61459, 61461, 61465, 61468, + 61473, 61478, 61479, 61480, 61502, 61507, 61512, 61515, 61516, 61517, + 61521, 61522, 61523, 61524, 61543, 61544, 61550, 61552, 61553, 61556, + 61559, 61560, 61561, 61563, 61587, 61589, 61636, 61637, 61639, 61641, + 61664, 61671, 61674, 61683, 61724, 61732, 61787, 61931, 62016, 62017, + 62018, 62019, 62020, 62087, 62099, 62189, 62212, 62810, 63426, 63650 +*/ + +/* These symbols can be prefined in the lv_conf.h file. + * If they are not predefined, they will use the following values + */ + + +#if !defined LV_SYMBOL_AUDIO +#define LV_SYMBOL_AUDIO "\xEF\x80\x81" /*61441, 0xF001*/ +#endif + +#if !defined LV_SYMBOL_VIDEO +#define LV_SYMBOL_VIDEO "\xEF\x80\x88" /*61448, 0xF008*/ +#endif + +#if !defined LV_SYMBOL_LIST +#define LV_SYMBOL_LIST "\xEF\x80\x8B" /*61451, 0xF00B*/ +#endif + +#if !defined LV_SYMBOL_OK +#define LV_SYMBOL_OK "\xEF\x80\x8C" /*61452, 0xF00C*/ +#endif + +#if !defined LV_SYMBOL_CLOSE +#define LV_SYMBOL_CLOSE "\xEF\x80\x8D" /*61453, 0xF00D*/ +#endif + +#if !defined LV_SYMBOL_POWER +#define LV_SYMBOL_POWER "\xEF\x80\x91" /*61457, 0xF011*/ +#endif + +#if !defined LV_SYMBOL_SETTINGS +#define LV_SYMBOL_SETTINGS "\xEF\x80\x93" /*61459, 0xF013*/ +#endif + +#if !defined LV_SYMBOL_HOME +#define LV_SYMBOL_HOME "\xEF\x80\x95" /*61461, 0xF015*/ +#endif + +#if !defined LV_SYMBOL_DOWNLOAD +#define LV_SYMBOL_DOWNLOAD "\xEF\x80\x99" /*61465, 0xF019*/ +#endif + +#if !defined LV_SYMBOL_DRIVE +#define LV_SYMBOL_DRIVE "\xEF\x80\x9C" /*61468, 0xF01C*/ +#endif + +#if !defined LV_SYMBOL_REFRESH +#define LV_SYMBOL_REFRESH "\xEF\x80\xA1" /*61473, 0xF021*/ +#endif + +#if !defined LV_SYMBOL_MUTE +#define LV_SYMBOL_MUTE "\xEF\x80\xA6" /*61478, 0xF026*/ +#endif + +#if !defined LV_SYMBOL_VOLUME_MID +#define LV_SYMBOL_VOLUME_MID "\xEF\x80\xA7" /*61479, 0xF027*/ +#endif + +#if !defined LV_SYMBOL_VOLUME_MAX +#define LV_SYMBOL_VOLUME_MAX "\xEF\x80\xA8" /*61480, 0xF028*/ +#endif + +#if !defined LV_SYMBOL_IMAGE +#define LV_SYMBOL_IMAGE "\xEF\x80\xBE" /*61502, 0xF03E*/ +#endif + +#if !defined LV_SYMBOL_TINT +#define LV_SYMBOL_TINT "\xEF\x81\x83" /*61507, 0xF043*/ +#endif + +#if !defined LV_SYMBOL_PREV +#define LV_SYMBOL_PREV "\xEF\x81\x88" /*61512, 0xF048*/ +#endif + +#if !defined LV_SYMBOL_PLAY +#define LV_SYMBOL_PLAY "\xEF\x81\x8B" /*61515, 0xF04B*/ +#endif + +#if !defined LV_SYMBOL_PAUSE +#define LV_SYMBOL_PAUSE "\xEF\x81\x8C" /*61516, 0xF04C*/ +#endif + +#if !defined LV_SYMBOL_STOP +#define LV_SYMBOL_STOP "\xEF\x81\x8D" /*61517, 0xF04D*/ +#endif + +#if !defined LV_SYMBOL_NEXT +#define LV_SYMBOL_NEXT "\xEF\x81\x91" /*61521, 0xF051*/ +#endif + +#if !defined LV_SYMBOL_EJECT +#define LV_SYMBOL_EJECT "\xEF\x81\x92" /*61522, 0xF052*/ +#endif + +#if !defined LV_SYMBOL_LEFT +#define LV_SYMBOL_LEFT "\xEF\x81\x93" /*61523, 0xF053*/ +#endif + +#if !defined LV_SYMBOL_RIGHT +#define LV_SYMBOL_RIGHT "\xEF\x81\x94" /*61524, 0xF054*/ +#endif + +#if !defined LV_SYMBOL_PLUS +#define LV_SYMBOL_PLUS "\xEF\x81\xA7" /*61543, 0xF067*/ +#endif + +#if !defined LV_SYMBOL_MINUS +#define LV_SYMBOL_MINUS "\xEF\x81\xA8" /*61544, 0xF068*/ +#endif + +#if !defined LV_SYMBOL_EYE_OPEN +#define LV_SYMBOL_EYE_OPEN "\xEF\x81\xAE" /*61550, 0xF06E*/ +#endif + +#if !defined LV_SYMBOL_EYE_CLOSE +#define LV_SYMBOL_EYE_CLOSE "\xEF\x81\xB0" /*61552, 0xF070*/ +#endif + +#if !defined LV_SYMBOL_WARNING +#define LV_SYMBOL_WARNING "\xEF\x81\xB1" /*61553, 0xF071*/ +#endif + +#if !defined LV_SYMBOL_SHUFFLE +#define LV_SYMBOL_SHUFFLE "\xEF\x81\xB4" /*61556, 0xF074*/ +#endif + +#if !defined LV_SYMBOL_UP +#define LV_SYMBOL_UP "\xEF\x81\xB7" /*61559, 0xF077*/ +#endif + +#if !defined LV_SYMBOL_DOWN +#define LV_SYMBOL_DOWN "\xEF\x81\xB8" /*61560, 0xF078*/ +#endif + +#if !defined LV_SYMBOL_LOOP +#define LV_SYMBOL_LOOP "\xEF\x81\xB9" /*61561, 0xF079*/ +#endif + +#if !defined LV_SYMBOL_DIRECTORY +#define LV_SYMBOL_DIRECTORY "\xEF\x81\xBB" /*61563, 0xF07B*/ +#endif + +#if !defined LV_SYMBOL_UPLOAD +#define LV_SYMBOL_UPLOAD "\xEF\x82\x93" /*61587, 0xF093*/ +#endif + +#if !defined LV_SYMBOL_CALL +#define LV_SYMBOL_CALL "\xEF\x82\x95" /*61589, 0xF095*/ +#endif + +#if !defined LV_SYMBOL_CUT +#define LV_SYMBOL_CUT "\xEF\x83\x84" /*61636, 0xF0C4*/ +#endif + +#if !defined LV_SYMBOL_COPY +#define LV_SYMBOL_COPY "\xEF\x83\x85" /*61637, 0xF0C5*/ +#endif + +#if !defined LV_SYMBOL_SAVE +#define LV_SYMBOL_SAVE "\xEF\x83\x87" /*61639, 0xF0C7*/ +#endif + +#if !defined LV_SYMBOL_BARS +#define LV_SYMBOL_BARS "\xEF\x83\x89" /*61641, 0xF0C9*/ +#endif + +#if !defined LV_SYMBOL_ENVELOPE +#define LV_SYMBOL_ENVELOPE "\xEF\x83\xA0" /*61664, 0xF0E0*/ +#endif + +#if !defined LV_SYMBOL_CHARGE +#define LV_SYMBOL_CHARGE "\xEF\x83\xA7" /*61671, 0xF0E7*/ +#endif + +#if !defined LV_SYMBOL_PASTE +#define LV_SYMBOL_PASTE "\xEF\x83\xAA" /*61674, 0xF0EA*/ +#endif + +#if !defined LV_SYMBOL_BELL +#define LV_SYMBOL_BELL "\xEF\x83\xB3" /*61683, 0xF0F3*/ +#endif + +#if !defined LV_SYMBOL_KEYBOARD +#define LV_SYMBOL_KEYBOARD "\xEF\x84\x9C" /*61724, 0xF11C*/ +#endif + +#if !defined LV_SYMBOL_GPS +#define LV_SYMBOL_GPS "\xEF\x84\xA4" /*61732, 0xF124*/ +#endif + +#if !defined LV_SYMBOL_FILE +#define LV_SYMBOL_FILE "\xEF\x85\x9B" /*61787, 0xF158*/ +#endif + +#if !defined LV_SYMBOL_WIFI +#define LV_SYMBOL_WIFI "\xEF\x87\xAB" /*61931, 0xF1EB*/ +#endif + +#if !defined LV_SYMBOL_BATTERY_FULL +#define LV_SYMBOL_BATTERY_FULL "\xEF\x89\x80" /*62016, 0xF240*/ +#endif + +#if !defined LV_SYMBOL_BATTERY_3 +#define LV_SYMBOL_BATTERY_3 "\xEF\x89\x81" /*62017, 0xF241*/ +#endif + +#if !defined LV_SYMBOL_BATTERY_2 +#define LV_SYMBOL_BATTERY_2 "\xEF\x89\x82" /*62018, 0xF242*/ +#endif + +#if !defined LV_SYMBOL_BATTERY_1 +#define LV_SYMBOL_BATTERY_1 "\xEF\x89\x83" /*62019, 0xF243*/ +#endif + +#if !defined LV_SYMBOL_BATTERY_EMPTY +#define LV_SYMBOL_BATTERY_EMPTY "\xEF\x89\x84" /*62020, 0xF244*/ +#endif + +#if !defined LV_SYMBOL_USB +#define LV_SYMBOL_USB "\xEF\x8a\x87" /*62087, 0xF287*/ +#endif + +#if !defined LV_SYMBOL_BLUETOOTH +#define LV_SYMBOL_BLUETOOTH "\xEF\x8a\x93" /*62099, 0xF293*/ +#endif + +#if !defined LV_SYMBOL_TRASH +#define LV_SYMBOL_TRASH "\xEF\x8B\xAD" /*62189, 0xF2ED*/ +#endif + +#if !defined LV_SYMBOL_EDIT +#define LV_SYMBOL_EDIT "\xEF\x8C\x84" /*62212, 0xF304*/ +#endif + +#if !defined LV_SYMBOL_BACKSPACE +#define LV_SYMBOL_BACKSPACE "\xEF\x95\x9A" /*62810, 0xF55A*/ +#endif + +#if !defined LV_SYMBOL_SD_CARD +#define LV_SYMBOL_SD_CARD "\xEF\x9F\x82" /*63426, 0xF7C2*/ +#endif + +#if !defined LV_SYMBOL_NEW_LINE +#define LV_SYMBOL_NEW_LINE "\xEF\xA2\xA2" /*63650, 0xF8A2*/ +#endif + +#if !defined LV_SYMBOL_DUMMY +/** Invalid symbol at (U+F8FF). If written before a string then `lv_img` will show it as a label*/ +#define LV_SYMBOL_DUMMY "\xEF\xA3\xBF" +#endif + +/* + * The following list is generated using + * cat src/font/lv_symbol_def.h | sed -E -n 's/^#define\s+LV_(SYMBOL_\w+).*".*$/ _LV_STR_\1,/p' + */ +enum { + _LV_STR_SYMBOL_BULLET, + _LV_STR_SYMBOL_AUDIO, + _LV_STR_SYMBOL_VIDEO, + _LV_STR_SYMBOL_LIST, + _LV_STR_SYMBOL_OK, + _LV_STR_SYMBOL_CLOSE, + _LV_STR_SYMBOL_POWER, + _LV_STR_SYMBOL_SETTINGS, + _LV_STR_SYMBOL_HOME, + _LV_STR_SYMBOL_DOWNLOAD, + _LV_STR_SYMBOL_DRIVE, + _LV_STR_SYMBOL_REFRESH, + _LV_STR_SYMBOL_MUTE, + _LV_STR_SYMBOL_VOLUME_MID, + _LV_STR_SYMBOL_VOLUME_MAX, + _LV_STR_SYMBOL_IMAGE, + _LV_STR_SYMBOL_TINT, + _LV_STR_SYMBOL_PREV, + _LV_STR_SYMBOL_PLAY, + _LV_STR_SYMBOL_PAUSE, + _LV_STR_SYMBOL_STOP, + _LV_STR_SYMBOL_NEXT, + _LV_STR_SYMBOL_EJECT, + _LV_STR_SYMBOL_LEFT, + _LV_STR_SYMBOL_RIGHT, + _LV_STR_SYMBOL_PLUS, + _LV_STR_SYMBOL_MINUS, + _LV_STR_SYMBOL_EYE_OPEN, + _LV_STR_SYMBOL_EYE_CLOSE, + _LV_STR_SYMBOL_WARNING, + _LV_STR_SYMBOL_SHUFFLE, + _LV_STR_SYMBOL_UP, + _LV_STR_SYMBOL_DOWN, + _LV_STR_SYMBOL_LOOP, + _LV_STR_SYMBOL_DIRECTORY, + _LV_STR_SYMBOL_UPLOAD, + _LV_STR_SYMBOL_CALL, + _LV_STR_SYMBOL_CUT, + _LV_STR_SYMBOL_COPY, + _LV_STR_SYMBOL_SAVE, + _LV_STR_SYMBOL_BARS, + _LV_STR_SYMBOL_ENVELOPE, + _LV_STR_SYMBOL_CHARGE, + _LV_STR_SYMBOL_PASTE, + _LV_STR_SYMBOL_BELL, + _LV_STR_SYMBOL_KEYBOARD, + _LV_STR_SYMBOL_GPS, + _LV_STR_SYMBOL_FILE, + _LV_STR_SYMBOL_WIFI, + _LV_STR_SYMBOL_BATTERY_FULL, + _LV_STR_SYMBOL_BATTERY_3, + _LV_STR_SYMBOL_BATTERY_2, + _LV_STR_SYMBOL_BATTERY_1, + _LV_STR_SYMBOL_BATTERY_EMPTY, + _LV_STR_SYMBOL_USB, + _LV_STR_SYMBOL_BLUETOOTH, + _LV_STR_SYMBOL_TRASH, + _LV_STR_SYMBOL_EDIT, + _LV_STR_SYMBOL_BACKSPACE, + _LV_STR_SYMBOL_SD_CARD, + _LV_STR_SYMBOL_NEW_LINE, + _LV_STR_SYMBOL_DUMMY, +}; + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/include/liblvgl/hal/lv_hal.h b/include/liblvgl/hal/lv_hal.h new file mode 100644 index 0000000..167da1f --- /dev/null +++ b/include/liblvgl/hal/lv_hal.h @@ -0,0 +1,48 @@ +/** + * @file lv_hal.h + * + */ + +#ifndef LV_HAL_H +#define LV_HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ +/** + * Same as Android's DIP. (Different name is chosen to avoid mistype between LV_DPI and LV_DIP) + * 1 dip is 1 px on a 160 DPI screen + * 1 dip is 2 px on a 320 DPI screen + * https://stackoverflow.com/questions/2025282/what-is-the-difference-between-px-dip-dp-and-sp + */ +#define _LV_DPX_CALC(dpi, n) ((n) == 0 ? 0 :LV_MAX((( (dpi) * (n) + 80) / 160), 1)) /*+80 for rounding*/ +#define LV_DPX(n) _LV_DPX_CALC(lv_disp_get_dpi(NULL), n) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/hal/lv_hal_disp.h b/include/liblvgl/hal/lv_hal_disp.h new file mode 100644 index 0000000..5b36916 --- /dev/null +++ b/include/liblvgl/hal/lv_hal_disp.h @@ -0,0 +1,371 @@ +/** + * @file lv_hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef LV_HAL_DISP_H +#define LV_HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "liblvgl/draw/lv_draw.h" +#include "liblvgl/misc/lv_color.h" +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_ll.h" +#include "liblvgl/misc/lv_timer.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_INV_BUF_SIZE +#define LV_INV_BUF_SIZE 32 /*Buffer size for invalid areas*/ +#endif + +#ifndef LV_ATTRIBUTE_FLUSH_READY +#define LV_ATTRIBUTE_FLUSH_READY +#endif + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_disp_t; +struct _lv_disp_drv_t; +struct _lv_theme_t; + +/** + * Structure for holding display buffer information. + */ +typedef struct _lv_disp_draw_buf_t { + void * buf1; /**< First display buffer.*/ + void * buf2; /**< Second display buffer.*/ + + /*Internal, used by the library*/ + void * buf_act; + uint32_t size; /*In pixel count*/ + /*1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/ + volatile int flushing; + /*1: It was the last chunk to flush. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/ + volatile int flushing_last; + volatile uint32_t last_area : 1; /*1: the last area is being rendered*/ + volatile uint32_t last_part : 1; /*1: the last part of the current area is being rendered*/ +} lv_disp_draw_buf_t; + +typedef enum { + LV_DISP_ROT_NONE = 0, + LV_DISP_ROT_90, + LV_DISP_ROT_180, + LV_DISP_ROT_270 +} lv_disp_rot_t; + +/** + * Display Driver structure to be registered by HAL. + * Only its pointer will be saved in `lv_disp_t` so it should be declared as + * `static lv_disp_drv_t my_drv` or allocated dynamically. + */ +typedef struct _lv_disp_drv_t { + + lv_coord_t hor_res; /**< Horizontal resolution.*/ + lv_coord_t ver_res; /**< Vertical resolution.*/ + + lv_coord_t + physical_hor_res; /**< Horizontal resolution of the full / physical display. Set to -1 for fullscreen mode.*/ + lv_coord_t + physical_ver_res; /**< Vertical resolution of the full / physical display. Set to -1 for fullscreen mode.*/ + lv_coord_t + offset_x; /**< Horizontal offset from the full / physical display. Set to 0 for fullscreen mode.*/ + lv_coord_t offset_y; /**< Vertical offset from the full / physical display. Set to 0 for fullscreen mode.*/ + + /** Pointer to a buffer initialized with `lv_disp_draw_buf_init()`. + * LVGL will use this buffer(s) to draw the screens contents*/ + lv_disp_draw_buf_t * draw_buf; + + uint32_t direct_mode : 1; /**< 1: Use screen-sized buffers and draw to absolute coordinates*/ + uint32_t full_refresh : 1; /**< 1: Always make the whole screen redrawn*/ + uint32_t sw_rotate : 1; /**< 1: use software rotation (slower)*/ + uint32_t antialiasing : 1; /**< 1: anti-aliasing is enabled on this display.*/ + uint32_t rotated : 2; /**< 1: turn the display by 90 degree. @warning Does not update coordinates for you!*/ + uint32_t screen_transp : 1; /**Handle if the screen doesn't have a solid (opa == LV_OPA_COVER) background. + * Use only if required because it's slower.*/ + + uint32_t dpi : 10; /** DPI (dot per inch) of the display. Default value is `LV_DPI_DEF`.*/ + + /** MANDATORY: Write the internal buffer (draw_buf) to the display. 'lv_disp_flush_ready()' has to be + * called when finished*/ + void (*flush_cb)(struct _lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p); + + /** OPTIONAL: Extend the invalidated areas to match with the display drivers requirements + * E.g. round `y` to, 8, 16 ..) on a monochrome display*/ + void (*rounder_cb)(struct _lv_disp_drv_t * disp_drv, lv_area_t * area); + + /** OPTIONAL: Set a pixel in a buffer according to the special requirements of the display + * Can be used for color format not supported in LittelvGL. E.g. 2 bit -> 4 gray scales + * @note Much slower then drawing with supported color formats.*/ + void (*set_px_cb)(struct _lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, + lv_color_t color, lv_opa_t opa); + + void (*clear_cb)(struct _lv_disp_drv_t * disp_drv, uint8_t * buf, uint32_t size); + + + /** OPTIONAL: Called after every refresh cycle to tell the rendering and flushing time + the + * number of flushed pixels*/ + void (*monitor_cb)(struct _lv_disp_drv_t * disp_drv, uint32_t time, uint32_t px); + + /** OPTIONAL: Called periodically while lvgl waits for operation to be completed. + * For example flushing or GPU + * User can execute very simple tasks here or yield the task*/ + void (*wait_cb)(struct _lv_disp_drv_t * disp_drv); + + /** OPTIONAL: Called when lvgl needs any CPU cache that affects rendering to be cleaned*/ + void (*clean_dcache_cb)(struct _lv_disp_drv_t * disp_drv); + + /** OPTIONAL: called when driver parameters are updated */ + void (*drv_update_cb)(struct _lv_disp_drv_t * disp_drv); + + /** OPTIONAL: called when start rendering */ + void (*render_start_cb)(struct _lv_disp_drv_t * disp_drv); + + /** On CHROMA_KEYED images this color will be transparent. + * `LV_COLOR_CHROMA_KEY` by default. (lv_conf.h)*/ + lv_color_t color_chroma_key; + + lv_draw_ctx_t * draw_ctx; + void (*draw_ctx_init)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + void (*draw_ctx_deinit)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx); + size_t draw_ctx_size; + +#if LV_USE_USER_DATA + void * user_data; /**< Custom display driver user data*/ +#endif + +} lv_disp_drv_t; + +/** + * Display structure. + * @note `lv_disp_drv_t` should be the first member of the structure. + */ +typedef struct _lv_disp_t { + /**< Driver to the display*/ + struct _lv_disp_drv_t * driver; + + /**< A timer which periodically checks the dirty areas and refreshes them*/ + lv_timer_t * refr_timer; + + /**< The theme assigned to the screen*/ + struct _lv_theme_t * theme; + + /** Screens of the display*/ + struct _lv_obj_t ** screens; /**< Array of screen objects.*/ + struct _lv_obj_t * act_scr; /**< Currently active screen on this display*/ + struct _lv_obj_t * prev_scr; /**< Previous screen. Used during screen animations*/ + struct _lv_obj_t * scr_to_load; /**< The screen prepared to load in lv_scr_load_anim*/ + struct _lv_obj_t * top_layer; /**< @see lv_disp_get_layer_top*/ + struct _lv_obj_t * sys_layer; /**< @see lv_disp_get_layer_sys*/ + uint32_t screen_cnt; +uint8_t draw_prev_over_act : + 1; /**< 1: Draw previous screen over active screen*/ +uint8_t del_prev : + 1; /**< 1: Automatically delete the previous screen when the screen load animation is ready*/ + uint8_t rendering_in_progress : 1; /**< 1: The current screen rendering is in progress*/ + + lv_opa_t bg_opa; /**flush` you should use DMA or similar hardware to send + * the image to the display in the background. + * It lets LVGL to render next frame into the other buffer while previous is being + * sent. Set to `NULL` if unused. + * @param size_in_px_cnt size of the `buf1` and `buf2` in pixel count. + */ +void lv_disp_draw_buf_init(lv_disp_draw_buf_t * draw_buf, void * buf1, void * buf2, uint32_t size_in_px_cnt); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable. Only its pointer is saved! + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver); + +/** + * Update the driver in run time. + * @param disp pointer to a display. (return value of `lv_disp_drv_register`) + * @param new_drv pointer to the new driver + */ +void lv_disp_drv_update(lv_disp_t * disp, lv_disp_drv_t * new_drv); + +/** + * Remove a display + * @param disp pointer to display + */ +void lv_disp_remove(lv_disp_t * disp); + +/** + * Set a default display. The new screens will be created on it by default. + * @param disp pointer to a display + */ +void lv_disp_set_default(lv_disp_t * disp); + +/** + * Get the default display + * @return pointer to the default display + */ +lv_disp_t * lv_disp_get_default(void); + +/** + * Get the horizontal resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the horizontal resolution of the display + */ +lv_coord_t lv_disp_get_hor_res(lv_disp_t * disp); + +/** + * Get the vertical resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the vertical resolution of the display + */ +lv_coord_t lv_disp_get_ver_res(lv_disp_t * disp); + +/** + * Get the full / physical horizontal resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the full / physical horizontal resolution of the display + */ +lv_coord_t lv_disp_get_physical_hor_res(lv_disp_t * disp); + +/** + * Get the full / physical vertical resolution of a display + * @param disp pointer to a display (NULL to use the default display) + * @return the full / physical vertical resolution of the display + */ +lv_coord_t lv_disp_get_physical_ver_res(lv_disp_t * disp); + +/** + * Get the horizontal offset from the full / physical display + * @param disp pointer to a display (NULL to use the default display) + * @return the horizontal offset from the full / physical display + */ +lv_coord_t lv_disp_get_offset_x(lv_disp_t * disp); + +/** + * Get the vertical offset from the full / physical display + * @param disp pointer to a display (NULL to use the default display) + * @return the horizontal offset from the full / physical display + */ +lv_coord_t lv_disp_get_offset_y(lv_disp_t * disp); + +/** + * Get if anti-aliasing is enabled for a display or not + * @param disp pointer to a display (NULL to use the default display) + * @return true: anti-aliasing is enabled; false: disabled + */ +bool lv_disp_get_antialiasing(lv_disp_t * disp); + +/** + * Get the DPI of the display + * @param disp pointer to a display (NULL to use the default display) + * @return dpi of the display + */ +lv_coord_t lv_disp_get_dpi(const lv_disp_t * disp); + + +/** + * Set the rotation of this display. + * @param disp pointer to a display (NULL to use the default display) + * @param rotation rotation angle + */ +void lv_disp_set_rotation(lv_disp_t * disp, lv_disp_rot_t rotation); + +/** + * Get the current rotation of this display. + * @param disp pointer to a display (NULL to use the default display) + * @return rotation angle + */ +lv_disp_rot_t lv_disp_get_rotation(lv_disp_t * disp); + +//! @cond Doxygen_Suppress + +/** + * Call in the display driver's `flush_cb` function when the flushing is finished + * @param disp_drv pointer to display driver in `flush_cb` where this function is called + */ +LV_ATTRIBUTE_FLUSH_READY void lv_disp_flush_ready(lv_disp_drv_t * disp_drv); + +/** + * Tell if it's the last area of the refreshing process. + * Can be called from `flush_cb` to execute some special display refreshing if needed when all areas area flushed. + * @param disp_drv pointer to display driver + * @return true: it's the last area to flush; false: there are other areas too which will be refreshed soon + */ +LV_ATTRIBUTE_FLUSH_READY bool lv_disp_flush_is_last(lv_disp_drv_t * disp_drv); + +//! @endcond + +/** + * Get the next display. + * @param disp pointer to the current display. NULL to initialize. + * @return the next display or NULL if no more. Give the first display when the parameter is NULL + */ +lv_disp_t * lv_disp_get_next(lv_disp_t * disp); + +/** + * Get the internal buffer of a display + * @param disp pointer to a display + * @return pointer to the internal buffers + */ +lv_disp_draw_buf_t * lv_disp_get_draw_buf(lv_disp_t * disp); + +void lv_disp_drv_use_generic_set_px_cb(lv_disp_drv_t * disp_drv, lv_img_cf_t cf); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/hal/lv_hal_indev.h b/include/liblvgl/hal/lv_hal_indev.h new file mode 100644 index 0000000..630d471 --- /dev/null +++ b/include/liblvgl/hal/lv_hal_indev.h @@ -0,0 +1,239 @@ +/** + * @file lv_hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef LV_HAL_INDEV_H +#define LV_HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include "liblvgl/misc/lv_area.h" +#include "liblvgl/misc/lv_timer.h" + +/********************* + * DEFINES + *********************/ + +/*Drag threshold in pixels*/ +#define LV_INDEV_DEF_SCROLL_LIMIT 10 + +/*Drag throw slow-down in [%]. Greater value -> faster slow-down*/ +#define LV_INDEV_DEF_SCROLL_THROW 10 + +/*Long press time in milliseconds. + *Time to send `LV_EVENT_LONG_PRESSSED`)*/ +#define LV_INDEV_DEF_LONG_PRESS_TIME 400 + +/*Repeated trigger period in long press [ms] + *Time between `LV_EVENT_LONG_PRESSED_REPEAT*/ +#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100 + + +/*Gesture threshold in pixels*/ +#define LV_INDEV_DEF_GESTURE_LIMIT 50 + +/*Gesture min velocity at release before swipe (pixels)*/ +#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3 + + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; +struct _lv_disp_t; +struct _lv_group_t; +struct _lv_indev_t; +struct _lv_indev_drv_t; + +/** Possible input device types*/ +typedef enum { + LV_INDEV_TYPE_NONE, /**< Uninitialized state*/ + LV_INDEV_TYPE_POINTER, /**< Touch pad, mouse, external button*/ + LV_INDEV_TYPE_KEYPAD, /**< Keypad or keyboard*/ + LV_INDEV_TYPE_BUTTON, /**< External (hardware button) which is assigned to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /**< Encoder with only Left, Right turn and a Button*/ +} lv_indev_type_t; + +/** States for input devices*/ +typedef enum { + LV_INDEV_STATE_RELEASED = 0, + LV_INDEV_STATE_PRESSED +} lv_indev_state_t; + +/** Data structure passed to an input driver to fill*/ +typedef struct { + lv_point_t point; /**< For LV_INDEV_TYPE_POINTER the currently pressed point*/ + uint32_t key; /**< For LV_INDEV_TYPE_KEYPAD the currently pressed key*/ + uint32_t btn_id; /**< For LV_INDEV_TYPE_BUTTON the currently pressed button*/ + int16_t enc_diff; /**< For LV_INDEV_TYPE_ENCODER number of steps since the previous read*/ + + lv_indev_state_t state; /**< LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ + bool continue_reading; /**< If set to true, the read callback is invoked again*/ +} lv_indev_data_t; + +/** Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct _lv_indev_drv_t { + + /**< Input device type*/ + lv_indev_type_t type; + + /**< Function pointer to read input device data.*/ + void (*read_cb)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + + /** Called when an action happened on the input device. + * The second parameter is the event from `lv_event_t`*/ + void (*feedback_cb)(struct _lv_indev_drv_t *, uint8_t); + +#if LV_USE_USER_DATA + void * user_data; +#endif + + /**< Pointer to the assigned display*/ + struct _lv_disp_t * disp; + + /**< Timer to periodically read the input device*/ + lv_timer_t * read_timer; + + /**< Number of pixels to slide before actually drag the object*/ + uint8_t scroll_limit; + + /**< Drag throw slow-down in [%]. Greater value means faster slow-down*/ + uint8_t scroll_throw; + + /**< At least this difference should be between two points to evaluate as gesture*/ + uint8_t gesture_min_velocity; + + /**< At least this difference should be to send a gesture*/ + uint8_t gesture_limit; + + /**< Long press time in milliseconds*/ + uint16_t long_press_time; + + /**< Repeated trigger period in long press [ms]*/ + uint16_t long_press_repeat_time; +} lv_indev_drv_t; + +/** Run time data of input devices + * Internally used by the library, you should not need to touch it. + */ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; /**< Current state of the input device.*/ + /*Flags*/ + uint8_t long_pr_sent : 1; + uint8_t reset_query : 1; + uint8_t disabled : 1; + uint8_t wait_until_release : 1; + + union { + struct { + /*Pointer and button data*/ + lv_point_t act_point; /**< Current point of input device.*/ + lv_point_t last_point; /**< Last point of input device.*/ + lv_point_t last_raw_point; /**< Last point read from read_cb. */ + lv_point_t vect; /**< Difference between `act_point` and `last_point`.*/ + lv_point_t scroll_sum; /*Count the dragged pixels to check LV_INDEV_DEF_SCROLL_LIMIT*/ + lv_point_t scroll_throw_vect; + lv_point_t scroll_throw_vect_ori; + struct _lv_obj_t * act_obj; /*The object being pressed*/ + struct _lv_obj_t * last_obj; /*The last object which was pressed*/ + struct _lv_obj_t * scroll_obj; /*The object being scrolled*/ + struct _lv_obj_t * last_pressed; /*The lastly pressed object*/ + lv_area_t scroll_area; + + lv_point_t gesture_sum; /*Count the gesture pixels to check LV_INDEV_DEF_GESTURE_LIMIT*/ + /*Flags*/ + lv_dir_t scroll_dir : 4; + lv_dir_t gesture_dir : 4; + uint8_t gesture_sent : 1; + } pointer; + struct { + /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + } keypad; + } types; + + uint32_t pr_timestamp; /**< Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /**< Long press repeat time stamp*/ +} _lv_indev_proc_t; + +/** The main input device descriptor with driver, runtime data ('proc') and some additional + * information*/ +typedef struct _lv_indev_t { + struct _lv_indev_drv_t * driver; + _lv_indev_proc_t proc; + struct _lv_obj_t * cursor; /**< Cursor for LV_INPUT_TYPE_POINTER*/ + struct _lv_group_t * group; /**< Keypad destination group*/ + const lv_point_t * btn_points; /**< Array points assigned to the button ()screen will be pressed + here by the buttons*/ +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device driver with default values. + * It is used to surely have known values in the fields and not memory junk. + * After it you can set the fields. + * @param driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(struct _lv_indev_drv_t * driver); + +/** + * Register an initialized input device driver. + * @param driver pointer to an initialized 'lv_indev_drv_t' variable (can be local variable) + * @return pointer to the new input device or NULL on error + */ +lv_indev_t * lv_indev_drv_register(struct _lv_indev_drv_t * driver); + +/** + * Update the driver in run time. + * @param indev pointer to an input device. (return value of `lv_indev_drv_register`) + * @param new_drv pointer to the new driver + */ +void lv_indev_drv_update(lv_indev_t * indev, struct _lv_indev_drv_t * new_drv); + +/** +* Remove the provided input device. Make sure not to use the provided input device afterwards anymore. +* @param indev pointer to delete +*/ +void lv_indev_delete(lv_indev_t * indev); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input device or NULL if there are no more. Provide the first input device when + * the parameter is NULL + */ +lv_indev_t * lv_indev_get_next(lv_indev_t * indev); + +/** + * Read data from an input device. + * @param indev pointer to an input device + * @param data input device will write its data here + */ +void _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/hal/lv_hal_tick.h b/include/liblvgl/hal/lv_hal_tick.h new file mode 100644 index 0000000..407fa42 --- /dev/null +++ b/include/liblvgl/hal/lv_hal_tick.h @@ -0,0 +1,69 @@ +/** + * @file lv_hal_tick.h + * Provide access to the system tick with 1 millisecond resolution + */ + +#ifndef LV_HAL_TICK_H +#define LV_HAL_TICK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +//! @cond Doxygen_Suppress + +#if !LV_TICK_CUSTOM +/** + * You have to call this function periodically + * @param tick_period the call period of this function in milliseconds + */ +LV_ATTRIBUTE_TICK_INC void lv_tick_inc(uint32_t tick_period); +#endif + +//! @endcond + +/** + * Get the elapsed milliseconds since start up + * @return the elapsed milliseconds + */ +uint32_t lv_tick_get(void); + +/** + * Get the elapsed milliseconds since a previous time stamp + * @param prev_tick a previous time stamp (return value of lv_tick_get() ) + * @return the elapsed milliseconds since 'prev_tick' + */ +uint32_t lv_tick_elaps(uint32_t prev_tick); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_HAL_TICK_H*/ diff --git a/include/liblvgl/llemu.h b/include/liblvgl/llemu.h new file mode 100644 index 0000000..c3c4e6d --- /dev/null +++ b/include/liblvgl/llemu.h @@ -0,0 +1,438 @@ +/** + * \file liblvgl/llemu.h + * \ingroup c-llemu + * + * Legacy LCD Emulator + * + * \details This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-llemu LLEMU C API + * @{ + * LLEMU - Legacy Lcd EMUlator + * + * \image html llemu/llemu-3.8.png + * + * LLEMU provides a virtual 40x8 LCD screen with 3 buttons. The user can set the + * text of the screen and set create functions that are run when the buttons are + * pressed. + * + * LLEMU is a emulation of the UART-based LCD screens that were available with + * VEX's cortex product line. + * @} + */ + +#ifndef _LIBLVGL_LLEMU_H_ +#define _LIBLVGL_LLEMU_H_ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#include "liblvgl/lvgl.h" +#pragma GCC diagnostic pop + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef void (*lcd_btn_cb_fn_t)(void); + +#define LCD_BTN_LEFT 4 +#define LCD_BTN_CENTER 2 +#define LCD_BTN_RIGHT 1 + +typedef struct lcd_s { + lv_obj_t* frame; + lv_obj_t* screen; + lv_obj_t* lcd_text[8]; + lv_obj_t* btn_container; + lv_obj_t* btns[3]; // < 0 => left; 1 => center; 2 => right + lcd_btn_cb_fn_t callbacks[3]; // < 0 => left; 1 => center; 2 => right + volatile uint8_t touch_bits; // < 4 => left; 2 => center; 1 => right (no + // multitouch support) +} lcd_s_t; + +/** + * \ingroup c-llemu + */ + +/** + * \addtogroup c-llemu + * @{ + */ + +/** + * \enum lcd_text_align_e + * + * @brief Represents how to align the text in the LCD + */ +typedef enum lcd_text_align_e { + /// Align the text to the left side of LCD line + LCD_TEXT_ALIGN_LEFT = 0, + /// Align the text to the center of the LCD line + LCD_TEXT_ALIGN_CENTER = 1, + /// Align the text to the right side of the LCD line + LCD_TEXT_ALIGN_RIGHT = 2 +} text_align_e_t; + +/// @} + +#ifdef __cplusplus + +/** + * \ingroup c-llemu + */ +namespace c { +#endif + +/** + * \ingroup c-llemu + */ + +/** + * \addtogroup c-llemu + * @{ + */ + +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + * + * \b Example + * \code + * if (pros::c::lcd_is_initialized()) { + * pros::c::lcd_print("LLEMU!"); + * } + * else { + * printf("Error: LLEMU is not initialized\n"); + * } + * \endcode + */ +bool lcd_is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * if (pros::c::lcd_initialize()) { + * pros::c::lcd_print("LLEMU!"); + * } + * else { + * printf("Error: LLEMU could not initailize\n"); + * } + * } + * \endcode + */ +bool lcd_initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void disabled() { + * pros::c::lcd_shutdown(); + * } + * \endcode + */ +bool lcd_shutdown(void); + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_print(0, "My formatted text: %d!", 2); + * } + * \endcode + */ +bool lcd_print(int16_t line, const char* fmt, ...); + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_set_text(0, "My custom LLEMU text!"); + * } + * \endcode + */ +bool lcd_set_text(int16_t line, const char* text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_clear(); // Clear the LCD screen + * } + * \endcode + */ +bool lcd_clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_clear_line(0); // Clear line 0 + * } + * \endcode + */ +bool lcd_clear_line(int16_t line); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void left_callback() { + * static int i = 0; + * + * i++; + * pros::c::lcd_print(0, "Left button pressed %i times", i); + * } + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_register_btn0_cb(); + * } + * \endcode + */ +bool lcd_register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void center_callback() { + * static int i = 0; + * + * i++; + * pros::c::lcd_print(0, "Center button pressed %i times", i); + * } + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_register_btn1_cb(); + * } + * \endcode + */ +bool lcd_register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t (void (*cb)(void)) + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void right_callback() { + * static int i = 0; + * + * i++; + * pros::c::lcd_print(0, "Right button pressed %i times", i); + * } + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_register_btn2_cb(); + * } + * \endcode + */ +bool lcd_register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + */ +uint8_t lcd_read_buttons(void); + +/** + * Changes the alignment of text on the LCD background + * + * \param alignment + * An enum specifying the alignment. Available alignments are: + * TEXT_ALIGN_LEFT + * TEXT_ALIGN_RIGHT + * TEXT_ALIGN_CENTER + * + * \b Example + * \code + * #include "pros/llemu.h" + * + * void initialize() { + * pros::c::lcd_initialize(); + * pros::c::lcd_set_alignment(pros::c::lcd_Text_Align::LEFT); + * pros::c::lcd_print(0, "Left Aligned Text"); + * pros::c::lcd_set_alignment(pros::c::lcd_Text_Align::CENTER); + * pros::c::lcd_print(1, "Center Aligned Text"); + * pros::c::lcd_set_alignment(pros::c::lcd_Text_Align::RIGHT); + * pros::c::lcd_print(2, "Right Aligned Text"); + * } + * \endcode + */ +void lcd_set_text_align(text_align_e_t alignment); + + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} // extern "C" +#endif +#endif // _LIBLVGL_LLEMU_H_ diff --git a/include/liblvgl/llemu.hpp b/include/liblvgl/llemu.hpp new file mode 100644 index 0000000..78d3193 --- /dev/null +++ b/include/liblvgl/llemu.hpp @@ -0,0 +1,373 @@ +/** + * \file liblvgl/llemu.hpp + * + * \ingroup cpp-llemu + * + * Legacy LCD Emulator + * + * \details This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/adi.html to learn more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-llemu LLEMU C++ API + * @{ + * LLEMU - Legacy Lcd EMUlator + * + * \image html llemu/llemu-3.8.png + * + * LLEMU provides a virtual 40x8 LCD screen with 3 buttons. The user can set the + * text of the screen and set create functions that are run when the buttons are + * pressed. + * + * LLEMU is a emulation of the UART-based LCD screens that were available with + * VEX's cortex product line. + * @} + */ + +#ifndef _LIBLVGL_LLEMU_HPP_ +#define _LIBLVGL_LLEMU_HPP_ + +#include +#include + +#include "liblvgl/llemu.h" + +namespace pros { + +/** + * \ingroup cpp-llemu + */ +namespace lcd { + +/** + * \ingroup cpp-llemu + */ + +/** + * \addtogroup cpp-llemu + * @{ + */ + +/** + * \enum Text_Align + * + * @brief Represents how to align the text in the LCD + */ +enum class Text_Align { + /// Align the text to the left side of LCD line + LEFT = 0, + /// Align the text to the center of the LCD line + CENTER = 1, + /// Align the text to the right side of the LCD line + RIGHT = 2 +}; + +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + * + * \b Example + * \code + * if (pros::lcd::is_initialized()) { + * pros::lcd::print("LLEMU!"); + * } + * else { + * printf("Error: LLEMU is not initialized\n"); + * } + * \endcode + */ +bool is_initialized(void); + +/** + * Creates an emulation of the three-button, UART-based VEX LCD on the display. + * + * \return True if the LCD was successfully initialized, or false if it has + * already been initialized. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * if (pros::lcd::initialize()) { + * pros::lcd::print("LLEMU!"); + * } + * else { + * printf("Error: LLEMU could not initailize\n"); + * } + * } + * \endcode + */ +bool initialize(void); + +/** + * Turns off the Legacy LCD Emulator. + * + * Calling this function will clear the entire display, and you will not be able + * to call any further LLEMU functions until another call to lcd_initialize. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void disabled() { + * pros::lcd::shutdown(); + * } + * \endcode + */ +bool shutdown(void); + +/** + * Displays a string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param text + * The text to display + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::set_text(0, "My custom LLEMU text!"); + * } + * \endcode + */ +bool set_text(std::int16_t line, std::string text); + +/** + * Clears the contents of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::clear(); // Clear the LCD screen + * } + * \endcode + */ +bool clear(void); + +/** + * Clears the contents of a line of the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line to clear + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::clear_line(0); // Clear line 0 + * } + * \endcode + */ +bool clear_line(std::int16_t line); + +using lcd_btn_cb_fn_t = void (*)(void); + +/** + * Registers a callback function for the leftmost button. + * + * When the leftmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void left_callback() { + * static int i = 0; + * + * pros::lcd::print(0, "Left button pressed %i times", i); + * i++ + * } + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::register_btn0_cb(); + * } + * \endcode + */ +void register_btn0_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the center button. + * + * When the center button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + * + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void center_callback() { + * static int i = 0; + * + * pros::lcd::print(0, "Center button pressed %i times", i); + * i++ + * } + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::register_btn1_cb(); + * } + * \endcode + */ +void register_btn1_cb(lcd_btn_cb_fn_t cb); + +/** + * Registers a callback function for the rightmost button. + * + * When the rightmost button on the emulated three-button LCD is pressed, the + * user-provided callback function will be invoked. + * + * \param cb + * A callback function of type lcd_btn_cb_fn_t(void (*cb)(void)) + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void right_callback() { + * static int i = 0; + * + * pros::lcd::print(0, "Right button pressed %i times", i); + * i++ + * } + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::register_btn2_cb(); + * } + * \endcode + */ +void register_btn2_cb(lcd_btn_cb_fn_t cb); + +/** + * Sets the alignment to use for subsequent calls that print text to a line. + * + * \param alignment + * An enum specifying the alignment. Available alignments are: + * TEXT_ALIGN_LEFT + * TEXT_ALIGN_RIGHT + * TEXT_ALIGN_CENTER + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::set_alignment(pros::lcd::Text_Align::LEFT); + * pros::lcd::print(0, "Left Aligned Text"); + * pros::lcd::set_alignment(pros::lcd::Text_Align::CENTER); + * pros::lcd::print(1, "Center Aligned Text"); + * pros::lcd::set_alignment(pros::lcd::Text_Align::RIGHT); + * pros::lcd::print(2, "Right Aligned Text"); + * } + * \endcode + */ +void set_text_align(Text_Align alignment); + +/** + * Gets the button status from the emulated three-button LCD. + * + * The value returned is a 3-bit integer where 1 0 0 indicates the left button + * is pressed, 0 1 0 indicates the center button is pressed, and 0 0 1 + * indicates the right button is pressed. 0 is returned if no buttons are + * currently being pressed. + * + * Note that this function is provided for legacy API compatibility purposes, + * with the caveat that the V5 touch screen does not actually support pressing + * multiple points on the screen at the same time. + * + * \return The buttons pressed as a bit mask + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * } + * + * void opcontrol() { + * while(true) { + * std::uint8_t state = pros::lcd::read_buttons(); + * pros::lcd::print(0, "%d %d %d", + * (state & LCD_BTN_LEFT) >> 2 + * (state & LCD_BTN_CENTER) >> 1, + * (state & LCD_BTN_RIGHT) >> 0 + * ); + * + * pros::delay(10); + * } + * } + * \endcode + */ +std::uint8_t read_buttons(void); + +///@} + +} // namespace lcd +} // namespace pros + + +#endif // _LIBLVGL_LLEMU_HPP_ diff --git a/include/liblvgl/lv_api_map.h b/include/liblvgl/lv_api_map.h new file mode 100644 index 0000000..c1b9e8d --- /dev/null +++ b/include/liblvgl/lv_api_map.h @@ -0,0 +1,88 @@ +/** + * @file lv_api_map.h + * + */ + +#ifndef LV_API_MAP_H +#define LV_API_MAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lvgl.h" + +/********************* + * DEFINES + *********************/ + +#define LV_NO_TASK_READY LV_NO_TIMER_READY +#define LV_INDEV_STATE_REL LV_INDEV_STATE_RELEASED +#define LV_INDEV_STATE_PR LV_INDEV_STATE_PRESSED +#define LV_OBJ_FLAG_SNAPABLE LV_OBJ_FLAG_SNAPPABLE /*Fixed typo*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +static inline LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_task_handler(void) +{ + return lv_timer_handler(); +} + +/********************** + * MACROS + **********************/ + + +/********************** + * INLINE FUNCTIONS + **********************/ + +/** + * Move the object to the foreground. + * It will look like if it was created as the last child of its parent. + * It also means it can cover any of the siblings. + * @param obj pointer to an object + */ +static inline void lv_obj_move_foreground(lv_obj_t * obj) +{ + lv_obj_t * parent = lv_obj_get_parent(obj); + lv_obj_move_to_index(obj, lv_obj_get_child_cnt(parent) - 1); +} + +/** + * Move the object to the background. + * It will look like if it was created as the first child of its parent. + * It also means any of the siblings can cover the object. + * @param obj pointer to an object + */ +static inline void lv_obj_move_background(lv_obj_t * obj) +{ + lv_obj_move_to_index(obj, 0); +} + + + +/********************** + * DEPRECATED FUNCTIONS + **********************/ + +static inline uint32_t lv_obj_get_child_id(const struct _lv_obj_t * obj) +{ + LV_LOG_WARN("lv_obj_get_child_id(obj) is deprecated, please use lv_obj_get_index(obj)."); + return lv_obj_get_index(obj); +} + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_API_MAP_H*/ diff --git a/include/liblvgl/lv_conf.h b/include/liblvgl/lv_conf.h new file mode 100644 index 0000000..bd93a55 --- /dev/null +++ b/include/liblvgl/lv_conf.h @@ -0,0 +1,779 @@ +/** + * @file lv_conf.h + * Configuration file for v7.11.0 + */ + +/* + * COPY THIS FILE AS `lv_conf.h` NEXT TO the `lvgl` FOLDER + */ + +#if 1 /*Set it to "1" to enable content*/ + +#ifndef LV_CONF_H +#define LV_CONF_H +/* clang-format off */ + +#include + +/*==================== + Graphical settings + *====================*/ + +/* Maximal horizontal and vertical resolution to support by the library.*/ +#define LV_HOR_RES_MAX (480) +#define LV_VER_RES_MAX (240) + +/* Color depth: + * - 1: 1 byte per pixel + * - 8: RGB332 + * - 16: RGB565 + * - 32: ARGB8888 + */ +#define LV_COLOR_DEPTH 32 + +/* Swap the 2 bytes of RGB565 color. + * Useful if the display has a 8 bit interface (e.g. SPI)*/ +#define LV_COLOR_16_SWAP 0 + +/* 1: Enable screen transparency. + * Useful for OSD or other overlapping GUIs. + * Requires `LV_COLOR_DEPTH = 32` colors and the screen's style should be modified: `style.body.opa = ...`*/ +#define LV_COLOR_SCREEN_TRANSP 0 + +/*Images pixels with this color will not be drawn (with chroma keying)*/ +#define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/ + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 + +/* Default display refresh period. + * Can be changed in the display driver (`lv_disp_drv_t`).*/ +#define LV_DISP_DEF_REFR_PERIOD 40 /*[ms]*/ + +/* Dot Per Inch: used to initialize default sizes. + * E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#define LV_DPI 126 /*[px]*/ + +/* The the real width of the display changes some default values: + * default object sizes, layout of examples, etc. + * According to the width of the display (hor. res. / dpi) + * the displays fall in 4 categories. + * The 4th is extra large which has no upper limit so not listed here + * The upper limit of the categories are set below in 0.1 inch unit. + */ +#define LV_DISP_SMALL_LIMIT 30 +#define LV_DISP_MEDIUM_LIMIT 50 +#define LV_DISP_LARGE_LIMIT 70 + +/* Type of coordinates. Should be `int16_t` (or `int32_t` for extreme cases) */ +typedef int16_t lv_coord_t; + +/* Maximum buffer size to allocate for rotation. Only used if software rotation is enabled. */ +#define LV_DISP_ROT_MAX_BUF (10U * 1024U) + +/*========================= + Memory manager settings + *=========================*/ + +/* LittelvGL's internal memory manager's settings. + * The graphical objects and other related data are stored here. */ + +/* 1: use custom malloc/free, 0: use the built-in `lv_mem_alloc` and `lv_mem_free` */ +#define LV_MEM_CUSTOM 0 +#if LV_MEM_CUSTOM == 0 +/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +# define LV_MEM_SIZE (32U * 1024U) + +/* Compiler prefix for a big array declaration */ +# define LV_MEM_ATTR + +/* Set an address for the memory pool instead of allocating it as an array. + * Can be in external SRAM too. */ +# define LV_MEM_ADR 0 + +/* Automatically defrag. on free. Defrag. means joining the adjacent free cells. */ +# define LV_MEM_AUTO_DEFRAG 1 +#else /*LV_MEM_CUSTOM*/ +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ + +/* Use the standard memcpy and memset instead of LVGL's own functions. + * The standard functions might or might not be faster depending on their implementation. */ +#define LV_MEMCPY_MEMSET_STD 0 + +/* Garbage Collector settings + * Used if lvgl is binded to higher level language and the memory is managed by that language */ +#define LV_ENABLE_GC 0 +#if LV_ENABLE_GC != 0 +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +#endif /* LV_ENABLE_GC */ + +/*======================= + Input device settings + *=======================*/ + +/* Input device default settings. + * Can be changed in the Input device driver (`lv_indev_drv_t`)*/ + +/* Input device read period in milliseconds */ +#define LV_INDEV_DEF_READ_PERIOD 50 + +/* Drag threshold in pixels */ +#define LV_INDEV_DEF_DRAG_LIMIT 10 + +/* Drag throw slow-down in [%]. Greater value -> faster slow-down */ +#define LV_INDEV_DEF_DRAG_THROW 20 + +/* Long press time in milliseconds. + * Time to send `LV_EVENT_LONG_PRESSED`) */ +#define LV_INDEV_DEF_LONG_PRESS_TIME 400 + +/* Repeated trigger period in long press [ms] + * Time between `LV_EVENT_LONG_PRESSED_REPEAT */ +#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100 + +/* Gesture threshold in pixels */ +#define LV_INDEV_DEF_GESTURE_LIMIT 50 + +/* Gesture min velocity at release before swipe (pixels)*/ +#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3 + +/*================== + * Feature usage + *==================*/ + +/*1: Enable the Animations */ +#define LV_USE_ANIMATION 1 +#if LV_USE_ANIMATION + +/*Declare the type of the user data of animations (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_anim_user_data_t; + +#endif + +/* 1: Enable shadow drawing on rectangles*/ +#define LV_USE_SHADOW 1 +#if LV_USE_SHADOW +/* Allow buffering some shadow calculation + * LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, + * where shadow size is `shadow_width + radius` + * Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/ +#define LV_SHADOW_CACHE_SIZE 0 +#endif + +/*1: enable outline drawing on rectangles*/ +#define LV_USE_OUTLINE 1 + +/*1: enable pattern drawing on rectangles*/ +#define LV_USE_PATTERN 1 + +/*1: enable value string drawing on rectangles*/ +#define LV_USE_VALUE_STR 1 + +/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/ +#define LV_USE_BLEND_MODES 1 + +/* 1: Use the `opa_scale` style property to set the opacity of an object and its children at once*/ +#define LV_USE_OPA_SCALE 1 + +/* 1: Use image zoom and rotation*/ +#define LV_USE_IMG_TRANSFORM 1 + +/* 1: Enable object groups (for keyboard/encoder navigation) */ +#define LV_USE_GROUP 1 +#if LV_USE_GROUP +typedef void * lv_group_user_data_t; +#endif /*LV_USE_GROUP*/ + +/* 1: Enable GPU interface*/ +#define LV_USE_GPU 0 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */ +#define LV_USE_GPU_STM32_DMA2D 0 +/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor +e.g. "stm32f769xx.h" or "stm32f429xx.h" */ +#define LV_GPU_DMA2D_CMSIS_INCLUDE + +/*1: Use PXP for CPU off-load on NXP RTxxx platforms */ +#define LV_USE_GPU_NXP_PXP 0 + +/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol FSL_RTOS_FREE_RTOS + * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + * */ +#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 + +/*1: Use VG-Lite for CPU offload on NXP RTxxx platforms */ +#define LV_USE_GPU_NXP_VG_LITE 0 + +/* 1: Enable file system (might be required for images */ +#define LV_USE_FILESYSTEM 1 +#if LV_USE_FILESYSTEM +/*Declare the type of the user data of file system drivers (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_fs_drv_user_data_t; +#endif + +/*1: Add a `user_data` to drivers and objects*/ +#define LV_USE_USER_DATA 1 + +/*1: Show CPU usage and FPS count in the right bottom corner*/ +#define LV_USE_PERF_MONITOR 0 + +/*1: Use the functions and types from the older API if possible */ +#define LV_USE_API_EXTENSION_V6 1 +#define LV_USE_API_EXTENSION_V7 1 + +/*======================== + * Image decoder and cache + *========================*/ + +/* 1: Enable indexed (palette) images */ +#define LV_IMG_CF_INDEXED 1 + +/* 1: Enable alpha indexed images */ +#define LV_IMG_CF_ALPHA 1 + +/* Default image cache size. Image caching keeps the images opened. + * If only the built-in image formats are used there is no real advantage of caching. + * (I.e. no new image decoder is added) + * With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. + * However the opened images might consume additional RAM. + * Set it to 0 to disable caching */ +#define LV_IMG_CACHE_DEF_SIZE 1 + +/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_img_decoder_user_data_t; + +/*===================== + * Compiler settings + *====================*/ + +/* For big endian systems set to 1 */ +#define LV_BIG_ENDIAN_SYSTEM 0 + +/* Define a custom attribute to `lv_tick_inc` function */ +#define LV_ATTRIBUTE_TICK_INC + +/* Define a custom attribute to `lv_task_handler` function */ +#define LV_ATTRIBUTE_TASK_HANDLER + +/* Define a custom attribute to `lv_disp_flush_ready` function */ +#define LV_ATTRIBUTE_FLUSH_READY + +/* Required alignment size for buffers */ +#define LV_ATTRIBUTE_MEM_ALIGN_SIZE + +/* With size optimization (-Os) the compiler might not align data to + * 4 or 8 byte boundary. Some HW may need even 32 or 64 bytes. + * This alignment will be explicitly applied where needed. + * LV_ATTRIBUTE_MEM_ALIGN_SIZE should be used to specify required align size. + * E.g. __attribute__((aligned(LV_ATTRIBUTE_MEM_ALIGN_SIZE))) */ +#define LV_ATTRIBUTE_MEM_ALIGN + +/* Attribute to mark large constant arrays for example + * font's bitmaps */ +#define LV_ATTRIBUTE_LARGE_CONST + +/* Prefix performance critical functions to place them into a faster memory (e.g RAM) + * Uses 15-20 kB extra memory */ +#define LV_ATTRIBUTE_FAST_MEM + +/* Export integer constant to binding. + * This macro is used with constants in the form of LV_ that + * should also appear on lvgl binding API such as Micropython + * + * The default value just prevents a GCC warning. + */ +#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning + +/* Prefix variables that are used in GPU accelerated operations, often these need to be + * placed in RAM sections that are DMA accessible */ +#define LV_ATTRIBUTE_DMA + +/*=================== + * HAL settings + *==================*/ + +/* 1: use a custom tick source. + * It removes the need to manually update the tick with `lv_tick_inc`) */ +#define LV_TICK_CUSTOM 0 +#if LV_TICK_CUSTOM == 1 +#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ +#endif /*LV_TICK_CUSTOM*/ + +typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/ +typedef void * lv_indev_drv_user_data_t; /*Type of user data in the input device driver*/ + +/*================ + * Log settings + *===============*/ + +/*1: Enable the log module*/ +#define LV_USE_LOG 0 +#if LV_USE_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + * LV_LOG_LEVEL_NONE Do not log anything + */ +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN + +/* 1: Print the log with 'printf'; + * 0: user need to register a callback with `lv_log_register_print_cb`*/ +# define LV_LOG_PRINTF 0 +#endif /*LV_USE_LOG*/ + +/*================= + * Debug settings + *================*/ + +/* If Debug is enabled LittelvGL validates the parameters of the functions. + * If an invalid parameter is found an error log message is printed and + * the MCU halts at the error. (`LV_USE_LOG` should be enabled) + * If you are debugging the MCU you can pause + * the debugger to see exactly where the issue is. + * + * The behavior of asserts can be overwritten by redefining them here. + * E.g. #define LV_ASSERT_MEM(p) + */ +#define LV_USE_DEBUG 1 +#if LV_USE_DEBUG + +/*Check if the parameter is NULL. (Quite fast) */ +#define LV_USE_ASSERT_NULL 1 + +/*Checks is the memory is successfully allocated or no. (Quite fast)*/ +#define LV_USE_ASSERT_MEM 1 + +/*Check the integrity of `lv_mem` after critical operations. (Slow)*/ +#define LV_USE_ASSERT_MEM_INTEGRITY 0 + +/* Check the strings. + * Search for NULL, very long strings, invalid characters, and unnatural repetitions. (Slow) + * If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */ +#define LV_USE_ASSERT_STR 0 + +/* Check NULL, the object's type and existence (e.g. not deleted). (Quite slow) + * If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */ +#define LV_USE_ASSERT_OBJ 0 + +/*Check if the styles are properly initialized. (Fast)*/ +#define LV_USE_ASSERT_STYLE 0 + +#endif /*LV_USE_DEBUG*/ + +/*================== + * FONT USAGE + *===================*/ + +/* The built-in fonts contains the ASCII range and some Symbols with 4 bit-per-pixel. + * The symbols are available via `LV_SYMBOL_...` defines + * More info about fonts: https://docs.lvgl.io/v7/en/html/overview/font.html + * To create a new font go to: https://lvgl.com/ttf-font-to-c-array + */ + +/* Montserrat fonts with bpp = 4 + * https://fonts.google.com/specimen/Montserrat */ +#define LV_FONT_MONTSERRAT_8 0 +#define LV_FONT_MONTSERRAT_10 1 +#define LV_FONT_MONTSERRAT_12 1 +#define LV_FONT_MONTSERRAT_14 1 +#define LV_FONT_MONTSERRAT_16 1 +#define LV_FONT_MONTSERRAT_18 1 +#define LV_FONT_MONTSERRAT_20 1 +#define LV_FONT_MONTSERRAT_22 0 +#define LV_FONT_MONTSERRAT_24 1 +#define LV_FONT_MONTSERRAT_26 0 +#define LV_FONT_MONTSERRAT_28 0 +#define LV_FONT_MONTSERRAT_30 1 +#define LV_FONT_MONTSERRAT_32 0 +#define LV_FONT_MONTSERRAT_34 0 +#define LV_FONT_MONTSERRAT_36 1 +#define LV_FONT_MONTSERRAT_38 0 +#define LV_FONT_MONTSERRAT_40 1 +#define LV_FONT_MONTSERRAT_42 1 +#define LV_FONT_MONTSERRAT_44 0 +#define LV_FONT_MONTSERRAT_46 0 +#define LV_FONT_MONTSERRAT_48 1 + +/* Demonstrate special features */ +#define LV_FONT_MONTSERRAT_12_SUBPX 0 +#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ +#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, PErisan letters and all their forms*/ +#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ + +/*Pixel perfect monospace font + * http://pelulamu.net/unscii/ */ +#define LV_FONT_UNSCII_8 1 +#define LV_FONT_UNSCII_16 1 + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) + */ +#define LV_FONT_CUSTOM_DECLARE + +/* Enable it if you have fonts with a lot of characters. + * The limit depends on the font size, font face and bpp + * but with > 10,000 characters if you see issues probably you need to enable it.*/ +#define LV_FONT_FMT_TXT_LARGE 0 + +/* Enables/disables support for compressed fonts. If it's disabled, compressed + * glyphs cannot be processed by the library and won't be rendered. + */ +#define LV_USE_FONT_COMPRESSED 1 + +/* Enable subpixel rendering */ +#define LV_USE_FONT_SUBPX 1 +#if LV_USE_FONT_SUBPX +/* Set the pixel order of the display. + * Important only if "subpx fonts" are used. + * With "normal" font it doesn't matter. + */ +#define LV_FONT_SUBPX_BGR 0 + +/* PROS adds the mono variant of DejaVu sans */ +#define USE_PROS_FONT_DEJAVU_MONO_10 1 + +#define USE_PROS_FONT_DEJAVU_MONO_18 1 // llemu font + +#define USE_PROS_FONT_DEJAVU_MONO_30 0 + +#define USE_PROS_FONT_DEJAVU_MONO_40 0 + +#endif + +/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_font_user_data_t; + +/*================ + * THEME USAGE + *================*/ + +/*Always enable at least on theme*/ + +/* No theme, you can apply your styles as you need + * No flags. Set LV_THEME_DEFAULT_FLAG 0 */ +#define LV_USE_THEME_EMPTY 1 + +/*Simple to the create your theme based on it + * No flags. Set LV_THEME_DEFAULT_FLAG 0 */ +#define LV_USE_THEME_TEMPLATE 1 + +/* A fast and impressive theme. + * Flags: + * LV_THEME_MATERIAL_FLAG_LIGHT: light theme + * LV_THEME_MATERIAL_FLAG_DARK: dark theme + * LV_THEME_MATERIAL_FLAG_NO_TRANSITION: disable transitions (state change animations) + * LV_THEME_MATERIAL_FLAG_NO_FOCUS: disable indication of focused state) + * */ +#define LV_USE_THEME_MATERIAL 1 + +/* Mono-color theme for monochrome displays. + * If LV_THEME_DEFAULT_COLOR_PRIMARY is LV_COLOR_BLACK the + * texts and borders will be black and the background will be + * white. Else the colors are inverted. + * No flags. Set LV_THEME_DEFAULT_FLAG 0 */ +#define LV_USE_THEME_MONO 1 + +#define LV_THEME_DEFAULT_INCLUDE /*Include a header for the init. function*/ +#define LV_THEME_DEFAULT_INIT lv_theme_material_init +#define LV_THEME_DEFAULT_COLOR_PRIMARY lv_color_hex(0x01a2b1) +#define LV_THEME_DEFAULT_COLOR_SECONDARY lv_color_hex(0x44d1b6) +#define LV_THEME_DEFAULT_FLAG LV_THEME_MATERIAL_FLAG_DARK +#define LV_THEME_DEFAULT_FONT_SMALL &lv_font_montserrat_10 +#define LV_THEME_DEFAULT_FONT_NORMAL &lv_font_montserrat_20 +#define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_10 +#define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_30 + +#define CONFIG_LV_THEME_DEFAULT_DARK 1 + +/*================= + * Text settings + *=================*/ + +/* Select a character encoding for strings. + * Your IDE or editor should have the same character encoding + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + * */ +#define LV_TXT_ENC LV_TXT_ENC_UTF8 + + /*Can break (wrap) texts on these chars*/ +#define LV_TXT_BREAK_CHARS " ,.;:-_" + +/* If a word is at least this long, will break wherever "prettiest" + * To disable, set to a value <= 0 */ +#define LV_TXT_LINE_BREAK_LONG_LEN 0 + +/* Minimum number of characters in a long word to put on a line before a break. + * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */ +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + +/* Minimum number of characters in a long word to put on a line after a break. + * Depends on LV_TXT_LINE_BREAK_LONG_LEN. */ +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + +/* The control character to use for signalling text recoloring. */ +#define LV_TXT_COLOR_CMD "#" + +/* Support bidirectional texts. + * Allows mixing Left-to-Right and Right-to-Left texts. + * The direction will be processed according to the Unicode Bidirectional Algorithm: + * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#define LV_USE_BIDI 0 +#if LV_USE_BIDI +/* Set the default direction. Supported values: + * `LV_BIDI_DIR_LTR` Left-to-Right + * `LV_BIDI_DIR_RTL` Right-to-Left + * `LV_BIDI_DIR_AUTO` detect texts base direction */ +#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO +#endif + +/* Enable Arabic/Persian processing + * In these languages characters should be replaced with + * an other form based on their position in the text */ +#define LV_USE_ARABIC_PERSIAN_CHARS 0 + +/*Change the built in (v)snprintf functions*/ +#define LV_SPRINTF_CUSTOM 0 +#if LV_SPRINTF_CUSTOM +# define LV_SPRINTF_INCLUDE +# define lv_snprintf snprintf +# define lv_vsnprintf vsnprintf +#else /*!LV_SPRINTF_CUSTOM*/ +# define LV_SPRINTF_DISABLE_FLOAT 1 +#endif /*LV_SPRINTF_CUSTOM*/ + +/*=================== + * LV_OBJ SETTINGS + *==================*/ + +#if LV_USE_USER_DATA +/*Declare the type of the user data of object (can be e.g. `void *`, `int`, `struct`)*/ +typedef void * lv_obj_user_data_t; +/*Provide a function to free user data*/ +#define LV_USE_USER_DATA_FREE 0 +#if LV_USE_USER_DATA_FREE +# define LV_USER_DATA_FREE_INCLUDE "something.h" /*Header for user data free function*/ +/* Function prototype : void user_data_free(lv_obj_t * obj); */ +# define LV_USER_DATA_FREE (user_data_free) /*Invoking for user data free function*/ +#endif +#endif + +/*1: enable `lv_obj_realign()` based on `lv_obj_align()` parameters*/ +#define LV_USE_OBJ_REALIGN 1 + +/* Enable to make the object clickable on a larger area. + * LV_EXT_CLICK_AREA_OFF or 0: Disable this feature + * LV_EXT_CLICK_AREA_TINY: The extra area can be adjusted horizontally and vertically (0..255 px) + * LV_EXT_CLICK_AREA_FULL: The extra area can be adjusted in all 4 directions (-32k..+32k px) + */ +#define LV_USE_EXT_CLICK_AREA LV_EXT_CLICK_AREA_TINY + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.lvgl.com/#Object-types + */ + +/*Arc (dependencies: -)*/ +#define LV_USE_ARC 1 + +/*Bar (dependencies: -)*/ +#define LV_USE_BAR 1 + +/*Button (dependencies: lv_cont*/ +#define LV_USE_BTN 1 + +/*Button matrix (dependencies: -)*/ +#define LV_USE_BTNMATRIX 1 + +/*Calendar (dependencies: -)*/ +#define LV_USE_CALENDAR 1 +#if LV_USE_CALENDAR +# define LV_CALENDAR_WEEK_STARTS_MONDAY 0 +#endif + +/*Canvas (dependencies: lv_img)*/ +#define LV_USE_CANVAS 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define LV_USE_CHECKBOX 1 + +/*Chart (dependencies: -)*/ +#define LV_USE_CHART 1 +#if LV_USE_CHART +# define LV_CHART_AXIS_TICK_LABEL_MAX_LEN 256 +#endif + +/*Container (dependencies: -*/ +#define LV_USE_CONT 1 + +/*Color picker (dependencies: -*/ +#define LV_USE_CPICKER 1 + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#define LV_USE_DROPDOWN 1 +#if LV_USE_DROPDOWN != 0 +/*Open and close default animation time [ms] (0: no animation)*/ +# define LV_DROPDOWN_DEF_ANIM_TIME 200 +#endif + +/*Gauge (dependencies:lv_bar, lv_linemeter)*/ +#define LV_USE_GAUGE 1 + +/*Image (dependencies: lv_label*/ +#define LV_USE_IMG 1 + +/*Image Button (dependencies: lv_btn*/ +#define LV_USE_IMGBTN 1 +#if LV_USE_IMGBTN +/*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +# define LV_IMGBTN_TILED 0 +#endif + +/*Keyboard (dependencies: lv_btnm)*/ +#define LV_USE_KEYBOARD 1 + +/*Label (dependencies: -*/ +#define LV_USE_LABEL 1 +#if LV_USE_LABEL != 0 +/*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_ROLL/ROLL_CIRC' mode*/ +# define LV_LABEL_DEF_SCROLL_SPEED 25 + +/* Waiting period at beginning/end of animation cycle */ +# define LV_LABEL_WAIT_CHAR_COUNT 3 + +/*Enable selecting text of the label */ +# define LV_LABEL_TEXT_SEL 0 + +/*Store extra some info in labels (12 bytes) to speed up drawing of very long texts*/ +# define LV_LABEL_LONG_TXT_HINT 0 +#endif + +/*LED (dependencies: -)*/ +#define LV_USE_LED 1 +#if LV_USE_LED +# define LV_LED_BRIGHT_MIN 120 /*Minimal brightness*/ +# define LV_LED_BRIGHT_MAX 255 /*Maximal brightness*/ +#endif + +/*Line (dependencies: -*/ +#define LV_USE_LINE 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#define LV_USE_LIST 1 +#if LV_USE_LIST != 0 +/*Default animation time of focusing to a list element [ms] (0: no animation) */ +# define LV_LIST_DEF_ANIM_TIME 100 +#endif + +/*Line meter (dependencies: *;)*/ +#define LV_USE_LINEMETER 1 +#if LV_USE_LINEMETER +/* Draw line more precisely at cost of performance. + * Useful if there are lot of lines any minor are visible + * 0: No extra precision + * 1: Some extra precision + * 2: Best precision + */ +# define LV_LINEMETER_PRECISE 1 +#endif + +/*Mask (dependencies: -)*/ +#define LV_USE_OBJMASK 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define LV_USE_MSGBOX 1 + +/*Page (dependencies: lv_cont)*/ +#define LV_USE_PAGE 1 +#if LV_USE_PAGE != 0 +/*Focus default animation time [ms] (0: no animation)*/ +# define LV_PAGE_DEF_ANIM_TIME 400 +#endif + +/*Preload (dependencies: lv_arc, lv_anim)*/ +#define LV_USE_SPINNER 1 +#if LV_USE_SPINNER != 0 +# define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/ +# define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/ +# define LV_SPINNER_DEF_ANIM LV_SPINNER_TYPE_SPINNING_ARC +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define LV_USE_ROLLER 1 +#if LV_USE_ROLLER != 0 +/*Focus animation time [ms] (0: no animation)*/ +# define LV_ROLLER_DEF_ANIM_TIME 200 + +/*Number of extra "pages" when the roller is infinite*/ +# define LV_ROLLER_INF_PAGES 7 +#endif + +/*Slider (dependencies: lv_bar)*/ +#define LV_USE_SLIDER 1 + +/*Spinbox (dependencies: lv_ta)*/ +#define LV_USE_SPINBOX 1 + +/*Switch (dependencies: lv_slider)*/ +#define LV_USE_SWITCH 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define LV_USE_TEXTAREA 1 +#if LV_USE_TEXTAREA != 0 +# define LV_TEXTAREA_DEF_CURSOR_BLINK_TIME 400 /*ms*/ +# define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +/*Table (dependencies: lv_label)*/ +#define LV_USE_TABLE 1 +#if LV_USE_TABLE +# define LV_TABLE_COL_MAX 12 +# define LV_TABLE_CELL_STYLE_CNT 4 +#endif + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define LV_USE_TABVIEW 1 +# if LV_USE_TABVIEW != 0 +/*Time of slide animation [ms] (0: no animation)*/ +# define LV_TABVIEW_DEF_ANIM_TIME 300 +#endif + +/*Tileview (dependencies: lv_page) */ +#define LV_USE_TILEVIEW 1 +#if LV_USE_TILEVIEW +/*Time of slide animation [ms] (0: no animation)*/ +# define LV_TILEVIEW_DEF_ANIM_TIME 300 +#endif + +#define CONFIG_LV_USE_GIF 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define LV_USE_WIN 1 + +/*================== + * Non-user section + *==================*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +# define _CRT_SECURE_NO_WARNINGS +#endif + +/*--END OF LV_CONF_H--*/ + +#endif /*LV_CONF_H*/ + +#endif /*End of "Content enable"*/ diff --git a/include/liblvgl/lv_conf.old.h b/include/liblvgl/lv_conf.old.h new file mode 100644 index 0000000..16deedd --- /dev/null +++ b/include/liblvgl/lv_conf.old.h @@ -0,0 +1,341 @@ +/** + * @file lv_conf.h + * + */ + +#ifndef LV_CONF_H +#define LV_CONF_H + +/*---------------- + * Dynamic memory + *----------------*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#define LV_MEM_CUSTOM \ + 0 /*1: use custom malloc/free, 0: use the built-in \ + lv_mem_alloc/lv_mem_free*/ +#if LV_MEM_CUSTOM == 0 +#define LV_MEM_SIZE \ + (32U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#else /*LV_MEM_CUSTOM*/ +#define LV_MEM_CUSTOM_INCLUDE \ + /*Header for the dynamic memory function*/ +#define LV_MEM_CUSTOM_ALLOC kmalloc /*Wrapper to malloc*/ +#define LV_MEM_CUSTOM_FREE kfree /*Wrapper to free*/ +#endif /*LV_MEM_CUSTOM*/ +#define LV_ENABLE_GC 0 + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#define LV_HOR_RES (480) +#define LV_VER_RES (240) +#define LV_DPI 126 + +/* Size of VDB (Virtual Display Buffer: the internal graphics buffer). + * Required for buffered drawing, opacity and anti-aliasing + * VDB makes the double buffering, you don't need to deal with it! + * Typical size: ~1/10 screen */ +#define LV_VDB_SIZE \ + (LV_VER_RES * \ + LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for \ + first)*/ +#define LV_VDB_ADR \ + 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing + * (optional) + * The flushing should use DMA to write the frame buffer in the background*/ +#define LV_VDB_DOUBLE 0 /*1: Enable the use of 2 VDBs*/ +#define LV_VDB2_ADR \ + 0 /*Place VDB2 to a specific address (e.g. in external RAM) (0: allocate \ + automatically into RAM)*/ + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ + +/*Screen refresh settings*/ +#define LV_REFR_PERIOD 40 /*Screen refresh period in milliseconds*/ +#define LV_INV_FIFO_SIZE 32 /*The average count of objects on a screen */ + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#define LV_INDEV_POINT_MARKER \ + 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#define LV_INDEV_DRAG_THROW \ + 20 /*Drag throw slow-down in [%]. Greater value means faster slow-down */ +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#define LV_INDEV_LONG_PRESS_REP_TIME \ + 100 /*Repeated trigger period in long press [ms] */ + +/*Color settings*/ +#define LV_COLOR_DEPTH 32 /*Color depth: 1/8/16/24*/ +#define LV_COLOR_TRANSP \ + LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma \ + keying)*/ + +/*Text settings*/ +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#define LV_TXT_LINE_BREAK_LONG_LEN 12 +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 + +/*Graphics feature usage*/ +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#define USE_LV_GPU 0 /*1: Enable GPU interface*/ +#define USE_LV_REAL_DRAW \ + 1 /*1: Enable function which draw directly to the frame buffer instead of \ + VDB (required if LV_VDB_SIZE = 0)*/ +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (required by images*/ +#define USE_LV_MULTI_LANG 1 + +/*Compiler attributes*/ +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to tick increment \ + function */ +#define LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_MEM_ALIGN +#define LV_COMPILER_VLA_SUPPORTED 1 +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 + +#define USE_LV_LOG 0 +/*================ + * THEME USAGE + *================*/ +#define LV_THEME_LIVE_UPDATE 1 +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#define USE_LV_THEME_DEFAULT 0 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://littlevgl.com/basics#fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel */ +#define LV_FONT_DEFAULT \ + &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ + +#define USE_LV_FONT_DEJAVU_10 4 +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_10 4 + +#define USE_LV_FONT_DEJAVU_20 4 +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#define USE_LV_FONT_SYMBOL_20 4 + +#define USE_LV_FONT_DEJAVU_30 0 +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_30 0 + +#define USE_LV_FONT_DEJAVU_40 0 +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 0 +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 0 +#define USE_LV_FONT_SYMBOL_40 0 + +/* PROS adds the mono variant of DejaVu sans */ +#define USE_PROS_FONT_DEJAVU_MONO_10 4 +#define USE_PROS_FONT_DEJAVU_MONO_10_LATIN_SUP 4 + +#define USE_PROS_FONT_DEJAVU_MONO_20 4 +#define USE_PROS_FONT_DEJAVU_MONO_LATIN_SUP_20 4 + +#define USE_PROS_FONT_DEJAVU_MONO_30 0 +#define USE_PROS_FONT_DEJAVU_MONO_30_LATIN_SUP 0 + +#define USE_PROS_FONT_DEJAVU_MONO_40 0 +#define USE_PROS_FONT_DEJAVU_MONO_40_LATIN_SUP 0 + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#define LV_OBJ_FREE_NUM_TYPE \ + uint32_t /*Type of free number attribute (comment out disable free number)*/ +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://littlevgl.com/object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#define USE_LV_LABEL 1 +#if USE_LV_LABEL != 0 +#define LV_LABEL_SCROLL_SPEED \ + 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' \ + mode*/ +#endif + +/*Image (dependencies: lv_label*/ +#define USE_LV_IMG 1 +#if USE_LV_IMG != 0 +# define LV_IMG_CF_INDEXED 1 +# define LV_IMG_CF_ALPHA 1 +#endif + +/*Line (dependencies: -*/ +#define USE_LV_LINE 1 +#define USE_LV_ARC 1 + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#define USE_LV_CONT 1 + +/*Page (dependencies: lv_cont)*/ +#define USE_LV_PAGE 1 + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#define USE_LV_WIN 1 + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#define USE_LV_TABVIEW 1 +#if USE_LV_TABVIEW != 0 +#define LV_TABVIEW_ANIM_TIME \ + 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#define USE_LV_TILEVIEW 1 +#if USE_LV_TILEVIEW +# define LV_TILEVIEW_ANIM_TIME 300 +#endif + + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#define USE_LV_BAR 1 + +/*Line meter (dependencies: *;)*/ +#define USE_LV_LMETER 1 + +/*Gauge (dependencies:bar, lmeter)*/ +#define USE_LV_GAUGE 1 + +/*Chart (dependencies: -)*/ +#define USE_LV_CHART 1 + +#define USE_LV_TABLE 1 +#if USE_LV_TABLE +# define LV_TABLE_COL_MAX 12 +#endif + +/*LED (dependencies: -)*/ +#define USE_LV_LED 1 + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#define USE_LV_MBOX 1 + +/*Text area (dependencies: lv_label, lv_page)*/ +#define USE_LV_TA 1 +#if USE_LV_TA != 0 +#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif + +#define USE_LV_SPINBOX 1 +#define USE_LV_CALENDAR 1 + +#define USE_PRELOAD 1 +#if USE_LV_PRELOAD != 0 +# define LV_PRELOAD_DEF_ARC_LENGTH 60 +# define LV_PRELOAD_DEF_SPIN_TIME 1000 +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif + +#define USE_LV_CANVAS 1 +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#define USE_LV_BTN 1 +#if USE_LV_BTN != 0 +# define LV_BTN_INK_EFFECT 1 +#endif + +#define USE_LV_IMGBTN 1 +#if USE_LV_IMGBTN +# define LV_IMGBTN_TILED 0 +#endif + +/*Button matrix (dependencies: -)*/ +#define USE_LV_BTNM 1 + +/*Keyboard (dependencies: lv_btnm)*/ +#define USE_LV_KB 1 + +/*Check box (dependencies: lv_btn, lv_label)*/ +#define USE_LV_CB 1 + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons + * ))*/ +#define USE_LV_LIST 1 +#if USE_LV_LIST != 0 +#define LV_LIST_FOCUS_TIME \ + 100 /*Default animation time of focusing to a list element [ms] (0: no \ + animation) */ +#endif + +/*Drop down list (dependencies: lv_page, lv_label)*/ +#define USE_LV_DDLIST 1 +#if USE_LV_DDLIST != 0 +#define LV_DDLIST_ANIM_TIME \ + 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#define USE_LV_ROLLER 1 +#if USE_LV_ROLLER != 0 +#define LV_ROLLER_ANIM_TIME \ + 200 /*Focus animation time [ms] (0: no \ + animation)*/ +#endif + +/*Slider (dependencies: lv_bar)*/ +#define USE_LV_SLIDER 1 + +/*Switch (dependencies: lv_slider)*/ +#define USE_LV_SW 1 + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +#endif +#include "liblvgl/lv_conf_checker.h" +#endif /*LV_CONF_H*/ diff --git a/include/liblvgl/lv_conf_checker.h b/include/liblvgl/lv_conf_checker.h new file mode 100644 index 0000000..3a8ead5 --- /dev/null +++ b/include/liblvgl/lv_conf_checker.h @@ -0,0 +1,664 @@ +/** + * GENERATED FILE, DO NOT EDIT IT! + * @file lv_conf_checker.h + * Make sure all the defines of lv_conf.h have a default value +**/ + +#ifndef LV_CONF_CHECKER_H +#define LV_CONF_CHECKER_H +/*=================== + Dynamic memory + *===================*/ + +/* Memory size which will be used by the library + * to store the graphical objects and other data */ +#ifndef LV_MEM_CUSTOM +#define LV_MEM_CUSTOM 0 /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/ +#endif +#if LV_MEM_CUSTOM == 0 +#ifndef LV_MEM_SIZE +# define LV_MEM_SIZE (64U * 1024U) /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ +#endif +#ifndef LV_MEM_ATTR +# define LV_MEM_ATTR /*Complier prefix for big array declaration*/ +#endif +#ifndef LV_MEM_ADR +# define LV_MEM_ADR 0 /*Set an address for memory pool instead of allocation it as an array. Can be in external SRAM too.*/ +#endif +#ifndef LV_MEM_AUTO_DEFRAG +# define LV_MEM_AUTO_DEFRAG 1 /*Automatically defrag on free*/ +#endif +#else /*LV_MEM_CUSTOM*/ +#ifndef LV_MEM_CUSTOM_INCLUDE +# define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ +#endif +#ifndef LV_MEM_CUSTOM_ALLOC +# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/ +#endif +#ifndef LV_MEM_CUSTOM_FREE +# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/ +#endif +#endif /*LV_MEM_CUSTOM*/ + +/* Garbage Collector settings + * Used if lvgl is binded to higher language and the memory is managed by that language */ +#ifndef LV_ENABLE_GC +#define LV_ENABLE_GC 0 +#endif +#if LV_ENABLE_GC != 0 +#ifndef LV_MEM_CUSTOM_REALLOC +# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/ +#endif +#ifndef LV_MEM_CUSTOM_GET_SIZE +# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/ +#endif +#ifndef LV_GC_INCLUDE +# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ +#endif +#endif /* LV_ENABLE_GC */ + +/*=================== + Graphical settings + *===================*/ + +/* Horizontal and vertical resolution of the library.*/ +#ifndef LV_HOR_RES +#define LV_HOR_RES (480) +#endif +#ifndef LV_VER_RES +#define LV_VER_RES (320) +#endif + +/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide + * (Not so important, you can adjust it to modify default sizes and spaces)*/ +#ifndef LV_DPI +#define LV_DPI 100 +#endif + +/* Enable anti-aliasing (lines, and radiuses will be smoothed) */ +#ifndef LV_ANTIALIAS +#define LV_ANTIALIAS 1 /*1: Enable anti-aliasing*/ +#endif + +/*Screen refresh period in milliseconds*/ +#ifndef LV_REFR_PERIOD +#define LV_REFR_PERIOD 30 +#endif + +/*----------------- + * VDB settings + *----------------*/ + +/* VDB (Virtual Display Buffer) is an internal graphics buffer. + * The GUI will be drawn into this buffer first and then + * the buffer will be passed to your `disp_drv.disp_flush` function to + * copy it to your frame buffer. + * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows + * Learn more: https://docs.littlevgl.com/#Drawing*/ + +/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES + * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions + * will be called to draw to the frame buffer directly*/ +#ifndef LV_VDB_SIZE +#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES) / 10) +#endif + + /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. + * Special formats are handled with `disp_drv.vdb_wr`)*/ +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */ +#endif + + /* Place VDB to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB_ADR +#define LV_VDB_ADR 0 +#endif + +/* Use two Virtual Display buffers (VDB) to parallelize rendering and flushing + * The flushing should use DMA to write the frame buffer in the background */ +#ifndef LV_VDB_DOUBLE +#define LV_VDB_DOUBLE 0 +#endif + +/* Place VDB2 to a specific address (e.g. in external RAM) + * 0: allocate automatically into RAM + * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/ +#ifndef LV_VDB2_ADR +#define LV_VDB2_ADR 0 +#endif + +/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen. + * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display. + * The best if you do in the blank period of you display to avoid tearing effect. + * Requires: + * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES + * - LV_VDB_DOUBLE = 1 + */ +#ifndef LV_VDB_TRUE_DOUBLE_BUFFERED +#define LV_VDB_TRUE_DOUBLE_BUFFERED 0 +#endif + +/*================= + Misc. setting + *=================*/ + +/*Input device settings*/ +#ifndef LV_INDEV_READ_PERIOD +#define LV_INDEV_READ_PERIOD 50 /*Input device read period in milliseconds*/ +#endif +#ifndef LV_INDEV_POINT_MARKER +#define LV_INDEV_POINT_MARKER 0 /*Mark the pressed points (required: USE_LV_REAL_DRAW = 1)*/ +#endif +#ifndef LV_INDEV_DRAG_LIMIT +#define LV_INDEV_DRAG_LIMIT 10 /*Drag threshold in pixels */ +#endif +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 20 /*Drag throw slow-down in [%] (must be > 0). Greater value means faster slow-down */ +#endif +#ifndef LV_INDEV_LONG_PRESS_TIME +#define LV_INDEV_LONG_PRESS_TIME 400 /*Long press time in milliseconds*/ +#endif +#ifndef LV_INDEV_LONG_PRESS_REP_TIME +#define LV_INDEV_LONG_PRESS_REP_TIME 100 /*Repeated trigger period in long press [ms] */ +#endif + +/*Color settings*/ +#ifndef LV_COLOR_DEPTH +#define LV_COLOR_DEPTH 16 /*Color depth: 1/8/16/32*/ +#endif +#ifndef LV_COLOR_16_SWAP +#define LV_COLOR_16_SWAP 0 /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/ +#endif +#ifndef LV_COLOR_SCREEN_TRANSP +#define LV_COLOR_SCREEN_TRANSP 0 /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/ +#endif +#ifndef LV_COLOR_TRANSP +#define LV_COLOR_TRANSP LV_COLOR_LIME /*Images pixels with this color will not be drawn (with chroma keying)*/ +#endif + +/*Text settings*/ +#ifndef LV_TXT_UTF8 +#define LV_TXT_UTF8 1 /*Enable UTF-8 coded Unicode character usage */ +#endif +#ifndef LV_TXT_BREAK_CHARS +#define LV_TXT_BREAK_CHARS " ,.;:-_" /*Can break texts on these chars*/ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_LEN +#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */ +#endif +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN +#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */ +#endif + +/*Feature usage*/ +#ifndef USE_LV_ANIMATION +#define USE_LV_ANIMATION 1 /*1: Enable all animations*/ +#endif +#ifndef USE_LV_SHADOW +#define USE_LV_SHADOW 1 /*1: Enable shadows*/ +#endif +#ifndef USE_LV_GROUP +#define USE_LV_GROUP 1 /*1: Enable object groups (for keyboards)*/ +#endif +#ifndef USE_LV_GPU +#define USE_LV_GPU 1 /*1: Enable GPU interface*/ +#endif +#ifndef USE_LV_REAL_DRAW +#define USE_LV_REAL_DRAW 1 /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/ +#endif +#ifndef USE_LV_FILESYSTEM +#define USE_LV_FILESYSTEM 1 /*1: Enable file system (might be required for images*/ +#endif +#ifndef USE_LV_MULTI_LANG +#define USE_LV_MULTI_LANG 0 /* Number of languages for labels to store (0: to disable this feature)*/ +#endif + +/*Compiler settings*/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC /* Define a custom attribute to `lv_tick_inc` function */ +#endif +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER /* Define a custom attribute to `lv_task_handler` function */ +#endif +#ifndef LV_ATTRIBUTE_MEM_ALIGN +#define LV_ATTRIBUTE_MEM_ALIGN /* With size optimization (-Os) the compiler might not align data to 4 or 8 byte boundary. This alignment will be explicitly applied where needed.*/ +#endif +#ifndef LV_COMPILER_VLA_SUPPORTED +#define LV_COMPILER_VLA_SUPPORTED 1 /* 1: Variable length array is supported*/ +#endif +#ifndef LV_COMPILER_NON_CONST_INIT_SUPPORTED +#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1 /* 1: Initialization with non constant values are supported */ +#endif + +/*HAL settings*/ +#ifndef LV_TICK_CUSTOM +#define LV_TICK_CUSTOM 0 /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */ +#endif +#if LV_TICK_CUSTOM == 1 +#ifndef LV_TICK_CUSTOM_INCLUDE +#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/ +#endif +#ifndef LV_TICK_CUSTOM_SYS_TIME_EXPR +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/ +#endif +#endif /*LV_TICK_CUSTOM*/ + + +/*Log settings*/ +#ifndef USE_LV_LOG +#define USE_LV_LOG 1 /*Enable/disable the log module*/ +#endif +#if USE_LV_LOG +/* How important log should be added: + * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + * LV_LOG_LEVEL_INFO Log important events + * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't caused problem + * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + */ +#ifndef LV_LOG_LEVEL +# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN +#endif +/* 1: Print the log with 'printf'; 0: user need to register a callback*/ + +#ifndef LV_LOG_PRINTF +# define LV_LOG_PRINTF 0 +#endif +#endif /*USE_LV_LOG*/ + +/*================ + * THEME USAGE + *================*/ +#ifndef LV_THEME_LIVE_UPDATE +#define LV_THEME_LIVE_UPDATE 1 /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/ +#endif + +#ifndef USE_LV_THEME_TEMPL +#define USE_LV_THEME_TEMPL 0 /*Just for test*/ +#endif +#ifndef USE_LV_THEME_DEFAULT +#define USE_LV_THEME_DEFAULT 1 /*Built mainly from the built-in styles. Consumes very few RAM*/ +#endif +#ifndef USE_LV_THEME_ALIEN +#define USE_LV_THEME_ALIEN 1 /*Dark futuristic theme*/ +#endif +#ifndef USE_LV_THEME_NIGHT +#define USE_LV_THEME_NIGHT 1 /*Dark elegant theme*/ +#endif +#ifndef USE_LV_THEME_MONO +#define USE_LV_THEME_MONO 1 /*Mono color theme for monochrome displays*/ +#endif +#ifndef USE_LV_THEME_MATERIAL +#define USE_LV_THEME_MATERIAL 1 /*Flat theme with bold colors and light shadows*/ +#endif +#ifndef USE_LV_THEME_ZEN +#define USE_LV_THEME_ZEN 1 /*Peaceful, mainly light theme */ +#endif +#ifndef USE_LV_THEME_NEMO +#define USE_LV_THEME_NEMO 1 /*Water-like theme based on the movie "Finding Nemo"*/ +#endif + +/*================== + * FONT USAGE + *===================*/ + +/* More info about fonts: https://docs.littlevgl.com/#Fonts + * To enable a built-in font use 1,2,4 or 8 values + * which will determine the bit-per-pixel. Higher value means smoother fonts */ +#ifndef USE_LV_FONT_DEJAVU_10 +#define USE_LV_FONT_DEJAVU_10 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_LATIN_SUP +#define USE_LV_FONT_DEJAVU_10_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_10_CYRILLIC +#define USE_LV_FONT_DEJAVU_10_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_10 +#define USE_LV_FONT_SYMBOL_10 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_20 +#define USE_LV_FONT_DEJAVU_20 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_LATIN_SUP +#define USE_LV_FONT_DEJAVU_20_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_20_CYRILLIC +#define USE_LV_FONT_DEJAVU_20_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_20 +#define USE_LV_FONT_SYMBOL_20 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_30 +#define USE_LV_FONT_DEJAVU_30 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_LATIN_SUP +#define USE_LV_FONT_DEJAVU_30_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_30_CYRILLIC +#define USE_LV_FONT_DEJAVU_30_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_30 +#define USE_LV_FONT_SYMBOL_30 4 +#endif + +#ifndef USE_LV_FONT_DEJAVU_40 +#define USE_LV_FONT_DEJAVU_40 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_LATIN_SUP +#define USE_LV_FONT_DEJAVU_40_LATIN_SUP 4 +#endif +#ifndef USE_LV_FONT_DEJAVU_40_CYRILLIC +#define USE_LV_FONT_DEJAVU_40_CYRILLIC 4 +#endif +#ifndef USE_LV_FONT_SYMBOL_40 +#define USE_LV_FONT_SYMBOL_40 4 +#endif + +#ifndef USE_LV_FONT_MONOSPACE_8 +#define USE_LV_FONT_MONOSPACE_8 1 +#endif + +/* Optionally declare your custom fonts here. + * You can use these fonts as default font too + * and they will be available globally. E.g. + * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \ + * LV_FONT_DECLARE(my_font_2) \ + */ +#ifndef LV_FONT_CUSTOM_DECLARE +#define LV_FONT_CUSTOM_DECLARE +#endif + + +#ifndef LV_FONT_DEFAULT +#define LV_FONT_DEFAULT &lv_font_dejavu_20 /*Always set a default font from the built-in fonts*/ +#endif + +/*=================== + * LV_OBJ SETTINGS + *==================*/ +#ifndef LV_OBJ_FREE_NUM_TYPE +#define LV_OBJ_FREE_NUM_TYPE uint32_t /*Type of free number attribute (comment out disable free number)*/ +#endif +#ifndef LV_OBJ_FREE_PTR +#define LV_OBJ_FREE_PTR 1 /*Enable the free pointer attribute*/ +#endif +#ifndef LV_OBJ_REALIGN +#define LV_OBJ_REALIGN 1 /*Enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/ +#endif + +/*================== + * LV OBJ X USAGE + *================*/ +/* + * Documentation of the object types: https://docs.littlevgl.com/#Object-types + */ + +/***************** + * Simple object + *****************/ + +/*Label (dependencies: -*/ +#ifndef USE_LV_LABEL +#define USE_LV_LABEL 1 +#endif +#if USE_LV_LABEL != 0 +#ifndef LV_LABEL_SCROLL_SPEED +# define LV_LABEL_SCROLL_SPEED 25 /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/ +#endif +#endif + +/*Image (dependencies: lv_label*/ +#ifndef USE_LV_IMG +#define USE_LV_IMG 1 +#endif +#if USE_LV_IMG != 0 +#ifndef LV_IMG_CF_INDEXED +# define LV_IMG_CF_INDEXED 1 /*Enable indexed (palette) images*/ +#endif +#ifndef LV_IMG_CF_ALPHA +# define LV_IMG_CF_ALPHA 1 /*Enable alpha indexed images*/ +#endif +#endif + +/*Line (dependencies: -*/ +#ifndef USE_LV_LINE +#define USE_LV_LINE 1 +#endif + +/*Arc (dependencies: -)*/ +#ifndef USE_LV_ARC +#define USE_LV_ARC 1 +#endif + +/******************* + * Container objects + *******************/ + +/*Container (dependencies: -*/ +#ifndef USE_LV_CONT +#define USE_LV_CONT 1 +#endif + +/*Page (dependencies: lv_cont)*/ +#ifndef USE_LV_PAGE +#define USE_LV_PAGE 1 +#endif + +/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ +#ifndef USE_LV_WIN +#define USE_LV_WIN 1 +#endif + +/*Tab (dependencies: lv_page, lv_btnm)*/ +#ifndef USE_LV_TABVIEW +#define USE_LV_TABVIEW 1 +#endif +# if USE_LV_TABVIEW != 0 +#ifndef LV_TABVIEW_ANIM_TIME +# define LV_TABVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/*Tileview (dependencies: lv_page) */ +#ifndef USE_LV_TILEVIEW +#define USE_LV_TILEVIEW 1 +#endif +#if USE_LV_TILEVIEW +#ifndef LV_TILEVIEW_ANIM_TIME +# define LV_TILEVIEW_ANIM_TIME 300 /*Time of slide animation [ms] (0: no animation)*/ +#endif +#endif + +/************************* + * Data visualizer objects + *************************/ + +/*Bar (dependencies: -)*/ +#ifndef USE_LV_BAR +#define USE_LV_BAR 1 +#endif + +/*Line meter (dependencies: *;)*/ +#ifndef USE_LV_LMETER +#define USE_LV_LMETER 1 +#endif + +/*Gauge (dependencies:lv_bar, lv_lmeter)*/ +#ifndef USE_LV_GAUGE +#define USE_LV_GAUGE 1 +#endif + +/*Chart (dependencies: -)*/ +#ifndef USE_LV_CHART +#define USE_LV_CHART 1 +#endif + +/*Table (dependencies: lv_label)*/ +#ifndef USE_LV_TABLE +#define USE_LV_TABLE 1 +#endif +#if USE_LV_TABLE +#ifndef LV_TABLE_COL_MAX +# define LV_TABLE_COL_MAX 12 +#endif +#endif + +/*LED (dependencies: -)*/ +#ifndef USE_LV_LED +#define USE_LV_LED 1 +#endif + +/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ +#ifndef USE_LV_MBOX +#define USE_LV_MBOX 1 +#endif + +/*Text area (dependencies: lv_label, lv_page)*/ +#ifndef USE_LV_TA +#define USE_LV_TA 1 +#endif +#if USE_LV_TA != 0 +#ifndef LV_TA_CURSOR_BLINK_TIME +# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/ +#endif +#ifndef LV_TA_PWD_SHOW_TIME +# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/ +#endif +#endif + +/*Spinbox (dependencies: lv_ta)*/ +#ifndef USE_LV_SPINBOX +#define USE_LV_SPINBOX 1 +#endif + +/*Calendar (dependencies: -)*/ +#ifndef USE_LV_CALENDAR +#define USE_LV_CALENDAR 1 +#endif + +/*Preload (dependencies: lv_arc)*/ +#ifndef USE_LV_PRELOAD +#define USE_LV_PRELOAD 1 +#endif +#if USE_LV_PRELOAD != 0 +#ifndef LV_PRELOAD_DEF_ARC_LENGTH +# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ +#endif +#ifndef LV_PRELOAD_DEF_SPIN_TIME +# define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#endif +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC +#endif +#endif + +/*Canvas (dependencies: lv_img)*/ +#ifndef USE_LV_CANVAS +#define USE_LV_CANVAS 1 +#endif +/************************* + * User input objects + *************************/ + +/*Button (dependencies: lv_cont*/ +#ifndef USE_LV_BTN +#define USE_LV_BTN 1 +#endif +#if USE_LV_BTN != 0 +#ifndef LV_BTN_INK_EFFECT +# define LV_BTN_INK_EFFECT 1 /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/ +#endif +#endif + +/*Image Button (dependencies: lv_btn*/ +#ifndef USE_LV_IMGBTN +#define USE_LV_IMGBTN 1 +#endif +#if USE_LV_IMGBTN +#ifndef LV_IMGBTN_TILED +# define LV_IMGBTN_TILED 0 /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/ +#endif +#endif + +/*Button matrix (dependencies: -)*/ +#ifndef USE_LV_BTNM +#define USE_LV_BTNM 1 +#endif + +/*Keyboard (dependencies: lv_btnm)*/ +#ifndef USE_LV_KB +#define USE_LV_KB 1 +#endif + +/*Check box (dependencies: lv_btn, lv_label)*/ +#ifndef USE_LV_CB +#define USE_LV_CB 1 +#endif + +/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ +#ifndef USE_LV_LIST +#define USE_LV_LIST 1 +#endif +#if USE_LV_LIST != 0 +#ifndef LV_LIST_FOCUS_TIME +# define LV_LIST_FOCUS_TIME 100 /*Default animation time of focusing to a list element [ms] (0: no animation) */ +#endif +#endif + +/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ +#ifndef USE_LV_DDLIST +#define USE_LV_DDLIST 1 +#endif +#if USE_LV_DDLIST != 0 +#ifndef LV_DDLIST_ANIM_TIME +# define LV_DDLIST_ANIM_TIME 200 /*Open and close default animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Roller (dependencies: lv_ddlist)*/ +#ifndef USE_LV_ROLLER +#define USE_LV_ROLLER 1 +#endif +#if USE_LV_ROLLER != 0 +#ifndef LV_ROLLER_ANIM_TIME +# define LV_ROLLER_ANIM_TIME 200 /*Focus animation time [ms] (0: no animation)*/ +#endif +#endif + +/*Slider (dependencies: lv_bar)*/ +#ifndef USE_LV_SLIDER +#define USE_LV_SLIDER 1 +#endif + +/*Switch (dependencies: lv_slider)*/ +#ifndef USE_LV_SW +#define USE_LV_SW 1 +#endif + +/************************* + * Non-user section + *************************/ + +#if LV_INDEV_DRAG_THROW <= 0 +#warning "LV_INDEV_DRAG_THROW must be greater than 0" +#undef LV_INDEV_DRAG_THROW +#ifndef LV_INDEV_DRAG_THROW +#define LV_INDEV_DRAG_THROW 1 +#endif +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/ +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif +#endif + + +#endif /*LV_CONF_CHECKER_H*/ diff --git a/include/liblvgl/lv_conf_internal.h b/include/liblvgl/lv_conf_internal.h new file mode 100644 index 0000000..97807fe --- /dev/null +++ b/include/liblvgl/lv_conf_internal.h @@ -0,0 +1,2469 @@ +/** + * GENERATED FILE, DO NOT EDIT IT! + * @file lv_conf_internal.h + * Make sure all the defines of lv_conf.h have a default value +**/ + +#ifndef LV_CONF_INTERNAL_H +#define LV_CONF_INTERNAL_H +/* clang-format off */ + +#include + +/* Handle special Kconfig options */ +#ifndef LV_KCONFIG_IGNORE + #include "lv_conf_kconfig.h" + #ifdef CONFIG_LV_CONF_SKIP + #define LV_CONF_SKIP + #endif +#endif + +/*If "lv_conf.h" is available from here try to use it later.*/ +#ifdef __has_include + #if __has_include("lv_conf.h") + #ifndef LV_CONF_INCLUDE_SIMPLE + #define LV_CONF_INCLUDE_SIMPLE + #endif + #endif +#endif + +/*If lv_conf.h is not skipped include it*/ +#ifndef LV_CONF_SKIP + #ifdef LV_CONF_PATH /*If there is a path defined for lv_conf.h use it*/ + #define __LV_TO_STR_AUX(x) #x + #define __LV_TO_STR(x) __LV_TO_STR_AUX(x) + #include __LV_TO_STR(LV_CONF_PATH) + #undef __LV_TO_STR_AUX + #undef __LV_TO_STR + #elif defined(LV_CONF_INCLUDE_SIMPLE) /*Or simply include lv_conf.h is enabled*/ + #include "lv_conf.h" + #else + #include "../../lv_conf.h" /*Else assume lv_conf.h is next to the lvgl folder*/ + #endif + #if !defined(LV_CONF_H) && !defined(LV_CONF_SUPPRESS_DEFINE_CHECK) + /* #include will sometimes silently fail when __has_include is used */ + /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80753 */ + #pragma message("Possible failure to include lv_conf.h, please read the comment in this file if you get errors") + #endif +#endif + +#ifdef CONFIG_LV_COLOR_DEPTH + #define _LV_KCONFIG_PRESENT +#endif + +/*---------------------------------- + * Start parsing lv_conf_template.h + -----------------------------------*/ + +#include + +/*==================== + COLOR SETTINGS + *====================*/ + +/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/ +#ifndef LV_COLOR_DEPTH + #ifdef CONFIG_LV_COLOR_DEPTH + #define LV_COLOR_DEPTH CONFIG_LV_COLOR_DEPTH + #else + #define LV_COLOR_DEPTH 16 + #endif +#endif + +/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/ +#ifndef LV_COLOR_16_SWAP + #ifdef CONFIG_LV_COLOR_16_SWAP + #define LV_COLOR_16_SWAP CONFIG_LV_COLOR_16_SWAP + #else + #define LV_COLOR_16_SWAP 0 + #endif +#endif + +/*Enable features to draw on transparent background. + *It's required if opa, and transform_* style properties are used. + *Can be also used if the UI is above another layer, e.g. an OSD menu or video player.*/ +#ifndef LV_COLOR_SCREEN_TRANSP + #ifdef CONFIG_LV_COLOR_SCREEN_TRANSP + #define LV_COLOR_SCREEN_TRANSP CONFIG_LV_COLOR_SCREEN_TRANSP + #else + #define LV_COLOR_SCREEN_TRANSP 0 + #endif +#endif + +/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently. + * 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */ +#ifndef LV_COLOR_MIX_ROUND_OFS + #ifdef CONFIG_LV_COLOR_MIX_ROUND_OFS + #define LV_COLOR_MIX_ROUND_OFS CONFIG_LV_COLOR_MIX_ROUND_OFS + #else + #define LV_COLOR_MIX_ROUND_OFS 0 + #endif +#endif + +/*Images pixels with this color will not be drawn if they are chroma keyed)*/ +#ifndef LV_COLOR_CHROMA_KEY + #ifdef CONFIG_LV_COLOR_CHROMA_KEY + #define LV_COLOR_CHROMA_KEY CONFIG_LV_COLOR_CHROMA_KEY + #else + #define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/ + #endif +#endif + +/*========================= + MEMORY SETTINGS + *=========================*/ + +/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/ +#ifndef LV_MEM_CUSTOM + #ifdef CONFIG_LV_MEM_CUSTOM + #define LV_MEM_CUSTOM CONFIG_LV_MEM_CUSTOM + #else + #define LV_MEM_CUSTOM 0 + #endif +#endif +#if LV_MEM_CUSTOM == 0 + /*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/ + #ifndef LV_MEM_SIZE + #ifdef CONFIG_LV_MEM_SIZE + #define LV_MEM_SIZE CONFIG_LV_MEM_SIZE + #else + #define LV_MEM_SIZE (48U * 1024U) /*[bytes]*/ + #endif + #endif + + /*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/ + #ifndef LV_MEM_ADR + #ifdef CONFIG_LV_MEM_ADR + #define LV_MEM_ADR CONFIG_LV_MEM_ADR + #else + #define LV_MEM_ADR 0 /*0: unused*/ + #endif + #endif + /*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/ + #if LV_MEM_ADR == 0 + #ifndef LV_MEM_POOL_INCLUDE + #ifdef CONFIG_LV_MEM_POOL_INCLUDE + #define LV_MEM_POOL_INCLUDE CONFIG_LV_MEM_POOL_INCLUDE + #else + #undef LV_MEM_POOL_INCLUDE + #endif + #endif + #ifndef LV_MEM_POOL_ALLOC + #ifdef CONFIG_LV_MEM_POOL_ALLOC + #define LV_MEM_POOL_ALLOC CONFIG_LV_MEM_POOL_ALLOC + #else + #undef LV_MEM_POOL_ALLOC + #endif + #endif + #endif + +#else /*LV_MEM_CUSTOM*/ + #ifndef LV_MEM_CUSTOM_INCLUDE + #ifdef CONFIG_LV_MEM_CUSTOM_INCLUDE + #define LV_MEM_CUSTOM_INCLUDE CONFIG_LV_MEM_CUSTOM_INCLUDE + #else + #define LV_MEM_CUSTOM_INCLUDE /*Header for the dynamic memory function*/ + #endif + #endif + #ifndef LV_MEM_CUSTOM_ALLOC + #ifdef CONFIG_LV_MEM_CUSTOM_ALLOC + #define LV_MEM_CUSTOM_ALLOC CONFIG_LV_MEM_CUSTOM_ALLOC + #else + #define LV_MEM_CUSTOM_ALLOC malloc + #endif + #endif + #ifndef LV_MEM_CUSTOM_FREE + #ifdef CONFIG_LV_MEM_CUSTOM_FREE + #define LV_MEM_CUSTOM_FREE CONFIG_LV_MEM_CUSTOM_FREE + #else + #define LV_MEM_CUSTOM_FREE free + #endif + #endif + #ifndef LV_MEM_CUSTOM_REALLOC + #ifdef CONFIG_LV_MEM_CUSTOM_REALLOC + #define LV_MEM_CUSTOM_REALLOC CONFIG_LV_MEM_CUSTOM_REALLOC + #else + #define LV_MEM_CUSTOM_REALLOC realloc + #endif + #endif +#endif /*LV_MEM_CUSTOM*/ + +/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms. + *You will see an error log message if there wasn't enough buffers. */ +#ifndef LV_MEM_BUF_MAX_NUM + #ifdef CONFIG_LV_MEM_BUF_MAX_NUM + #define LV_MEM_BUF_MAX_NUM CONFIG_LV_MEM_BUF_MAX_NUM + #else + #define LV_MEM_BUF_MAX_NUM 16 + #endif +#endif + +/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/ +#ifndef LV_MEMCPY_MEMSET_STD + #ifdef CONFIG_LV_MEMCPY_MEMSET_STD + #define LV_MEMCPY_MEMSET_STD CONFIG_LV_MEMCPY_MEMSET_STD + #else + #define LV_MEMCPY_MEMSET_STD 0 + #endif +#endif + +/*==================== + HAL SETTINGS + *====================*/ + +/*Default display refresh period. LVG will redraw changed areas with this period time*/ +#ifndef LV_DISP_DEF_REFR_PERIOD + #ifdef CONFIG_LV_DISP_DEF_REFR_PERIOD + #define LV_DISP_DEF_REFR_PERIOD CONFIG_LV_DISP_DEF_REFR_PERIOD + #else + #define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ + #endif +#endif + +/*Input device read period in milliseconds*/ +#ifndef LV_INDEV_DEF_READ_PERIOD + #ifdef CONFIG_LV_INDEV_DEF_READ_PERIOD + #define LV_INDEV_DEF_READ_PERIOD CONFIG_LV_INDEV_DEF_READ_PERIOD + #else + #define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/ + #endif +#endif + +/*Use a custom tick source that tells the elapsed time in milliseconds. + *It removes the need to manually update the tick with `lv_tick_inc()`)*/ +#ifndef LV_TICK_CUSTOM + #ifdef CONFIG_LV_TICK_CUSTOM + #define LV_TICK_CUSTOM CONFIG_LV_TICK_CUSTOM + #else + #define LV_TICK_CUSTOM 0 + #endif +#endif +#if LV_TICK_CUSTOM + #ifndef LV_TICK_CUSTOM_INCLUDE + #ifdef CONFIG_LV_TICK_CUSTOM_INCLUDE + #define LV_TICK_CUSTOM_INCLUDE CONFIG_LV_TICK_CUSTOM_INCLUDE + #else + #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ + #endif + #endif + #ifndef LV_TICK_CUSTOM_SYS_TIME_EXPR + #ifdef CONFIG_LV_TICK_CUSTOM_SYS_TIME_EXPR + #define LV_TICK_CUSTOM_SYS_TIME_EXPR CONFIG_LV_TICK_CUSTOM_SYS_TIME_EXPR + #else + #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ + #endif + #endif +#endif /*LV_TICK_CUSTOM*/ + +/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. + *(Not so important, you can adjust it to modify default sizes and spaces)*/ +#ifndef LV_DPI_DEF + #ifdef CONFIG_LV_DPI_DEF + #define LV_DPI_DEF CONFIG_LV_DPI_DEF + #else + #define LV_DPI_DEF 130 /*[px/inch]*/ + #endif +#endif + +/*======================= + * FEATURE CONFIGURATION + *=======================*/ + +/*------------- + * Drawing + *-----------*/ + +/*Enable complex draw engine. + *Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/ +#ifndef LV_DRAW_COMPLEX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_DRAW_COMPLEX + #define LV_DRAW_COMPLEX CONFIG_LV_DRAW_COMPLEX + #else + #define LV_DRAW_COMPLEX 0 + #endif + #else + #define LV_DRAW_COMPLEX 1 + #endif +#endif +#if LV_DRAW_COMPLEX != 0 + + /*Allow buffering some shadow calculation. + *LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius` + *Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/ + #ifndef LV_SHADOW_CACHE_SIZE + #ifdef CONFIG_LV_SHADOW_CACHE_SIZE + #define LV_SHADOW_CACHE_SIZE CONFIG_LV_SHADOW_CACHE_SIZE + #else + #define LV_SHADOW_CACHE_SIZE 0 + #endif + #endif + + /* Set number of maximally cached circle data. + * The circumference of 1/4 circle are saved for anti-aliasing + * radius * 4 bytes are used per circle (the most often used radiuses are saved) + * 0: to disable caching */ + #ifndef LV_CIRCLE_CACHE_SIZE + #ifdef CONFIG_LV_CIRCLE_CACHE_SIZE + #define LV_CIRCLE_CACHE_SIZE CONFIG_LV_CIRCLE_CACHE_SIZE + #else + #define LV_CIRCLE_CACHE_SIZE 4 + #endif + #endif +#endif /*LV_DRAW_COMPLEX*/ + +/** + * "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer + * and blend it as an image with the given opacity. + * Note that `bg_opa`, `text_opa` etc don't require buffering into layer) + * The widget can be buffered in smaller chunks to avoid using large buffers. + * + * - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it + * - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated. + * + * Both buffer sizes are in bytes. + * "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers + * and can't be drawn in chunks. So these settings affects only widgets with opacity. + */ +#ifndef LV_LAYER_SIMPLE_BUF_SIZE + #ifdef CONFIG_LV_LAYER_SIMPLE_BUF_SIZE + #define LV_LAYER_SIMPLE_BUF_SIZE CONFIG_LV_LAYER_SIMPLE_BUF_SIZE + #else + #define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024) + #endif +#endif +#ifndef LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE + #ifdef CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE + #define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE + #else + #define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024) + #endif +#endif + +/*Default image cache size. Image caching keeps the images opened. + *If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added) + *With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images. + *However the opened images might consume additional RAM. + *0: to disable caching*/ +#ifndef LV_IMG_CACHE_DEF_SIZE + #ifdef CONFIG_LV_IMG_CACHE_DEF_SIZE + #define LV_IMG_CACHE_DEF_SIZE CONFIG_LV_IMG_CACHE_DEF_SIZE + #else + #define LV_IMG_CACHE_DEF_SIZE 0 + #endif +#endif + +/*Number of stops allowed per gradient. Increase this to allow more stops. + *This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/ +#ifndef LV_GRADIENT_MAX_STOPS + #ifdef CONFIG_LV_GRADIENT_MAX_STOPS + #define LV_GRADIENT_MAX_STOPS CONFIG_LV_GRADIENT_MAX_STOPS + #else + #define LV_GRADIENT_MAX_STOPS 2 + #endif +#endif + +/*Default gradient buffer size. + *When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again. + *LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes. + *If the cache is too small the map will be allocated only while it's required for the drawing. + *0 mean no caching.*/ +#ifndef LV_GRAD_CACHE_DEF_SIZE + #ifdef CONFIG_LV_GRAD_CACHE_DEF_SIZE + #define LV_GRAD_CACHE_DEF_SIZE CONFIG_LV_GRAD_CACHE_DEF_SIZE + #else + #define LV_GRAD_CACHE_DEF_SIZE 0 + #endif +#endif + +/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display) + *LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface + *The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */ +#ifndef LV_DITHER_GRADIENT + #ifdef CONFIG_LV_DITHER_GRADIENT + #define LV_DITHER_GRADIENT CONFIG_LV_DITHER_GRADIENT + #else + #define LV_DITHER_GRADIENT 0 + #endif +#endif +#if LV_DITHER_GRADIENT + /*Add support for error diffusion dithering. + *Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing. + *The increase in memory consumption is (24 bits * object's width)*/ + #ifndef LV_DITHER_ERROR_DIFFUSION + #ifdef CONFIG_LV_DITHER_ERROR_DIFFUSION + #define LV_DITHER_ERROR_DIFFUSION CONFIG_LV_DITHER_ERROR_DIFFUSION + #else + #define LV_DITHER_ERROR_DIFFUSION 0 + #endif + #endif +#endif + +/*Maximum buffer size to allocate for rotation. + *Only used if software rotation is enabled in the display driver.*/ +#ifndef LV_DISP_ROT_MAX_BUF + #ifdef CONFIG_LV_DISP_ROT_MAX_BUF + #define LV_DISP_ROT_MAX_BUF CONFIG_LV_DISP_ROT_MAX_BUF + #else + #define LV_DISP_ROT_MAX_BUF (10*1024) + #endif +#endif + +/*------------- + * GPU + *-----------*/ + +/*Use Arm's 2D acceleration library Arm-2D */ +#ifndef LV_USE_GPU_ARM2D + #ifdef CONFIG_LV_USE_GPU_ARM2D + #define LV_USE_GPU_ARM2D CONFIG_LV_USE_GPU_ARM2D + #else + #define LV_USE_GPU_ARM2D 0 + #endif +#endif + +/*Use STM32's DMA2D (aka Chrom Art) GPU*/ +#ifndef LV_USE_GPU_STM32_DMA2D + #ifdef CONFIG_LV_USE_GPU_STM32_DMA2D + #define LV_USE_GPU_STM32_DMA2D CONFIG_LV_USE_GPU_STM32_DMA2D + #else + #define LV_USE_GPU_STM32_DMA2D 0 + #endif +#endif +#if LV_USE_GPU_STM32_DMA2D + /*Must be defined to include path of CMSIS header of target processor + e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ + #ifndef LV_GPU_DMA2D_CMSIS_INCLUDE + #ifdef CONFIG_LV_GPU_DMA2D_CMSIS_INCLUDE + #define LV_GPU_DMA2D_CMSIS_INCLUDE CONFIG_LV_GPU_DMA2D_CMSIS_INCLUDE + #else + #define LV_GPU_DMA2D_CMSIS_INCLUDE + #endif + #endif +#endif + +/*Use SWM341's DMA2D GPU*/ +#ifndef LV_USE_GPU_SWM341_DMA2D + #ifdef CONFIG_LV_USE_GPU_SWM341_DMA2D + #define LV_USE_GPU_SWM341_DMA2D CONFIG_LV_USE_GPU_SWM341_DMA2D + #else + #define LV_USE_GPU_SWM341_DMA2D 0 + #endif +#endif +#if LV_USE_GPU_SWM341_DMA2D + #ifndef LV_GPU_SWM341_DMA2D_INCLUDE + #ifdef CONFIG_LV_GPU_SWM341_DMA2D_INCLUDE + #define LV_GPU_SWM341_DMA2D_INCLUDE CONFIG_LV_GPU_SWM341_DMA2D_INCLUDE + #else + #define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h" + #endif + #endif +#endif + +/*Use NXP's PXP GPU iMX RTxxx platforms*/ +#ifndef LV_USE_GPU_NXP_PXP + #ifdef CONFIG_LV_USE_GPU_NXP_PXP + #define LV_USE_GPU_NXP_PXP CONFIG_LV_USE_GPU_NXP_PXP + #else + #define LV_USE_GPU_NXP_PXP 0 + #endif +#endif +#if LV_USE_GPU_NXP_PXP + /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS + * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + */ + #ifndef LV_USE_GPU_NXP_PXP_AUTO_INIT + #ifdef CONFIG_LV_USE_GPU_NXP_PXP_AUTO_INIT + #define LV_USE_GPU_NXP_PXP_AUTO_INIT CONFIG_LV_USE_GPU_NXP_PXP_AUTO_INIT + #else + #define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 + #endif + #endif +#endif + +/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/ +#ifndef LV_USE_GPU_NXP_VG_LITE + #ifdef CONFIG_LV_USE_GPU_NXP_VG_LITE + #define LV_USE_GPU_NXP_VG_LITE CONFIG_LV_USE_GPU_NXP_VG_LITE + #else + #define LV_USE_GPU_NXP_VG_LITE 0 + #endif +#endif + +/*Use SDL renderer API*/ +#ifndef LV_USE_GPU_SDL + #ifdef CONFIG_LV_USE_GPU_SDL + #define LV_USE_GPU_SDL CONFIG_LV_USE_GPU_SDL + #else + #define LV_USE_GPU_SDL 0 + #endif +#endif +#if LV_USE_GPU_SDL + #ifndef LV_GPU_SDL_INCLUDE_PATH + #ifdef CONFIG_LV_GPU_SDL_INCLUDE_PATH + #define LV_GPU_SDL_INCLUDE_PATH CONFIG_LV_GPU_SDL_INCLUDE_PATH + #else + #define LV_GPU_SDL_INCLUDE_PATH + #endif + #endif + /*Texture cache size, 8MB by default*/ + #ifndef LV_GPU_SDL_LRU_SIZE + #ifdef CONFIG_LV_GPU_SDL_LRU_SIZE + #define LV_GPU_SDL_LRU_SIZE CONFIG_LV_GPU_SDL_LRU_SIZE + #else + #define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8) + #endif + #endif + /*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/ + #ifndef LV_GPU_SDL_CUSTOM_BLEND_MODE + #ifdef CONFIG_LV_GPU_SDL_CUSTOM_BLEND_MODE + #define LV_GPU_SDL_CUSTOM_BLEND_MODE CONFIG_LV_GPU_SDL_CUSTOM_BLEND_MODE + #else + #define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6)) + #endif + #endif +#endif + +/*------------- + * Logging + *-----------*/ + +/*Enable the log module*/ +#ifndef LV_USE_LOG + #ifdef CONFIG_LV_USE_LOG + #define LV_USE_LOG CONFIG_LV_USE_LOG + #else + #define LV_USE_LOG 0 + #endif +#endif +#if LV_USE_LOG + + /*How important log should be added: + *LV_LOG_LEVEL_TRACE A lot of logs to give detailed information + *LV_LOG_LEVEL_INFO Log important events + *LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem + *LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail + *LV_LOG_LEVEL_USER Only logs added by the user + *LV_LOG_LEVEL_NONE Do not log anything*/ + #ifndef LV_LOG_LEVEL + #ifdef CONFIG_LV_LOG_LEVEL + #define LV_LOG_LEVEL CONFIG_LV_LOG_LEVEL + #else + #define LV_LOG_LEVEL LV_LOG_LEVEL_WARN + #endif + #endif + + /*1: Print the log with 'printf'; + *0: User need to register a callback with `lv_log_register_print_cb()`*/ + #ifndef LV_LOG_PRINTF + #ifdef CONFIG_LV_LOG_PRINTF + #define LV_LOG_PRINTF CONFIG_LV_LOG_PRINTF + #else + #define LV_LOG_PRINTF 0 + #endif + #endif + + /*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/ + #ifndef LV_LOG_TRACE_MEM + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_MEM + #define LV_LOG_TRACE_MEM CONFIG_LV_LOG_TRACE_MEM + #else + #define LV_LOG_TRACE_MEM 0 + #endif + #else + #define LV_LOG_TRACE_MEM 1 + #endif + #endif + #ifndef LV_LOG_TRACE_TIMER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_TIMER + #define LV_LOG_TRACE_TIMER CONFIG_LV_LOG_TRACE_TIMER + #else + #define LV_LOG_TRACE_TIMER 0 + #endif + #else + #define LV_LOG_TRACE_TIMER 1 + #endif + #endif + #ifndef LV_LOG_TRACE_INDEV + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_INDEV + #define LV_LOG_TRACE_INDEV CONFIG_LV_LOG_TRACE_INDEV + #else + #define LV_LOG_TRACE_INDEV 0 + #endif + #else + #define LV_LOG_TRACE_INDEV 1 + #endif + #endif + #ifndef LV_LOG_TRACE_DISP_REFR + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_DISP_REFR + #define LV_LOG_TRACE_DISP_REFR CONFIG_LV_LOG_TRACE_DISP_REFR + #else + #define LV_LOG_TRACE_DISP_REFR 0 + #endif + #else + #define LV_LOG_TRACE_DISP_REFR 1 + #endif + #endif + #ifndef LV_LOG_TRACE_EVENT + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_EVENT + #define LV_LOG_TRACE_EVENT CONFIG_LV_LOG_TRACE_EVENT + #else + #define LV_LOG_TRACE_EVENT 0 + #endif + #else + #define LV_LOG_TRACE_EVENT 1 + #endif + #endif + #ifndef LV_LOG_TRACE_OBJ_CREATE + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_OBJ_CREATE + #define LV_LOG_TRACE_OBJ_CREATE CONFIG_LV_LOG_TRACE_OBJ_CREATE + #else + #define LV_LOG_TRACE_OBJ_CREATE 0 + #endif + #else + #define LV_LOG_TRACE_OBJ_CREATE 1 + #endif + #endif + #ifndef LV_LOG_TRACE_LAYOUT + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_LAYOUT + #define LV_LOG_TRACE_LAYOUT CONFIG_LV_LOG_TRACE_LAYOUT + #else + #define LV_LOG_TRACE_LAYOUT 0 + #endif + #else + #define LV_LOG_TRACE_LAYOUT 1 + #endif + #endif + #ifndef LV_LOG_TRACE_ANIM + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LOG_TRACE_ANIM + #define LV_LOG_TRACE_ANIM CONFIG_LV_LOG_TRACE_ANIM + #else + #define LV_LOG_TRACE_ANIM 0 + #endif + #else + #define LV_LOG_TRACE_ANIM 1 + #endif + #endif + +#endif /*LV_USE_LOG*/ + +/*------------- + * Asserts + *-----------*/ + +/*Enable asserts if an operation is failed or an invalid data is found. + *If LV_USE_LOG is enabled an error message will be printed on failure*/ +#ifndef LV_USE_ASSERT_NULL + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_ASSERT_NULL + #define LV_USE_ASSERT_NULL CONFIG_LV_USE_ASSERT_NULL + #else + #define LV_USE_ASSERT_NULL 0 + #endif + #else + #define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/ + #endif +#endif +#ifndef LV_USE_ASSERT_MALLOC + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_ASSERT_MALLOC + #define LV_USE_ASSERT_MALLOC CONFIG_LV_USE_ASSERT_MALLOC + #else + #define LV_USE_ASSERT_MALLOC 0 + #endif + #else + #define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/ + #endif +#endif +#ifndef LV_USE_ASSERT_STYLE + #ifdef CONFIG_LV_USE_ASSERT_STYLE + #define LV_USE_ASSERT_STYLE CONFIG_LV_USE_ASSERT_STYLE + #else + #define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/ + #endif +#endif +#ifndef LV_USE_ASSERT_MEM_INTEGRITY + #ifdef CONFIG_LV_USE_ASSERT_MEM_INTEGRITY + #define LV_USE_ASSERT_MEM_INTEGRITY CONFIG_LV_USE_ASSERT_MEM_INTEGRITY + #else + #define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/ + #endif +#endif +#ifndef LV_USE_ASSERT_OBJ + #ifdef CONFIG_LV_USE_ASSERT_OBJ + #define LV_USE_ASSERT_OBJ CONFIG_LV_USE_ASSERT_OBJ + #else + #define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/ + #endif +#endif + +/*Add a custom handler when assert happens e.g. to restart the MCU*/ +#ifndef LV_ASSERT_HANDLER_INCLUDE + #ifdef CONFIG_LV_ASSERT_HANDLER_INCLUDE + #define LV_ASSERT_HANDLER_INCLUDE CONFIG_LV_ASSERT_HANDLER_INCLUDE + #else + #define LV_ASSERT_HANDLER_INCLUDE + #endif +#endif +#ifndef LV_ASSERT_HANDLER + #ifdef CONFIG_LV_ASSERT_HANDLER + #define LV_ASSERT_HANDLER CONFIG_LV_ASSERT_HANDLER + #else + #define LV_ASSERT_HANDLER while(1); /*Halt by default*/ + #endif +#endif + +/*------------- + * Others + *-----------*/ + +/*1: Show CPU usage and FPS count*/ +#ifndef LV_USE_PERF_MONITOR + #ifdef CONFIG_LV_USE_PERF_MONITOR + #define LV_USE_PERF_MONITOR CONFIG_LV_USE_PERF_MONITOR + #else + #define LV_USE_PERF_MONITOR 0 + #endif +#endif +#if LV_USE_PERF_MONITOR + #ifndef LV_USE_PERF_MONITOR_POS + #ifdef CONFIG_LV_USE_PERF_MONITOR_POS + #define LV_USE_PERF_MONITOR_POS CONFIG_LV_USE_PERF_MONITOR_POS + #else + #define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT + #endif + #endif +#endif + +/*1: Show the used memory and the memory fragmentation + * Requires LV_MEM_CUSTOM = 0*/ +#ifndef LV_USE_MEM_MONITOR + #ifdef CONFIG_LV_USE_MEM_MONITOR + #define LV_USE_MEM_MONITOR CONFIG_LV_USE_MEM_MONITOR + #else + #define LV_USE_MEM_MONITOR 0 + #endif +#endif +#if LV_USE_MEM_MONITOR + #ifndef LV_USE_MEM_MONITOR_POS + #ifdef CONFIG_LV_USE_MEM_MONITOR_POS + #define LV_USE_MEM_MONITOR_POS CONFIG_LV_USE_MEM_MONITOR_POS + #else + #define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT + #endif + #endif +#endif + +/*1: Draw random colored rectangles over the redrawn areas*/ +#ifndef LV_USE_REFR_DEBUG + #ifdef CONFIG_LV_USE_REFR_DEBUG + #define LV_USE_REFR_DEBUG CONFIG_LV_USE_REFR_DEBUG + #else + #define LV_USE_REFR_DEBUG 0 + #endif +#endif + +/*Change the built in (v)snprintf functions*/ +#ifndef LV_SPRINTF_CUSTOM + #ifdef CONFIG_LV_SPRINTF_CUSTOM + #define LV_SPRINTF_CUSTOM CONFIG_LV_SPRINTF_CUSTOM + #else + #define LV_SPRINTF_CUSTOM 0 + #endif +#endif +#if LV_SPRINTF_CUSTOM + #ifndef LV_SPRINTF_INCLUDE + #ifdef CONFIG_LV_SPRINTF_INCLUDE + #define LV_SPRINTF_INCLUDE CONFIG_LV_SPRINTF_INCLUDE + #else + #define LV_SPRINTF_INCLUDE + #endif + #endif + #ifndef lv_snprintf + #ifdef CONFIG_LV_SNPRINTF + #define lv_snprintf CONFIG_LV_SNPRINTF + #else + #define lv_snprintf snprintf + #endif + #endif + #ifndef lv_vsnprintf + #ifdef CONFIG_LV_VSNPRINTF + #define lv_vsnprintf CONFIG_LV_VSNPRINTF + #else + #define lv_vsnprintf vsnprintf + #endif + #endif +#else /*LV_SPRINTF_CUSTOM*/ + #ifndef LV_SPRINTF_USE_FLOAT + #ifdef CONFIG_LV_SPRINTF_USE_FLOAT + #define LV_SPRINTF_USE_FLOAT CONFIG_LV_SPRINTF_USE_FLOAT + #else + #define LV_SPRINTF_USE_FLOAT 0 + #endif + #endif +#endif /*LV_SPRINTF_CUSTOM*/ + +#ifndef LV_USE_USER_DATA + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_USER_DATA + #define LV_USE_USER_DATA CONFIG_LV_USE_USER_DATA + #else + #define LV_USE_USER_DATA 0 + #endif + #else + #define LV_USE_USER_DATA 1 + #endif +#endif + +/*Garbage Collector settings + *Used if lvgl is bound to higher level language and the memory is managed by that language*/ +#ifndef LV_ENABLE_GC + #ifdef CONFIG_LV_ENABLE_GC + #define LV_ENABLE_GC CONFIG_LV_ENABLE_GC + #else + #define LV_ENABLE_GC 0 + #endif +#endif +#if LV_ENABLE_GC != 0 + #ifndef LV_GC_INCLUDE + #ifdef CONFIG_LV_GC_INCLUDE + #define LV_GC_INCLUDE CONFIG_LV_GC_INCLUDE + #else + #define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/ + #endif + #endif +#endif /*LV_ENABLE_GC*/ + +/*===================== + * COMPILER SETTINGS + *====================*/ + +/*For big endian systems set to 1*/ +#ifndef LV_BIG_ENDIAN_SYSTEM + #ifdef CONFIG_LV_BIG_ENDIAN_SYSTEM + #define LV_BIG_ENDIAN_SYSTEM CONFIG_LV_BIG_ENDIAN_SYSTEM + #else + #define LV_BIG_ENDIAN_SYSTEM 0 + #endif +#endif + +/*Define a custom attribute to `lv_tick_inc` function*/ +#ifndef LV_ATTRIBUTE_TICK_INC + #ifdef CONFIG_LV_ATTRIBUTE_TICK_INC + #define LV_ATTRIBUTE_TICK_INC CONFIG_LV_ATTRIBUTE_TICK_INC + #else + #define LV_ATTRIBUTE_TICK_INC + #endif +#endif + +/*Define a custom attribute to `lv_timer_handler` function*/ +#ifndef LV_ATTRIBUTE_TIMER_HANDLER + #ifdef CONFIG_LV_ATTRIBUTE_TIMER_HANDLER + #define LV_ATTRIBUTE_TIMER_HANDLER CONFIG_LV_ATTRIBUTE_TIMER_HANDLER + #else + #define LV_ATTRIBUTE_TIMER_HANDLER + #endif +#endif + +/*Define a custom attribute to `lv_disp_flush_ready` function*/ +#ifndef LV_ATTRIBUTE_FLUSH_READY + #ifdef CONFIG_LV_ATTRIBUTE_FLUSH_READY + #define LV_ATTRIBUTE_FLUSH_READY CONFIG_LV_ATTRIBUTE_FLUSH_READY + #else + #define LV_ATTRIBUTE_FLUSH_READY + #endif +#endif + +/*Required alignment size for buffers*/ +#ifndef LV_ATTRIBUTE_MEM_ALIGN_SIZE + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_ATTRIBUTE_MEM_ALIGN_SIZE + #define LV_ATTRIBUTE_MEM_ALIGN_SIZE CONFIG_LV_ATTRIBUTE_MEM_ALIGN_SIZE + #else + #define LV_ATTRIBUTE_MEM_ALIGN_SIZE 0 + #endif + #else + #define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1 + #endif +#endif + +/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default). + * E.g. __attribute__((aligned(4)))*/ +#ifndef LV_ATTRIBUTE_MEM_ALIGN + #ifdef CONFIG_LV_ATTRIBUTE_MEM_ALIGN + #define LV_ATTRIBUTE_MEM_ALIGN CONFIG_LV_ATTRIBUTE_MEM_ALIGN + #else + #define LV_ATTRIBUTE_MEM_ALIGN + #endif +#endif + +/*Attribute to mark large constant arrays for example font's bitmaps*/ +#ifndef LV_ATTRIBUTE_LARGE_CONST + #ifdef CONFIG_LV_ATTRIBUTE_LARGE_CONST + #define LV_ATTRIBUTE_LARGE_CONST CONFIG_LV_ATTRIBUTE_LARGE_CONST + #else + #define LV_ATTRIBUTE_LARGE_CONST + #endif +#endif + +/*Compiler prefix for a big array declaration in RAM*/ +#ifndef LV_ATTRIBUTE_LARGE_RAM_ARRAY + #ifdef CONFIG_LV_ATTRIBUTE_LARGE_RAM_ARRAY + #define LV_ATTRIBUTE_LARGE_RAM_ARRAY CONFIG_LV_ATTRIBUTE_LARGE_RAM_ARRAY + #else + #define LV_ATTRIBUTE_LARGE_RAM_ARRAY + #endif +#endif + +/*Place performance critical functions into a faster memory (e.g RAM)*/ +#ifndef LV_ATTRIBUTE_FAST_MEM + #ifdef CONFIG_LV_ATTRIBUTE_FAST_MEM + #define LV_ATTRIBUTE_FAST_MEM CONFIG_LV_ATTRIBUTE_FAST_MEM + #else + #define LV_ATTRIBUTE_FAST_MEM + #endif +#endif + +/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/ +#ifndef LV_ATTRIBUTE_DMA + #ifdef CONFIG_LV_ATTRIBUTE_DMA + #define LV_ATTRIBUTE_DMA CONFIG_LV_ATTRIBUTE_DMA + #else + #define LV_ATTRIBUTE_DMA + #endif +#endif + +/*Export integer constant to binding. This macro is used with constants in the form of LV_ that + *should also appear on LVGL binding API such as Micropython.*/ +#ifndef LV_EXPORT_CONST_INT + #ifdef CONFIG_LV_EXPORT_CONST_INT + #define LV_EXPORT_CONST_INT CONFIG_LV_EXPORT_CONST_INT + #else + #define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/ + #endif +#endif + +/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/ +#ifndef LV_USE_LARGE_COORD + #ifdef CONFIG_LV_USE_LARGE_COORD + #define LV_USE_LARGE_COORD CONFIG_LV_USE_LARGE_COORD + #else + #define LV_USE_LARGE_COORD 0 + #endif +#endif + +/*================== + * FONT USAGE + *===================*/ + +/*Montserrat fonts with ASCII range and some symbols using bpp = 4 + *https://fonts.google.com/specimen/Montserrat*/ +#ifndef LV_FONT_MONTSERRAT_8 + #ifdef CONFIG_LV_FONT_MONTSERRAT_8 + #define LV_FONT_MONTSERRAT_8 CONFIG_LV_FONT_MONTSERRAT_8 + #else + #define LV_FONT_MONTSERRAT_8 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_10 + #ifdef CONFIG_LV_FONT_MONTSERRAT_10 + #define LV_FONT_MONTSERRAT_10 CONFIG_LV_FONT_MONTSERRAT_10 + #else + #define LV_FONT_MONTSERRAT_10 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_12 + #ifdef CONFIG_LV_FONT_MONTSERRAT_12 + #define LV_FONT_MONTSERRAT_12 CONFIG_LV_FONT_MONTSERRAT_12 + #else + #define LV_FONT_MONTSERRAT_12 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_14 + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_FONT_MONTSERRAT_14 + #define LV_FONT_MONTSERRAT_14 CONFIG_LV_FONT_MONTSERRAT_14 + #else + #define LV_FONT_MONTSERRAT_14 0 + #endif + #else + #define LV_FONT_MONTSERRAT_14 1 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_16 + #ifdef CONFIG_LV_FONT_MONTSERRAT_16 + #define LV_FONT_MONTSERRAT_16 CONFIG_LV_FONT_MONTSERRAT_16 + #else + #define LV_FONT_MONTSERRAT_16 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_18 + #ifdef CONFIG_LV_FONT_MONTSERRAT_18 + #define LV_FONT_MONTSERRAT_18 CONFIG_LV_FONT_MONTSERRAT_18 + #else + #define LV_FONT_MONTSERRAT_18 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_20 + #ifdef CONFIG_LV_FONT_MONTSERRAT_20 + #define LV_FONT_MONTSERRAT_20 CONFIG_LV_FONT_MONTSERRAT_20 + #else + #define LV_FONT_MONTSERRAT_20 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_22 + #ifdef CONFIG_LV_FONT_MONTSERRAT_22 + #define LV_FONT_MONTSERRAT_22 CONFIG_LV_FONT_MONTSERRAT_22 + #else + #define LV_FONT_MONTSERRAT_22 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_24 + #ifdef CONFIG_LV_FONT_MONTSERRAT_24 + #define LV_FONT_MONTSERRAT_24 CONFIG_LV_FONT_MONTSERRAT_24 + #else + #define LV_FONT_MONTSERRAT_24 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_26 + #ifdef CONFIG_LV_FONT_MONTSERRAT_26 + #define LV_FONT_MONTSERRAT_26 CONFIG_LV_FONT_MONTSERRAT_26 + #else + #define LV_FONT_MONTSERRAT_26 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_28 + #ifdef CONFIG_LV_FONT_MONTSERRAT_28 + #define LV_FONT_MONTSERRAT_28 CONFIG_LV_FONT_MONTSERRAT_28 + #else + #define LV_FONT_MONTSERRAT_28 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_30 + #ifdef CONFIG_LV_FONT_MONTSERRAT_30 + #define LV_FONT_MONTSERRAT_30 CONFIG_LV_FONT_MONTSERRAT_30 + #else + #define LV_FONT_MONTSERRAT_30 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_32 + #ifdef CONFIG_LV_FONT_MONTSERRAT_32 + #define LV_FONT_MONTSERRAT_32 CONFIG_LV_FONT_MONTSERRAT_32 + #else + #define LV_FONT_MONTSERRAT_32 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_34 + #ifdef CONFIG_LV_FONT_MONTSERRAT_34 + #define LV_FONT_MONTSERRAT_34 CONFIG_LV_FONT_MONTSERRAT_34 + #else + #define LV_FONT_MONTSERRAT_34 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_36 + #ifdef CONFIG_LV_FONT_MONTSERRAT_36 + #define LV_FONT_MONTSERRAT_36 CONFIG_LV_FONT_MONTSERRAT_36 + #else + #define LV_FONT_MONTSERRAT_36 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_38 + #ifdef CONFIG_LV_FONT_MONTSERRAT_38 + #define LV_FONT_MONTSERRAT_38 CONFIG_LV_FONT_MONTSERRAT_38 + #else + #define LV_FONT_MONTSERRAT_38 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_40 + #ifdef CONFIG_LV_FONT_MONTSERRAT_40 + #define LV_FONT_MONTSERRAT_40 CONFIG_LV_FONT_MONTSERRAT_40 + #else + #define LV_FONT_MONTSERRAT_40 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_42 + #ifdef CONFIG_LV_FONT_MONTSERRAT_42 + #define LV_FONT_MONTSERRAT_42 CONFIG_LV_FONT_MONTSERRAT_42 + #else + #define LV_FONT_MONTSERRAT_42 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_44 + #ifdef CONFIG_LV_FONT_MONTSERRAT_44 + #define LV_FONT_MONTSERRAT_44 CONFIG_LV_FONT_MONTSERRAT_44 + #else + #define LV_FONT_MONTSERRAT_44 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_46 + #ifdef CONFIG_LV_FONT_MONTSERRAT_46 + #define LV_FONT_MONTSERRAT_46 CONFIG_LV_FONT_MONTSERRAT_46 + #else + #define LV_FONT_MONTSERRAT_46 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_48 + #ifdef CONFIG_LV_FONT_MONTSERRAT_48 + #define LV_FONT_MONTSERRAT_48 CONFIG_LV_FONT_MONTSERRAT_48 + #else + #define LV_FONT_MONTSERRAT_48 0 + #endif +#endif + +/*Demonstrate special features*/ +#ifndef LV_FONT_MONTSERRAT_12_SUBPX + #ifdef CONFIG_LV_FONT_MONTSERRAT_12_SUBPX + #define LV_FONT_MONTSERRAT_12_SUBPX CONFIG_LV_FONT_MONTSERRAT_12_SUBPX + #else + #define LV_FONT_MONTSERRAT_12_SUBPX 0 + #endif +#endif +#ifndef LV_FONT_MONTSERRAT_28_COMPRESSED + #ifdef CONFIG_LV_FONT_MONTSERRAT_28_COMPRESSED + #define LV_FONT_MONTSERRAT_28_COMPRESSED CONFIG_LV_FONT_MONTSERRAT_28_COMPRESSED + #else + #define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/ + #endif +#endif +#ifndef LV_FONT_DEJAVU_16_PERSIAN_HEBREW + #ifdef CONFIG_LV_FONT_DEJAVU_16_PERSIAN_HEBREW + #define LV_FONT_DEJAVU_16_PERSIAN_HEBREW CONFIG_LV_FONT_DEJAVU_16_PERSIAN_HEBREW + #else + #define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/ + #endif +#endif +#ifndef LV_FONT_SIMSUN_16_CJK + #ifdef CONFIG_LV_FONT_SIMSUN_16_CJK + #define LV_FONT_SIMSUN_16_CJK CONFIG_LV_FONT_SIMSUN_16_CJK + #else + #define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/ + #endif +#endif + +/*Pixel perfect monospace fonts*/ +#ifndef LV_FONT_UNSCII_8 + #ifdef CONFIG_LV_FONT_UNSCII_8 + #define LV_FONT_UNSCII_8 CONFIG_LV_FONT_UNSCII_8 + #else + #define LV_FONT_UNSCII_8 0 + #endif +#endif +#ifndef LV_FONT_UNSCII_16 + #ifdef CONFIG_LV_FONT_UNSCII_16 + #define LV_FONT_UNSCII_16 CONFIG_LV_FONT_UNSCII_16 + #else + #define LV_FONT_UNSCII_16 0 + #endif +#endif + +/*Optionally declare custom fonts here. + *You can use these fonts as default font too and they will be available globally. + *E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/ +#ifndef LV_FONT_CUSTOM_DECLARE + #ifdef CONFIG_LV_FONT_CUSTOM_DECLARE + #define LV_FONT_CUSTOM_DECLARE CONFIG_LV_FONT_CUSTOM_DECLARE + #else + #define LV_FONT_CUSTOM_DECLARE + #endif +#endif + +/*Always set a default font*/ +#ifndef LV_FONT_DEFAULT + #ifdef CONFIG_LV_FONT_DEFAULT + #define LV_FONT_DEFAULT CONFIG_LV_FONT_DEFAULT + #else + #define LV_FONT_DEFAULT &lv_font_montserrat_14 + #endif +#endif + +/*Enable handling large font and/or fonts with a lot of characters. + *The limit depends on the font size, font face and bpp. + *Compiler error will be triggered if a font needs it.*/ +#ifndef LV_FONT_FMT_TXT_LARGE + #ifdef CONFIG_LV_FONT_FMT_TXT_LARGE + #define LV_FONT_FMT_TXT_LARGE CONFIG_LV_FONT_FMT_TXT_LARGE + #else + #define LV_FONT_FMT_TXT_LARGE 0 + #endif +#endif + +/*Enables/disables support for compressed fonts.*/ +#ifndef LV_USE_FONT_COMPRESSED + #ifdef CONFIG_LV_USE_FONT_COMPRESSED + #define LV_USE_FONT_COMPRESSED CONFIG_LV_USE_FONT_COMPRESSED + #else + #define LV_USE_FONT_COMPRESSED 0 + #endif +#endif + +/*Enable subpixel rendering*/ +#ifndef LV_USE_FONT_SUBPX + #ifdef CONFIG_LV_USE_FONT_SUBPX + #define LV_USE_FONT_SUBPX CONFIG_LV_USE_FONT_SUBPX + #else + #define LV_USE_FONT_SUBPX 0 + #endif +#endif +#if LV_USE_FONT_SUBPX + /*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/ + #ifndef LV_FONT_SUBPX_BGR + #ifdef CONFIG_LV_FONT_SUBPX_BGR + #define LV_FONT_SUBPX_BGR CONFIG_LV_FONT_SUBPX_BGR + #else + #define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/ + #endif + #endif +#endif + +/*Enable drawing placeholders when glyph dsc is not found*/ +#ifndef LV_USE_FONT_PLACEHOLDER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_FONT_PLACEHOLDER + #define LV_USE_FONT_PLACEHOLDER CONFIG_LV_USE_FONT_PLACEHOLDER + #else + #define LV_USE_FONT_PLACEHOLDER 0 + #endif + #else + #define LV_USE_FONT_PLACEHOLDER 1 + #endif +#endif + +/*================= + * TEXT SETTINGS + *=================*/ + +/** + * Select a character encoding for strings. + * Your IDE or editor should have the same character encoding + * - LV_TXT_ENC_UTF8 + * - LV_TXT_ENC_ASCII + */ +#ifndef LV_TXT_ENC + #ifdef CONFIG_LV_TXT_ENC + #define LV_TXT_ENC CONFIG_LV_TXT_ENC + #else + #define LV_TXT_ENC LV_TXT_ENC_UTF8 + #endif +#endif + +/*Can break (wrap) texts on these chars*/ +#ifndef LV_TXT_BREAK_CHARS + #ifdef CONFIG_LV_TXT_BREAK_CHARS + #define LV_TXT_BREAK_CHARS CONFIG_LV_TXT_BREAK_CHARS + #else + #define LV_TXT_BREAK_CHARS " ,.;:-_" + #endif +#endif + +/*If a word is at least this long, will break wherever "prettiest" + *To disable, set to a value <= 0*/ +#ifndef LV_TXT_LINE_BREAK_LONG_LEN + #ifdef CONFIG_LV_TXT_LINE_BREAK_LONG_LEN + #define LV_TXT_LINE_BREAK_LONG_LEN CONFIG_LV_TXT_LINE_BREAK_LONG_LEN + #else + #define LV_TXT_LINE_BREAK_LONG_LEN 0 + #endif +#endif + +/*Minimum number of characters in a long word to put on a line before a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN + #ifdef CONFIG_LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN + #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN CONFIG_LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN + #else + #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 + #endif +#endif + +/*Minimum number of characters in a long word to put on a line after a break. + *Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/ +#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN + #ifdef CONFIG_LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN + #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN CONFIG_LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN + #else + #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 + #endif +#endif + +/*The control character to use for signalling text recoloring.*/ +#ifndef LV_TXT_COLOR_CMD + #ifdef CONFIG_LV_TXT_COLOR_CMD + #define LV_TXT_COLOR_CMD CONFIG_LV_TXT_COLOR_CMD + #else + #define LV_TXT_COLOR_CMD "#" + #endif +#endif + +/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts. + *The direction will be processed according to the Unicode Bidirectional Algorithm: + *https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ +#ifndef LV_USE_BIDI + #ifdef CONFIG_LV_USE_BIDI + #define LV_USE_BIDI CONFIG_LV_USE_BIDI + #else + #define LV_USE_BIDI 0 + #endif +#endif +#if LV_USE_BIDI + /*Set the default direction. Supported values: + *`LV_BASE_DIR_LTR` Left-to-Right + *`LV_BASE_DIR_RTL` Right-to-Left + *`LV_BASE_DIR_AUTO` detect texts base direction*/ + #ifndef LV_BIDI_BASE_DIR_DEF + #ifdef CONFIG_LV_BIDI_BASE_DIR_DEF + #define LV_BIDI_BASE_DIR_DEF CONFIG_LV_BIDI_BASE_DIR_DEF + #else + #define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO + #endif + #endif +#endif + +/*Enable Arabic/Persian processing + *In these languages characters should be replaced with an other form based on their position in the text*/ +#ifndef LV_USE_ARABIC_PERSIAN_CHARS + #ifdef CONFIG_LV_USE_ARABIC_PERSIAN_CHARS + #define LV_USE_ARABIC_PERSIAN_CHARS CONFIG_LV_USE_ARABIC_PERSIAN_CHARS + #else + #define LV_USE_ARABIC_PERSIAN_CHARS 0 + #endif +#endif + +/*================== + * WIDGET USAGE + *================*/ + +/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/ + +#ifndef LV_USE_ARC + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_ARC + #define LV_USE_ARC CONFIG_LV_USE_ARC + #else + #define LV_USE_ARC 0 + #endif + #else + #define LV_USE_ARC 1 + #endif +#endif + +#ifndef LV_USE_BAR + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_BAR + #define LV_USE_BAR CONFIG_LV_USE_BAR + #else + #define LV_USE_BAR 0 + #endif + #else + #define LV_USE_BAR 1 + #endif +#endif + +#ifndef LV_USE_BTN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_BTN + #define LV_USE_BTN CONFIG_LV_USE_BTN + #else + #define LV_USE_BTN 0 + #endif + #else + #define LV_USE_BTN 1 + #endif +#endif + +#ifndef LV_USE_BTNMATRIX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_BTNMATRIX + #define LV_USE_BTNMATRIX CONFIG_LV_USE_BTNMATRIX + #else + #define LV_USE_BTNMATRIX 0 + #endif + #else + #define LV_USE_BTNMATRIX 1 + #endif +#endif + +#ifndef LV_USE_CANVAS + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CANVAS + #define LV_USE_CANVAS CONFIG_LV_USE_CANVAS + #else + #define LV_USE_CANVAS 0 + #endif + #else + #define LV_USE_CANVAS 1 + #endif +#endif + +#ifndef LV_USE_CHECKBOX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CHECKBOX + #define LV_USE_CHECKBOX CONFIG_LV_USE_CHECKBOX + #else + #define LV_USE_CHECKBOX 0 + #endif + #else + #define LV_USE_CHECKBOX 1 + #endif +#endif + +#ifndef LV_USE_DROPDOWN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_DROPDOWN + #define LV_USE_DROPDOWN CONFIG_LV_USE_DROPDOWN + #else + #define LV_USE_DROPDOWN 0 + #endif + #else + #define LV_USE_DROPDOWN 1 /*Requires: lv_label*/ + #endif +#endif + +#ifndef LV_USE_IMG + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_IMG + #define LV_USE_IMG CONFIG_LV_USE_IMG + #else + #define LV_USE_IMG 0 + #endif + #else + #define LV_USE_IMG 1 /*Requires: lv_label*/ + #endif +#endif + +#ifndef LV_USE_LABEL + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_LABEL + #define LV_USE_LABEL CONFIG_LV_USE_LABEL + #else + #define LV_USE_LABEL 0 + #endif + #else + #define LV_USE_LABEL 1 + #endif +#endif +#if LV_USE_LABEL + #ifndef LV_LABEL_TEXT_SELECTION + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LABEL_TEXT_SELECTION + #define LV_LABEL_TEXT_SELECTION CONFIG_LV_LABEL_TEXT_SELECTION + #else + #define LV_LABEL_TEXT_SELECTION 0 + #endif + #else + #define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/ + #endif + #endif + #ifndef LV_LABEL_LONG_TXT_HINT + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_LABEL_LONG_TXT_HINT + #define LV_LABEL_LONG_TXT_HINT CONFIG_LV_LABEL_LONG_TXT_HINT + #else + #define LV_LABEL_LONG_TXT_HINT 0 + #endif + #else + #define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/ + #endif + #endif +#endif + +#ifndef LV_USE_LINE + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_LINE + #define LV_USE_LINE CONFIG_LV_USE_LINE + #else + #define LV_USE_LINE 0 + #endif + #else + #define LV_USE_LINE 1 + #endif +#endif + +#ifndef LV_USE_ROLLER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_ROLLER + #define LV_USE_ROLLER CONFIG_LV_USE_ROLLER + #else + #define LV_USE_ROLLER 0 + #endif + #else + #define LV_USE_ROLLER 1 /*Requires: lv_label*/ + #endif +#endif +#if LV_USE_ROLLER + #ifndef LV_ROLLER_INF_PAGES + #ifdef CONFIG_LV_ROLLER_INF_PAGES + #define LV_ROLLER_INF_PAGES CONFIG_LV_ROLLER_INF_PAGES + #else + #define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/ + #endif + #endif +#endif + +#ifndef LV_USE_SLIDER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_SLIDER + #define LV_USE_SLIDER CONFIG_LV_USE_SLIDER + #else + #define LV_USE_SLIDER 0 + #endif + #else + #define LV_USE_SLIDER 1 /*Requires: lv_bar*/ + #endif +#endif + +#ifndef LV_USE_SWITCH + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_SWITCH + #define LV_USE_SWITCH CONFIG_LV_USE_SWITCH + #else + #define LV_USE_SWITCH 0 + #endif + #else + #define LV_USE_SWITCH 1 + #endif +#endif + +#ifndef LV_USE_TEXTAREA + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_TEXTAREA + #define LV_USE_TEXTAREA CONFIG_LV_USE_TEXTAREA + #else + #define LV_USE_TEXTAREA 0 + #endif + #else + #define LV_USE_TEXTAREA 1 /*Requires: lv_label*/ + #endif +#endif +#if LV_USE_TEXTAREA != 0 + #ifndef LV_TEXTAREA_DEF_PWD_SHOW_TIME + #ifdef CONFIG_LV_TEXTAREA_DEF_PWD_SHOW_TIME + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME CONFIG_LV_TEXTAREA_DEF_PWD_SHOW_TIME + #else + #define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/ + #endif + #endif +#endif + +#ifndef LV_USE_TABLE + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_TABLE + #define LV_USE_TABLE CONFIG_LV_USE_TABLE + #else + #define LV_USE_TABLE 0 + #endif + #else + #define LV_USE_TABLE 1 + #endif +#endif + +/*================== + * EXTRA COMPONENTS + *==================*/ + +/*----------- + * Widgets + *----------*/ +#ifndef LV_USE_ANIMIMG + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_ANIMIMG + #define LV_USE_ANIMIMG CONFIG_LV_USE_ANIMIMG + #else + #define LV_USE_ANIMIMG 0 + #endif + #else + #define LV_USE_ANIMIMG 1 + #endif +#endif + +#ifndef LV_USE_CALENDAR + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CALENDAR + #define LV_USE_CALENDAR CONFIG_LV_USE_CALENDAR + #else + #define LV_USE_CALENDAR 0 + #endif + #else + #define LV_USE_CALENDAR 1 + #endif +#endif +#if LV_USE_CALENDAR + #ifndef LV_CALENDAR_WEEK_STARTS_MONDAY + #ifdef CONFIG_LV_CALENDAR_WEEK_STARTS_MONDAY + #define LV_CALENDAR_WEEK_STARTS_MONDAY CONFIG_LV_CALENDAR_WEEK_STARTS_MONDAY + #else + #define LV_CALENDAR_WEEK_STARTS_MONDAY 0 + #endif + #endif + #if LV_CALENDAR_WEEK_STARTS_MONDAY + #ifndef LV_CALENDAR_DEFAULT_DAY_NAMES + #ifdef CONFIG_LV_CALENDAR_DEFAULT_DAY_NAMES + #define LV_CALENDAR_DEFAULT_DAY_NAMES CONFIG_LV_CALENDAR_DEFAULT_DAY_NAMES + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} + #endif + #endif + #else + #ifndef LV_CALENDAR_DEFAULT_DAY_NAMES + #ifdef CONFIG_LV_CALENDAR_DEFAULT_DAY_NAMES + #define LV_CALENDAR_DEFAULT_DAY_NAMES CONFIG_LV_CALENDAR_DEFAULT_DAY_NAMES + #else + #define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} + #endif + #endif + #endif + + #ifndef LV_CALENDAR_DEFAULT_MONTH_NAMES + #ifdef CONFIG_LV_CALENDAR_DEFAULT_MONTH_NAMES + #define LV_CALENDAR_DEFAULT_MONTH_NAMES CONFIG_LV_CALENDAR_DEFAULT_MONTH_NAMES + #else + #define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} + #endif + #endif + #ifndef LV_USE_CALENDAR_HEADER_ARROW + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CALENDAR_HEADER_ARROW + #define LV_USE_CALENDAR_HEADER_ARROW CONFIG_LV_USE_CALENDAR_HEADER_ARROW + #else + #define LV_USE_CALENDAR_HEADER_ARROW 0 + #endif + #else + #define LV_USE_CALENDAR_HEADER_ARROW 1 + #endif + #endif + #ifndef LV_USE_CALENDAR_HEADER_DROPDOWN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CALENDAR_HEADER_DROPDOWN + #define LV_USE_CALENDAR_HEADER_DROPDOWN CONFIG_LV_USE_CALENDAR_HEADER_DROPDOWN + #else + #define LV_USE_CALENDAR_HEADER_DROPDOWN 0 + #endif + #else + #define LV_USE_CALENDAR_HEADER_DROPDOWN 1 + #endif + #endif +#endif /*LV_USE_CALENDAR*/ + +#ifndef LV_USE_CHART + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_CHART + #define LV_USE_CHART CONFIG_LV_USE_CHART + #else + #define LV_USE_CHART 0 + #endif + #else + #define LV_USE_CHART 1 + #endif +#endif + +#ifndef LV_USE_COLORWHEEL + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_COLORWHEEL + #define LV_USE_COLORWHEEL CONFIG_LV_USE_COLORWHEEL + #else + #define LV_USE_COLORWHEEL 0 + #endif + #else + #define LV_USE_COLORWHEEL 1 + #endif +#endif + +#ifndef LV_USE_IMGBTN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_IMGBTN + #define LV_USE_IMGBTN CONFIG_LV_USE_IMGBTN + #else + #define LV_USE_IMGBTN 0 + #endif + #else + #define LV_USE_IMGBTN 1 + #endif +#endif + +#ifndef LV_USE_KEYBOARD + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_KEYBOARD + #define LV_USE_KEYBOARD CONFIG_LV_USE_KEYBOARD + #else + #define LV_USE_KEYBOARD 0 + #endif + #else + #define LV_USE_KEYBOARD 1 + #endif +#endif + +#ifndef LV_USE_LED + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_LED + #define LV_USE_LED CONFIG_LV_USE_LED + #else + #define LV_USE_LED 0 + #endif + #else + #define LV_USE_LED 1 + #endif +#endif + +#ifndef LV_USE_LIST + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_LIST + #define LV_USE_LIST CONFIG_LV_USE_LIST + #else + #define LV_USE_LIST 0 + #endif + #else + #define LV_USE_LIST 1 + #endif +#endif + +#ifndef LV_USE_MENU + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_MENU + #define LV_USE_MENU CONFIG_LV_USE_MENU + #else + #define LV_USE_MENU 0 + #endif + #else + #define LV_USE_MENU 1 + #endif +#endif + +#ifndef LV_USE_METER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_METER + #define LV_USE_METER CONFIG_LV_USE_METER + #else + #define LV_USE_METER 0 + #endif + #else + #define LV_USE_METER 1 + #endif +#endif + +#ifndef LV_USE_MSGBOX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_MSGBOX + #define LV_USE_MSGBOX CONFIG_LV_USE_MSGBOX + #else + #define LV_USE_MSGBOX 0 + #endif + #else + #define LV_USE_MSGBOX 1 + #endif +#endif + +#ifndef LV_USE_SPAN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_SPAN + #define LV_USE_SPAN CONFIG_LV_USE_SPAN + #else + #define LV_USE_SPAN 0 + #endif + #else + #define LV_USE_SPAN 1 + #endif +#endif +#if LV_USE_SPAN + /*A line text can contain maximum num of span descriptor */ + #ifndef LV_SPAN_SNIPPET_STACK_SIZE + #ifdef CONFIG_LV_SPAN_SNIPPET_STACK_SIZE + #define LV_SPAN_SNIPPET_STACK_SIZE CONFIG_LV_SPAN_SNIPPET_STACK_SIZE + #else + #define LV_SPAN_SNIPPET_STACK_SIZE 64 + #endif + #endif +#endif + +#ifndef LV_USE_SPINBOX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_SPINBOX + #define LV_USE_SPINBOX CONFIG_LV_USE_SPINBOX + #else + #define LV_USE_SPINBOX 0 + #endif + #else + #define LV_USE_SPINBOX 1 + #endif +#endif + +#ifndef LV_USE_SPINNER + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_SPINNER + #define LV_USE_SPINNER CONFIG_LV_USE_SPINNER + #else + #define LV_USE_SPINNER 0 + #endif + #else + #define LV_USE_SPINNER 1 + #endif +#endif + +#ifndef LV_USE_TABVIEW + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_TABVIEW + #define LV_USE_TABVIEW CONFIG_LV_USE_TABVIEW + #else + #define LV_USE_TABVIEW 0 + #endif + #else + #define LV_USE_TABVIEW 1 + #endif +#endif + +#ifndef LV_USE_TILEVIEW + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_TILEVIEW + #define LV_USE_TILEVIEW CONFIG_LV_USE_TILEVIEW + #else + #define LV_USE_TILEVIEW 0 + #endif + #else + #define LV_USE_TILEVIEW 1 + #endif +#endif + +#ifndef LV_USE_WIN + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_WIN + #define LV_USE_WIN CONFIG_LV_USE_WIN + #else + #define LV_USE_WIN 0 + #endif + #else + #define LV_USE_WIN 1 + #endif +#endif + +/*----------- + * Themes + *----------*/ + +/*A simple, impressive and very complete theme*/ +#ifndef LV_USE_THEME_DEFAULT + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_THEME_DEFAULT + #define LV_USE_THEME_DEFAULT CONFIG_LV_USE_THEME_DEFAULT + #else + #define LV_USE_THEME_DEFAULT 0 + #endif + #else + #define LV_USE_THEME_DEFAULT 1 + #endif +#endif +#if LV_USE_THEME_DEFAULT + + /*0: Light mode; 1: Dark mode*/ + #ifndef LV_THEME_DEFAULT_DARK + #ifdef CONFIG_LV_THEME_DEFAULT_DARK + #define LV_THEME_DEFAULT_DARK CONFIG_LV_THEME_DEFAULT_DARK + #else + #define LV_THEME_DEFAULT_DARK 0 + #endif + #endif + + /*1: Enable grow on press*/ + #ifndef LV_THEME_DEFAULT_GROW + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_THEME_DEFAULT_GROW + #define LV_THEME_DEFAULT_GROW CONFIG_LV_THEME_DEFAULT_GROW + #else + #define LV_THEME_DEFAULT_GROW 0 + #endif + #else + #define LV_THEME_DEFAULT_GROW 1 + #endif + #endif + + /*Default transition time in [ms]*/ + #ifndef LV_THEME_DEFAULT_TRANSITION_TIME + #ifdef CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME + #define LV_THEME_DEFAULT_TRANSITION_TIME CONFIG_LV_THEME_DEFAULT_TRANSITION_TIME + #else + #define LV_THEME_DEFAULT_TRANSITION_TIME 80 + #endif + #endif +#endif /*LV_USE_THEME_DEFAULT*/ + +/*A very simple theme that is a good starting point for a custom theme*/ +#ifndef LV_USE_THEME_BASIC + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_THEME_BASIC + #define LV_USE_THEME_BASIC CONFIG_LV_USE_THEME_BASIC + #else + #define LV_USE_THEME_BASIC 0 + #endif + #else + #define LV_USE_THEME_BASIC 1 + #endif +#endif + +/*A theme designed for monochrome displays*/ +#ifndef LV_USE_THEME_MONO + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_THEME_MONO + #define LV_USE_THEME_MONO CONFIG_LV_USE_THEME_MONO + #else + #define LV_USE_THEME_MONO 0 + #endif + #else + #define LV_USE_THEME_MONO 1 + #endif +#endif + +/*----------- + * Layouts + *----------*/ + +/*A layout similar to Flexbox in CSS.*/ +#ifndef LV_USE_FLEX + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_FLEX + #define LV_USE_FLEX CONFIG_LV_USE_FLEX + #else + #define LV_USE_FLEX 0 + #endif + #else + #define LV_USE_FLEX 1 + #endif +#endif + +/*A layout similar to Grid in CSS.*/ +#ifndef LV_USE_GRID + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_GRID + #define LV_USE_GRID CONFIG_LV_USE_GRID + #else + #define LV_USE_GRID 0 + #endif + #else + #define LV_USE_GRID 1 + #endif +#endif + +/*--------------------- + * 3rd party libraries + *--------------------*/ + +/*File system interfaces for common APIs */ + +/*API for fopen, fread, etc*/ +#ifndef LV_USE_FS_STDIO + #ifdef CONFIG_LV_USE_FS_STDIO + #define LV_USE_FS_STDIO CONFIG_LV_USE_FS_STDIO + #else + #define LV_USE_FS_STDIO 0 + #endif +#endif +#if LV_USE_FS_STDIO + #ifndef LV_FS_STDIO_LETTER + #ifdef CONFIG_LV_FS_STDIO_LETTER + #define LV_FS_STDIO_LETTER CONFIG_LV_FS_STDIO_LETTER + #else + #define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #endif + #endif + #ifndef LV_FS_STDIO_PATH + #ifdef CONFIG_LV_FS_STDIO_PATH + #define LV_FS_STDIO_PATH CONFIG_LV_FS_STDIO_PATH + #else + #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #endif + #endif + #ifndef LV_FS_STDIO_CACHE_SIZE + #ifdef CONFIG_LV_FS_STDIO_CACHE_SIZE + #define LV_FS_STDIO_CACHE_SIZE CONFIG_LV_FS_STDIO_CACHE_SIZE + #else + #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #endif + #endif +#endif + +/*API for open, read, etc*/ +#ifndef LV_USE_FS_POSIX + #ifdef CONFIG_LV_USE_FS_POSIX + #define LV_USE_FS_POSIX CONFIG_LV_USE_FS_POSIX + #else + #define LV_USE_FS_POSIX 0 + #endif +#endif +#if LV_USE_FS_POSIX + #ifndef LV_FS_POSIX_LETTER + #ifdef CONFIG_LV_FS_POSIX_LETTER + #define LV_FS_POSIX_LETTER CONFIG_LV_FS_POSIX_LETTER + #else + #define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #endif + #endif + #ifndef LV_FS_POSIX_PATH + #ifdef CONFIG_LV_FS_POSIX_PATH + #define LV_FS_POSIX_PATH CONFIG_LV_FS_POSIX_PATH + #else + #define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #endif + #endif + #ifndef LV_FS_POSIX_CACHE_SIZE + #ifdef CONFIG_LV_FS_POSIX_CACHE_SIZE + #define LV_FS_POSIX_CACHE_SIZE CONFIG_LV_FS_POSIX_CACHE_SIZE + #else + #define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #endif + #endif +#endif + +/*API for CreateFile, ReadFile, etc*/ +#ifndef LV_USE_FS_WIN32 + #ifdef CONFIG_LV_USE_FS_WIN32 + #define LV_USE_FS_WIN32 CONFIG_LV_USE_FS_WIN32 + #else + #define LV_USE_FS_WIN32 0 + #endif +#endif +#if LV_USE_FS_WIN32 + #ifndef LV_FS_WIN32_LETTER + #ifdef CONFIG_LV_FS_WIN32_LETTER + #define LV_FS_WIN32_LETTER CONFIG_LV_FS_WIN32_LETTER + #else + #define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #endif + #endif + #ifndef LV_FS_WIN32_PATH + #ifdef CONFIG_LV_FS_WIN32_PATH + #define LV_FS_WIN32_PATH CONFIG_LV_FS_WIN32_PATH + #else + #define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #endif + #endif + #ifndef LV_FS_WIN32_CACHE_SIZE + #ifdef CONFIG_LV_FS_WIN32_CACHE_SIZE + #define LV_FS_WIN32_CACHE_SIZE CONFIG_LV_FS_WIN32_CACHE_SIZE + #else + #define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #endif + #endif +#endif + +/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/ +#ifndef LV_USE_FS_FATFS + #ifdef CONFIG_LV_USE_FS_FATFS + #define LV_USE_FS_FATFS CONFIG_LV_USE_FS_FATFS + #else + #define LV_USE_FS_FATFS 0 + #endif +#endif +#if LV_USE_FS_FATFS + #ifndef LV_FS_FATFS_LETTER + #ifdef CONFIG_LV_FS_FATFS_LETTER + #define LV_FS_FATFS_LETTER CONFIG_LV_FS_FATFS_LETTER + #else + #define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #endif + #endif + #ifndef LV_FS_FATFS_CACHE_SIZE + #ifdef CONFIG_LV_FS_FATFS_CACHE_SIZE + #define LV_FS_FATFS_CACHE_SIZE CONFIG_LV_FS_FATFS_CACHE_SIZE + #else + #define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ + #endif + #endif +#endif + +/*PNG decoder library*/ +#ifndef LV_USE_PNG + #ifdef CONFIG_LV_USE_PNG + #define LV_USE_PNG CONFIG_LV_USE_PNG + #else + #define LV_USE_PNG 0 + #endif +#endif + +/*BMP decoder library*/ +#ifndef LV_USE_BMP + #ifdef CONFIG_LV_USE_BMP + #define LV_USE_BMP CONFIG_LV_USE_BMP + #else + #define LV_USE_BMP 0 + #endif +#endif + +/* JPG + split JPG decoder library. + * Split JPG is a custom format optimized for embedded systems. */ +#ifndef LV_USE_SJPG + #ifdef CONFIG_LV_USE_SJPG + #define LV_USE_SJPG CONFIG_LV_USE_SJPG + #else + #define LV_USE_SJPG 0 + #endif +#endif + +/*GIF decoder library*/ +#ifndef LV_USE_GIF + #ifdef CONFIG_LV_USE_GIF + #define LV_USE_GIF CONFIG_LV_USE_GIF + #else + #define LV_USE_GIF 0 + #endif +#endif + +/*QR code library*/ +#ifndef LV_USE_QRCODE + #ifdef CONFIG_LV_USE_QRCODE + #define LV_USE_QRCODE CONFIG_LV_USE_QRCODE + #else + #define LV_USE_QRCODE 0 + #endif +#endif + +/*FreeType library*/ +#ifndef LV_USE_FREETYPE + #ifdef CONFIG_LV_USE_FREETYPE + #define LV_USE_FREETYPE CONFIG_LV_USE_FREETYPE + #else + #define LV_USE_FREETYPE 0 + #endif +#endif +#if LV_USE_FREETYPE + /*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/ + #ifndef LV_FREETYPE_CACHE_SIZE + #ifdef CONFIG_LV_FREETYPE_CACHE_SIZE + #define LV_FREETYPE_CACHE_SIZE CONFIG_LV_FREETYPE_CACHE_SIZE + #else + #define LV_FREETYPE_CACHE_SIZE (16 * 1024) + #endif + #endif + #if LV_FREETYPE_CACHE_SIZE >= 0 + /* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */ + /* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */ + /* if font size >= 256, must be configured as image cache */ + #ifndef LV_FREETYPE_SBIT_CACHE + #ifdef CONFIG_LV_FREETYPE_SBIT_CACHE + #define LV_FREETYPE_SBIT_CACHE CONFIG_LV_FREETYPE_SBIT_CACHE + #else + #define LV_FREETYPE_SBIT_CACHE 0 + #endif + #endif + /* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */ + /* (0:use system defaults) */ + #ifndef LV_FREETYPE_CACHE_FT_FACES + #ifdef CONFIG_LV_FREETYPE_CACHE_FT_FACES + #define LV_FREETYPE_CACHE_FT_FACES CONFIG_LV_FREETYPE_CACHE_FT_FACES + #else + #define LV_FREETYPE_CACHE_FT_FACES 0 + #endif + #endif + #ifndef LV_FREETYPE_CACHE_FT_SIZES + #ifdef CONFIG_LV_FREETYPE_CACHE_FT_SIZES + #define LV_FREETYPE_CACHE_FT_SIZES CONFIG_LV_FREETYPE_CACHE_FT_SIZES + #else + #define LV_FREETYPE_CACHE_FT_SIZES 0 + #endif + #endif + #endif +#endif + +/*Rlottie library*/ +#ifndef LV_USE_RLOTTIE + #ifdef CONFIG_LV_USE_RLOTTIE + #define LV_USE_RLOTTIE CONFIG_LV_USE_RLOTTIE + #else + #define LV_USE_RLOTTIE 0 + #endif +#endif + +/*FFmpeg library for image decoding and playing videos + *Supports all major image formats so do not enable other image decoder with it*/ +#ifndef LV_USE_FFMPEG + #ifdef CONFIG_LV_USE_FFMPEG + #define LV_USE_FFMPEG CONFIG_LV_USE_FFMPEG + #else + #define LV_USE_FFMPEG 0 + #endif +#endif +#if LV_USE_FFMPEG + /*Dump input information to stderr*/ + #ifndef LV_FFMPEG_DUMP_FORMAT + #ifdef CONFIG_LV_FFMPEG_DUMP_FORMAT + #define LV_FFMPEG_DUMP_FORMAT CONFIG_LV_FFMPEG_DUMP_FORMAT + #else + #define LV_FFMPEG_DUMP_FORMAT 0 + #endif + #endif +#endif + +/*----------- + * Others + *----------*/ + +/*1: Enable API to take snapshot for object*/ +#ifndef LV_USE_SNAPSHOT + #ifdef CONFIG_LV_USE_SNAPSHOT + #define LV_USE_SNAPSHOT CONFIG_LV_USE_SNAPSHOT + #else + #define LV_USE_SNAPSHOT 0 + #endif +#endif + +/*1: Enable Monkey test*/ +#ifndef LV_USE_MONKEY + #ifdef CONFIG_LV_USE_MONKEY + #define LV_USE_MONKEY CONFIG_LV_USE_MONKEY + #else + #define LV_USE_MONKEY 0 + #endif +#endif + +/*1: Enable grid navigation*/ +#ifndef LV_USE_GRIDNAV + #ifdef CONFIG_LV_USE_GRIDNAV + #define LV_USE_GRIDNAV CONFIG_LV_USE_GRIDNAV + #else + #define LV_USE_GRIDNAV 0 + #endif +#endif + +/*1: Enable lv_obj fragment*/ +#ifndef LV_USE_FRAGMENT + #ifdef CONFIG_LV_USE_FRAGMENT + #define LV_USE_FRAGMENT CONFIG_LV_USE_FRAGMENT + #else + #define LV_USE_FRAGMENT 0 + #endif +#endif + +/*1: Support using images as font in label or span widgets */ +#ifndef LV_USE_IMGFONT + #ifdef CONFIG_LV_USE_IMGFONT + #define LV_USE_IMGFONT CONFIG_LV_USE_IMGFONT + #else + #define LV_USE_IMGFONT 0 + #endif +#endif + +/*1: Enable a published subscriber based messaging system */ +#ifndef LV_USE_MSG + #ifdef CONFIG_LV_USE_MSG + #define LV_USE_MSG CONFIG_LV_USE_MSG + #else + #define LV_USE_MSG 0 + #endif +#endif + +/*1: Enable Pinyin input method*/ +/*Requires: lv_keyboard*/ +#ifndef LV_USE_IME_PINYIN + #ifdef CONFIG_LV_USE_IME_PINYIN + #define LV_USE_IME_PINYIN CONFIG_LV_USE_IME_PINYIN + #else + #define LV_USE_IME_PINYIN 0 + #endif +#endif +#if LV_USE_IME_PINYIN + /*1: Use default thesaurus*/ + /*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/ + #ifndef LV_IME_PINYIN_USE_DEFAULT_DICT + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_IME_PINYIN_USE_DEFAULT_DICT + #define LV_IME_PINYIN_USE_DEFAULT_DICT CONFIG_LV_IME_PINYIN_USE_DEFAULT_DICT + #else + #define LV_IME_PINYIN_USE_DEFAULT_DICT 0 + #endif + #else + #define LV_IME_PINYIN_USE_DEFAULT_DICT 1 + #endif + #endif + /*Set the maximum number of candidate panels that can be displayed*/ + /*This needs to be adjusted according to the size of the screen*/ + #ifndef LV_IME_PINYIN_CAND_TEXT_NUM + #ifdef CONFIG_LV_IME_PINYIN_CAND_TEXT_NUM + #define LV_IME_PINYIN_CAND_TEXT_NUM CONFIG_LV_IME_PINYIN_CAND_TEXT_NUM + #else + #define LV_IME_PINYIN_CAND_TEXT_NUM 6 + #endif + #endif + + /*Use 9 key input(k9)*/ + #ifndef LV_IME_PINYIN_USE_K9_MODE + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_IME_PINYIN_USE_K9_MODE + #define LV_IME_PINYIN_USE_K9_MODE CONFIG_LV_IME_PINYIN_USE_K9_MODE + #else + #define LV_IME_PINYIN_USE_K9_MODE 0 + #endif + #else + #define LV_IME_PINYIN_USE_K9_MODE 1 + #endif + #endif + #if LV_IME_PINYIN_USE_K9_MODE == 1 + #ifndef LV_IME_PINYIN_K9_CAND_TEXT_NUM + #ifdef CONFIG_LV_IME_PINYIN_K9_CAND_TEXT_NUM + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM CONFIG_LV_IME_PINYIN_K9_CAND_TEXT_NUM + #else + #define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3 + #endif + #endif + #endif // LV_IME_PINYIN_USE_K9_MODE +#endif + +/*================== +* EXAMPLES +*==================*/ + +/*Enable the examples to be built with the library*/ +#ifndef LV_BUILD_EXAMPLES + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_BUILD_EXAMPLES + #define LV_BUILD_EXAMPLES CONFIG_LV_BUILD_EXAMPLES + #else + #define LV_BUILD_EXAMPLES 0 + #endif + #else + #define LV_BUILD_EXAMPLES 1 + #endif +#endif + +/*=================== + * DEMO USAGE + ====================*/ + +/*Show some widget. It might be required to increase `LV_MEM_SIZE` */ +#ifndef LV_USE_DEMO_WIDGETS + #ifdef CONFIG_LV_USE_DEMO_WIDGETS + #define LV_USE_DEMO_WIDGETS CONFIG_LV_USE_DEMO_WIDGETS + #else + #define LV_USE_DEMO_WIDGETS 0 + #endif +#endif +#if LV_USE_DEMO_WIDGETS +#ifndef LV_DEMO_WIDGETS_SLIDESHOW + #ifdef CONFIG_LV_DEMO_WIDGETS_SLIDESHOW + #define LV_DEMO_WIDGETS_SLIDESHOW CONFIG_LV_DEMO_WIDGETS_SLIDESHOW + #else + #define LV_DEMO_WIDGETS_SLIDESHOW 0 + #endif +#endif +#endif + +/*Demonstrate the usage of encoder and keyboard*/ +#ifndef LV_USE_DEMO_KEYPAD_AND_ENCODER + #ifdef CONFIG_LV_USE_DEMO_KEYPAD_AND_ENCODER + #define LV_USE_DEMO_KEYPAD_AND_ENCODER CONFIG_LV_USE_DEMO_KEYPAD_AND_ENCODER + #else + #define LV_USE_DEMO_KEYPAD_AND_ENCODER 0 + #endif +#endif + +/*Benchmark your system*/ +#ifndef LV_USE_DEMO_BENCHMARK + #ifdef CONFIG_LV_USE_DEMO_BENCHMARK + #define LV_USE_DEMO_BENCHMARK CONFIG_LV_USE_DEMO_BENCHMARK + #else + #define LV_USE_DEMO_BENCHMARK 0 + #endif +#endif +#if LV_USE_DEMO_BENCHMARK +/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/ +#ifndef LV_DEMO_BENCHMARK_RGB565A8 + #ifdef CONFIG_LV_DEMO_BENCHMARK_RGB565A8 + #define LV_DEMO_BENCHMARK_RGB565A8 CONFIG_LV_DEMO_BENCHMARK_RGB565A8 + #else + #define LV_DEMO_BENCHMARK_RGB565A8 0 + #endif +#endif +#endif + +/*Stress test for LVGL*/ +#ifndef LV_USE_DEMO_STRESS + #ifdef CONFIG_LV_USE_DEMO_STRESS + #define LV_USE_DEMO_STRESS CONFIG_LV_USE_DEMO_STRESS + #else + #define LV_USE_DEMO_STRESS 0 + #endif +#endif + +/*Music player demo*/ +#ifndef LV_USE_DEMO_MUSIC + #ifdef CONFIG_LV_USE_DEMO_MUSIC + #define LV_USE_DEMO_MUSIC CONFIG_LV_USE_DEMO_MUSIC + #else + #define LV_USE_DEMO_MUSIC 0 + #endif +#endif +#if LV_USE_DEMO_MUSIC + #ifndef LV_DEMO_MUSIC_SQUARE + #ifdef CONFIG_LV_DEMO_MUSIC_SQUARE + #define LV_DEMO_MUSIC_SQUARE CONFIG_LV_DEMO_MUSIC_SQUARE + #else + #define LV_DEMO_MUSIC_SQUARE 0 + #endif + #endif + #ifndef LV_DEMO_MUSIC_LANDSCAPE + #ifdef CONFIG_LV_DEMO_MUSIC_LANDSCAPE + #define LV_DEMO_MUSIC_LANDSCAPE CONFIG_LV_DEMO_MUSIC_LANDSCAPE + #else + #define LV_DEMO_MUSIC_LANDSCAPE 0 + #endif + #endif + #ifndef LV_DEMO_MUSIC_ROUND + #ifdef CONFIG_LV_DEMO_MUSIC_ROUND + #define LV_DEMO_MUSIC_ROUND CONFIG_LV_DEMO_MUSIC_ROUND + #else + #define LV_DEMO_MUSIC_ROUND 0 + #endif + #endif + #ifndef LV_DEMO_MUSIC_LARGE + #ifdef CONFIG_LV_DEMO_MUSIC_LARGE + #define LV_DEMO_MUSIC_LARGE CONFIG_LV_DEMO_MUSIC_LARGE + #else + #define LV_DEMO_MUSIC_LARGE 0 + #endif + #endif + #ifndef LV_DEMO_MUSIC_AUTO_PLAY + #ifdef CONFIG_LV_DEMO_MUSIC_AUTO_PLAY + #define LV_DEMO_MUSIC_AUTO_PLAY CONFIG_LV_DEMO_MUSIC_AUTO_PLAY + #else + #define LV_DEMO_MUSIC_AUTO_PLAY 0 + #endif + #endif +#endif + + + +/*---------------------------------- + * End of parsing lv_conf_template.h + -----------------------------------*/ + +LV_EXPORT_CONST_INT(LV_DPI_DEF); + +#undef _LV_KCONFIG_PRESENT + + +/*Set some defines if a dependency is disabled*/ +#if LV_USE_LOG == 0 + #define LV_LOG_LEVEL LV_LOG_LEVEL_NONE + #define LV_LOG_TRACE_MEM 0 + #define LV_LOG_TRACE_TIMER 0 + #define LV_LOG_TRACE_INDEV 0 + #define LV_LOG_TRACE_DISP_REFR 0 + #define LV_LOG_TRACE_EVENT 0 + #define LV_LOG_TRACE_OBJ_CREATE 0 + #define LV_LOG_TRACE_LAYOUT 0 + #define LV_LOG_TRACE_ANIM 0 +#endif /*LV_USE_LOG*/ + + +/*If running without lv_conf.h add typedefs with default value*/ +#ifdef LV_CONF_SKIP + #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /*Disable warnings for Visual Studio*/ + #define _CRT_SECURE_NO_WARNINGS + #endif +#endif /*defined(LV_CONF_SKIP)*/ + +#endif /*LV_CONF_INTERNAL_H*/ diff --git a/include/liblvgl/lv_conf_kconfig.h b/include/liblvgl/lv_conf_kconfig.h new file mode 100644 index 0000000..7742fe7 --- /dev/null +++ b/include/liblvgl/lv_conf_kconfig.h @@ -0,0 +1,182 @@ +/** * @file lv_conf_kconfig.h * Configs that need special handling when LVGL is used with Kconfig */ + +#ifndef LV_CONF_KCONFIG_H +#define LV_CONF_KCONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LV_CONF_KCONFIG_EXTERNAL_INCLUDE +# include LV_CONF_KCONFIG_EXTERNAL_INCLUDE +#else + +# ifdef ESP_PLATFORM +# include "sdkconfig.h" +# include "esp_attr.h" +# endif + +# ifdef __NuttX__ +# include +# elif defined(__RTTHREAD__) +# define LV_CONF_INCLUDE_SIMPLE +# include +# endif + +#endif /*LV_CONF_KCONFIG_EXTERNAL_INCLUDE*/ + +/******************* + * LV COLOR CHROMA KEY + *******************/ + +#ifdef CONFIG_LV_COLOR_CHROMA_KEY_HEX +# define CONFIG_LV_COLOR_CHROMA_KEY lv_color_hex(CONFIG_LV_COLOR_CHROMA_KEY_HEX) +#endif + +/******************* + * LV_MEM_SIZE + *******************/ + +#ifdef CONFIG_LV_MEM_SIZE_KILOBYTES +# define CONFIG_LV_MEM_SIZE (CONFIG_LV_MEM_SIZE_KILOBYTES * 1024U) +#endif + +/*------------------ + * MONITOR POSITION + *-----------------*/ + +#ifdef CONFIG_LV_PERF_MONITOR_ALIGN_TOP_LEFT +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_TOP_LEFT +#elif defined(CONFIG_LV_USE_PERF_MONITOR_ALIGN_TOP_MID) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_TOP_MID +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_TOP_RIGHT) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_TOP_RIGHT +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_BOTTOM_LEFT) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_LEFT +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_BOTTOM_MID) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_MID +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_BOTTOM_RIGHT) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_LEFT_MID) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_LEFT_MID +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_RIGHT_MID) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_RIGHT_MID +#elif defined(CONFIG_LV_PERF_MONITOR_ALIGN_CENTER) +# define CONFIG_LV_USE_PERF_MONITOR_POS LV_ALIGN_CENTER +#endif + +#ifdef CONFIG_LV_MEM_MONITOR_ALIGN_TOP_LEFT +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_TOP_LEFT +#elif defined(CONFIG_LV_USE_MEM_MONITOR_ALIGN_TOP_MID) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_TOP_MID +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_TOP_RIGHT) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_TOP_RIGHT +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_BOTTOM_LEFT) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_BOTTOM_MID) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_MID +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_BOTTOM_RIGHT) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_LEFT_MID) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_LEFT_MID +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_RIGHT_MID) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_RIGHT_MID +#elif defined(CONFIG_LV_MEM_MONITOR_ALIGN_CENTER) +# define CONFIG_LV_USE_MEM_MONITOR_POS LV_ALIGN_CENTER +#endif + +/******************** + * FONT SELECTION + *******************/ + +/** + * NOTE: In Kconfig instead of `LV_DEFAULT_FONT` + * `CONFIG_LV_FONT_DEFAULT_` is defined + * hence the large selection with if-s + */ + +/*------------------ + * DEFAULT FONT + *-----------------*/ +#ifdef CONFIG_LV_FONT_DEFAULT_MONTSERRAT_8 +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_8 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_10) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_10 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_12) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_12 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_14) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_14 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_16) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_16 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_18) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_18 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_20) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_20 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_22) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_22 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_24) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_24 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_26) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_26 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_28) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_28 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_30) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_30 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_32) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_32 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_34) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_34 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_36) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_36 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_38) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_38 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_40) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_40 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_42) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_42 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_44) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_44 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_46) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_46 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_48) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_48 +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_12_SUBPX) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_12_subpx +#elif defined(CONFIG_LV_FONT_DEFAULT_MONTSERRAT_28_COMPRESSED) +# define CONFIG_LV_FONT_DEFAULT &lv_font_montserrat_28_compressed +#elif defined(CONFIG_LV_FONT_DEFAULT_DEJAVU_16_PERSIAN_HEBREW) +# define CONFIG_LV_FONT_DEFAULT &lv_font_dejavu_16_persian_hebrew +#elif defined(CONFIG_LV_FONT_DEFAULT_SIMSUN_16_CJK) +# define CONFIG_LV_FONT_DEFAULT &lv_font_simsun_16_cjk +#elif defined(CONFIG_LV_FONT_DEFAULT_UNSCII_8) +# define CONFIG_LV_FONT_DEFAULT &lv_font_unscii_8 +#elif defined(CONFIG_LV_FONT_DEFAULT_UNSCII_16) +# define CONFIG_LV_FONT_DEFAULT &lv_font_unscii_16 +#endif + +/*------------------ + * TEXT ENCODING + *-----------------*/ +#ifdef CONFIG_LV_TXT_ENC_UTF8 +# define CONFIG_LV_TXT_ENC LV_TXT_ENC_UTF8 +#elif defined(CONFIG_LV_TXT_ENC_ASCII) +# define CONFIG_LV_TXT_ENC LV_TXT_ENC_ASCII +#endif + +/*------------------ + * BIDI DIRECTION + *-----------------*/ + +#ifdef CONFIG_LV_BASE_DIR_LTR +# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_LTR +#elif defined(CONFIG_LV_BASE_DIR_RTL) +# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_RTL +#elif defined(CONFIG_LV_BASE_DIR_AUTO) +# define CONFIG_LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CONF_KCONFIG_H*/ diff --git a/include/liblvgl/lv_version.h b/include/liblvgl/lv_version.h new file mode 100644 index 0000000..1e62e1e --- /dev/null +++ b/include/liblvgl/lv_version.h @@ -0,0 +1,66 @@ +/** + * @file lv_version.h + * + */ + +#ifndef LV_VERSION_H +#define LV_VERSION_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +/*Current version of LittlevGL*/ +#define LVGL_VERSION_MAJOR 5 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 0 +#define LVGL_VERSION_INFO "" + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ +/* Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + * */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VERSION_H*/ diff --git a/include/liblvgl/lvgl.h b/include/liblvgl/lvgl.h new file mode 100644 index 0000000..60d29f5 --- /dev/null +++ b/include/liblvgl/lvgl.h @@ -0,0 +1,138 @@ +/** + * @file lvgl.h + * Include all LVGL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************** + * CURRENT VERSION OF LVGL + ***************************/ +#define LVGL_VERSION_MAJOR 8 +#define LVGL_VERSION_MINOR 3 +#define LVGL_VERSION_PATCH 4 +#define LVGL_VERSION_INFO "dev" + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/misc/lv_log.h" +#include "liblvgl/misc/lv_timer.h" +#include "liblvgl/misc/lv_math.h" +#include "liblvgl/misc/lv_mem.h" +#include "liblvgl/misc/lv_async.h" +#include "liblvgl/misc/lv_anim_timeline.h" +#include "liblvgl/misc/lv_printf.h" + +#include "liblvgl/hal/lv_hal.h" + +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/core/lv_group.h" +#include "liblvgl/core/lv_indev.h" +#include "liblvgl/core/lv_refr.h" +#include "liblvgl/core/lv_disp.h" +#include "liblvgl/core/lv_theme.h" + +#include "liblvgl/font/lv_font.h" +#include "liblvgl/font/lv_font_loader.h" +#include "liblvgl/font/lv_font_fmt_txt.h" + +#include "liblvgl/widgets/lv_arc.h" +#include "liblvgl/widgets/lv_btn.h" +#include "liblvgl/widgets/lv_img.h" +#include "liblvgl/widgets/lv_label.h" +#include "liblvgl/widgets/lv_line.h" +#include "liblvgl/widgets/lv_table.h" +#include "liblvgl/widgets/lv_checkbox.h" +#include "liblvgl/widgets/lv_bar.h" +#include "liblvgl/widgets/lv_slider.h" +#include "liblvgl/widgets/lv_btnmatrix.h" +#include "liblvgl/widgets/lv_dropdown.h" +#include "liblvgl/widgets/lv_roller.h" +#include "liblvgl/widgets/lv_textarea.h" +#include "liblvgl/widgets/lv_canvas.h" +#include "liblvgl/widgets/lv_switch.h" + +#include "liblvgl/draw/lv_draw.h" + +#include "liblvgl/lv_api_map.h" + +/*----------------- + * EXTRAS + *----------------*/ +#include "liblvgl/extra/lv_extra.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +/** Gives 1 if the x.y.z version is supported in the current version + * Usage: + * + * - Require v6 + * #if LV_VERSION_CHECK(6,0,0) + * new_func_in_v6(); + * #endif + * + * + * - Require at least v5.3 + * #if LV_VERSION_CHECK(5,3,0) + * new_feature_from_v5_3(); + * #endif + * + * + * - Require v5.3.2 bugfixes + * #if LV_VERSION_CHECK(5,3,2) + * bugfix_in_v5_3_2(); + * #endif + * + */ +#define LV_VERSION_CHECK(x,y,z) (x == LVGL_VERSION_MAJOR && (y < LVGL_VERSION_MINOR || (y == LVGL_VERSION_MINOR && z <= LVGL_VERSION_PATCH))) + +/** + * Wrapper functions for VERSION macros + */ + +static inline int lv_version_major(void) +{ + return LVGL_VERSION_MAJOR; +} + +static inline int lv_version_minor(void) +{ + return LVGL_VERSION_MINOR; +} + +static inline int lv_version_patch(void) +{ + return LVGL_VERSION_PATCH; +} + +static inline const char *lv_version_info(void) +{ + return LVGL_VERSION_INFO; +} + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LVGL_H*/ diff --git a/include/liblvgl/misc/lv_anim.h b/include/liblvgl/misc/lv_anim.h new file mode 100644 index 0000000..cb460ab --- /dev/null +++ b/include/liblvgl/misc/lv_anim.h @@ -0,0 +1,484 @@ +/** + * @file lv_anim.h + * + */ + +#ifndef LV_ANIM_H +#define LV_ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +#define LV_ANIM_REPEAT_INFINITE 0xFFFF +#define LV_ANIM_PLAYTIME_INFINITE 0xFFFFFFFF + +LV_EXPORT_CONST_INT(LV_ANIM_REPEAT_INFINITE); +LV_EXPORT_CONST_INT(LV_ANIM_PLAYTIME_INFINITE); + +/********************** + * TYPEDEFS + **********************/ + +/** Can be used to indicate if animations are enabled or disabled in a case*/ +typedef enum { + LV_ANIM_OFF, + LV_ANIM_ON, +} lv_anim_enable_t; + +struct _lv_anim_t; +struct _lv_timer_t; + +/** Get the current value during an animation*/ +typedef int32_t (*lv_anim_path_cb_t)(const struct _lv_anim_t *); + +/** Generic prototype of "animator" functions. + * First parameter is the variable to animate. + * Second parameter is the value to set. + * Compatible with `lv_xxx_set_yyy(obj, value)` functions + * The `x` in `_xcb_t` means it's not a fully generic prototype because + * it doesn't receive `lv_anim_t *` as its first argument*/ +typedef void (*lv_anim_exec_xcb_t)(void *, int32_t); + +/** Same as `lv_anim_exec_xcb_t` but receives `lv_anim_t *` as the first parameter. + * It's more consistent but less convenient. Might be used by binding generator functions.*/ +typedef void (*lv_anim_custom_exec_cb_t)(struct _lv_anim_t *, int32_t); + +/** Callback to call when the animation is ready*/ +typedef void (*lv_anim_ready_cb_t)(struct _lv_anim_t *); + +/** Callback to call when the animation really stars (considering `delay`)*/ +typedef void (*lv_anim_start_cb_t)(struct _lv_anim_t *); + +/** Callback used when the animation values are relative to get the current value*/ +typedef int32_t (*lv_anim_get_value_cb_t)(struct _lv_anim_t *); + +/** Callback used when the animation is deleted*/ +typedef void (*lv_anim_deleted_cb_t)(struct _lv_anim_t *); + +/** Describes an animation*/ +typedef struct _lv_anim_t { + void * var; /**var = var; +} + +/** + * Set a function to animate `var` + * @param a pointer to an initialized `lv_anim_t` variable + * @param exec_cb a function to execute during animation + * LVGL's built-in functions can be used. + * E.g. lv_obj_set_x + */ +static inline void lv_anim_set_exec_cb(lv_anim_t * a, lv_anim_exec_xcb_t exec_cb) +{ + a->exec_cb = exec_cb; +} + +/** + * Set the duration of an animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param duration duration of the animation in milliseconds + */ +static inline void lv_anim_set_time(lv_anim_t * a, uint32_t duration) +{ + a->time = duration; +} + +/** + * Set a delay before starting the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay before the animation in milliseconds + */ +static inline void lv_anim_set_delay(lv_anim_t * a, uint32_t delay) +{ + a->act_time = -(int32_t)(delay); +} + +/** + * Set the start and end values of an animation + * @param a pointer to an initialized `lv_anim_t` variable + * @param start the start value + * @param end the end value + */ +static inline void lv_anim_set_values(lv_anim_t * a, int32_t start, int32_t end) +{ + a->start_value = start; + a->current_value = start; + a->end_value = end; +} + +/** + * Similar to `lv_anim_set_exec_cb` but `lv_anim_custom_exec_cb_t` receives + * `lv_anim_t * ` as its first parameter instead of `void *`. + * This function might be used when LVGL is bound to other languages because + * it's more consistent to have `lv_anim_t *` as first parameter. + * The variable to animate can be stored in the animation's `user_data` + * @param a pointer to an initialized `lv_anim_t` variable + * @param exec_cb a function to execute. + */ +static inline void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb) +{ + a->var = a; + a->exec_cb = (lv_anim_exec_xcb_t)exec_cb; +} + +/** + * Set the path (curve) of the animation. + * @param a pointer to an initialized `lv_anim_t` variable + * @param path_cb a function to set the current value of the animation. + */ +static inline void lv_anim_set_path_cb(lv_anim_t * a, lv_anim_path_cb_t path_cb) +{ + a->path_cb = path_cb; +} + +/** + * Set a function call when the animation really starts (considering `delay`) + * @param a pointer to an initialized `lv_anim_t` variable + * @param start_cb a function call when the animation starts + */ +static inline void lv_anim_set_start_cb(lv_anim_t * a, lv_anim_start_cb_t start_cb) +{ + a->start_cb = start_cb; +} + +/** + * Set a function to use the current value of the variable and make start and end value + * relative to the returned current value. + * @param a pointer to an initialized `lv_anim_t` variable + * @param get_value_cb a function call when the animation starts + */ +static inline void lv_anim_set_get_value_cb(lv_anim_t * a, lv_anim_get_value_cb_t get_value_cb) +{ + a->get_value_cb = get_value_cb; +} + +/** + * Set a function call when the animation is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param ready_cb a function call when the animation is ready + */ +static inline void lv_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_cb) +{ + a->ready_cb = ready_cb; +} + +/** + * Set a function call when the animation is deleted. + * @param a pointer to an initialized `lv_anim_t` variable + * @param deleted_cb a function call when the animation is deleted + */ +static inline void lv_anim_set_deleted_cb(lv_anim_t * a, lv_anim_deleted_cb_t deleted_cb) +{ + a->deleted_cb = deleted_cb; +} + +/** + * Make the animation to play back to when the forward direction is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param time the duration of the playback animation in milliseconds. 0: disable playback + */ +static inline void lv_anim_set_playback_time(lv_anim_t * a, uint32_t time) +{ + a->playback_time = time; +} + +/** + * Make the animation to play back to when the forward direction is ready + * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay in milliseconds before starting the playback animation. + */ +static inline void lv_anim_set_playback_delay(lv_anim_t * a, uint32_t delay) +{ + a->playback_delay = delay; +} + +/** + * Make the animation repeat itself. + * @param a pointer to an initialized `lv_anim_t` variable + * @param cnt repeat count or `LV_ANIM_REPEAT_INFINITE` for infinite repetition. 0: to disable repetition. + */ +static inline void lv_anim_set_repeat_count(lv_anim_t * a, uint16_t cnt) +{ + a->repeat_cnt = cnt; +} + +/** + * Set a delay before repeating the animation. + * @param a pointer to an initialized `lv_anim_t` variable + * @param delay delay in milliseconds before repeating the animation. + */ +static inline void lv_anim_set_repeat_delay(lv_anim_t * a, uint32_t delay) +{ + a->repeat_delay = delay; +} + +/** + * Set a whether the animation's should be applied immediately or only when the delay expired. + * @param a pointer to an initialized `lv_anim_t` variable + * @param en true: apply the start value immediately in `lv_anim_start`; + * false: apply the start value only when `delay` ms is elapsed and the animations really starts + */ +static inline void lv_anim_set_early_apply(lv_anim_t * a, bool en) +{ + a->early_apply = en; +} + +/** + * Set the custom user data field of the animation. + * @param a pointer to an initialized `lv_anim_t` variable + * @param user_data pointer to the new user_data. + */ +#if LV_USE_USER_DATA +static inline void lv_anim_set_user_data(lv_anim_t * a, void * user_data) +{ + a->user_data = user_data; +} +#endif + +/** + * Create an animation + * @param a an initialized 'anim_t' variable. Not required after call. + * @return pointer to the created animation (different from the `a` parameter) + */ +lv_anim_t * lv_anim_start(const lv_anim_t * a); + +/** + * Get a delay before starting the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @return delay before the animation in milliseconds + */ +static inline uint32_t lv_anim_get_delay(lv_anim_t * a) +{ + return -a->act_time; +} + +/** + * Get the time used to play the animation. + * @param a pointer to an animation. + * @return the play time in milliseconds. + */ +uint32_t lv_anim_get_playtime(lv_anim_t * a); + +/** + * Get the user_data field of the animation + * @param a pointer to an initialized `lv_anim_t` variable + * @return the pointer to the custom user_data of the animation + */ +#if LV_USE_USER_DATA +static inline void * lv_anim_get_user_data(lv_anim_t * a) +{ + return a->user_data; +} +#endif + +/** + * Delete an animation of a variable with a given animator function + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', + * or NULL to ignore it and delete all the animations of 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb); + +/** + * Delete all the animations + */ +void lv_anim_del_all(void); + +/** + * Get the animation of a variable and its `exec_cb`. + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', or NULL to return first matching 'var' + * @return pointer to the animation. + */ +lv_anim_t * lv_anim_get(void * var, lv_anim_exec_xcb_t exec_cb); + +/** + * Get global animation refresher timer. + * @return pointer to the animation refresher timer. + */ +struct _lv_timer_t * lv_anim_get_timer(void); + +/** + * Delete an animation by getting the animated variable from `a`. + * Only animations with `exec_cb` will be deleted. + * This function exists because it's logical that all anim. functions receives an + * `lv_anim_t` as their first parameter. It's not practical in C but might make + * the API more consequent and makes easier to generate bindings. + * @param a pointer to an animation. + * @param exec_cb a function pointer which is animating 'var', + * or NULL to ignore it and delete all the animations of 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +static inline bool lv_anim_custom_del(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb) +{ + return lv_anim_del(a ? a->var : NULL, (lv_anim_exec_xcb_t)exec_cb); +} + +/** + * Get the animation of a variable and its `exec_cb`. + * This function exists because it's logical that all anim. functions receives an + * `lv_anim_t` as their first parameter. It's not practical in C but might make + * the API more consequent and makes easier to generate bindings. + * @param a pointer to an animation. + * @param exec_cb a function pointer which is animating 'var', or NULL to return first matching 'var' + * @return pointer to the animation. + */ +static inline lv_anim_t * lv_anim_custom_get(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb) +{ + return lv_anim_get(a ? a->var : NULL, (lv_anim_exec_xcb_t)exec_cb); +} + +/** + * Get the number of currently running animations + * @return the number of running animations + */ +uint16_t lv_anim_count_running(void); + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint32_t lv_anim_speed_to_time(uint32_t speed, int32_t start, int32_t end); + +/** + * Manually refresh the state of the animations. + * Useful to make the animations running in a blocking process where + * `lv_timer_handler` can't run for a while. + * Shouldn't be used directly because it is called in `lv_refr_now()`. + */ +void lv_anim_refr_now(void); + +/** + * Calculate the current value of an animation applying linear characteristic + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_linear(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the start phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in(const lv_anim_t * a); + +/** + * Calculate the current value of an animation slowing down the end phase + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying an "S" characteristic (cosine) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_ease_in_out(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + +/** + * Calculate the current value of an animation with 3 bounces + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_bounce(const lv_anim_t * a); + +/** + * Calculate the current value of an animation applying step characteristic. + * (Set end value on the end of the animation) + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_step(const lv_anim_t * a); + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ANIM_H*/ diff --git a/include/liblvgl/misc/lv_anim_timeline.h b/include/liblvgl/misc/lv_anim_timeline.h new file mode 100644 index 0000000..d4dd0fc --- /dev/null +++ b/include/liblvgl/misc/lv_anim_timeline.h @@ -0,0 +1,103 @@ +/** + * @file lv_anim_timeline.h + * + */ + +#ifndef LV_ANIM_TIMELINE_H +#define LV_ANIM_TIMELINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_anim.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_timeline_t; + +typedef struct _lv_anim_timeline_t lv_anim_timeline_t; + +/********************** +* GLOBAL PROTOTYPES +**********************/ + +/** + * Create an animation timeline. + * @return pointer to the animation timeline. + */ +lv_anim_timeline_t * lv_anim_timeline_create(void); + +/** + * Delete animation timeline. + * @param at pointer to the animation timeline. + */ +void lv_anim_timeline_del(lv_anim_timeline_t * at); + +/** + * Add animation to the animation timeline. + * @param at pointer to the animation timeline. + * @param start_time the time the animation started on the timeline, note that start_time will override the value of delay. + * @param a pointer to an animation. + */ +void lv_anim_timeline_add(lv_anim_timeline_t * at, uint32_t start_time, lv_anim_t * a); + +/** + * Start the animation timeline. + * @param at pointer to the animation timeline. + * @return total time spent in animation timeline. + */ +uint32_t lv_anim_timeline_start(lv_anim_timeline_t * at); + +/** + * Stop the animation timeline. + * @param at pointer to the animation timeline. + */ +void lv_anim_timeline_stop(lv_anim_timeline_t * at); + +/** + * Set the playback direction of the animation timeline. + * @param at pointer to the animation timeline. + * @param reverse whether to play in reverse. + */ +void lv_anim_timeline_set_reverse(lv_anim_timeline_t * at, bool reverse); + +/** + * Set the progress of the animation timeline. + * @param at pointer to the animation timeline. + * @param progress set value 0~65535 to map 0~100% animation progress. + */ +void lv_anim_timeline_set_progress(lv_anim_timeline_t * at, uint16_t progress); + +/** + * Get the time used to play the animation timeline. + * @param at pointer to the animation timeline. + * @return total time spent in animation timeline. + */ +uint32_t lv_anim_timeline_get_playtime(lv_anim_timeline_t * at); + +/** + * Get whether the animation timeline is played in reverse. + * @param at pointer to the animation timeline. + * @return return true if it is reverse playback. + */ +bool lv_anim_timeline_get_reverse(lv_anim_timeline_t * at); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ANIM_TIMELINE_H*/ diff --git a/include/liblvgl/misc/lv_area.h b/include/liblvgl/misc/lv_area.h new file mode 100644 index 0000000..036767b --- /dev/null +++ b/include/liblvgl/misc/lv_area.h @@ -0,0 +1,295 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include +#include + +/********************* + * DEFINES + *********************/ + +#if LV_USE_LARGE_COORD +typedef int32_t lv_coord_t; +#else +typedef int16_t lv_coord_t; +#endif + +/********************** + * TYPEDEFS + **********************/ + +/** + * Represents a point on the screen. + */ +typedef struct { + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +/** Represents an area of the screen.*/ +typedef struct { + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_t; + +/** Alignments*/ +enum { + LV_ALIGN_DEFAULT = 0, + LV_ALIGN_TOP_LEFT, + LV_ALIGN_TOP_MID, + LV_ALIGN_TOP_RIGHT, + LV_ALIGN_BOTTOM_LEFT, + LV_ALIGN_BOTTOM_MID, + LV_ALIGN_BOTTOM_RIGHT, + LV_ALIGN_LEFT_MID, + LV_ALIGN_RIGHT_MID, + LV_ALIGN_CENTER, + + LV_ALIGN_OUT_TOP_LEFT, + LV_ALIGN_OUT_TOP_MID, + LV_ALIGN_OUT_TOP_RIGHT, + LV_ALIGN_OUT_BOTTOM_LEFT, + LV_ALIGN_OUT_BOTTOM_MID, + LV_ALIGN_OUT_BOTTOM_RIGHT, + LV_ALIGN_OUT_LEFT_TOP, + LV_ALIGN_OUT_LEFT_MID, + LV_ALIGN_OUT_LEFT_BOTTOM, + LV_ALIGN_OUT_RIGHT_TOP, + LV_ALIGN_OUT_RIGHT_MID, + LV_ALIGN_OUT_RIGHT_BOTTOM, +}; +typedef uint8_t lv_align_t; + +enum { + LV_DIR_NONE = 0x00, + LV_DIR_LEFT = (1 << 0), + LV_DIR_RIGHT = (1 << 1), + LV_DIR_TOP = (1 << 2), + LV_DIR_BOTTOM = (1 << 3), + LV_DIR_HOR = LV_DIR_LEFT | LV_DIR_RIGHT, + LV_DIR_VER = LV_DIR_TOP | LV_DIR_BOTTOM, + LV_DIR_ALL = LV_DIR_HOR | LV_DIR_VER, +}; + +typedef uint8_t lv_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an area + * @param area_p pointer to an area + * @param x1 left coordinate of the area + * @param y1 top coordinate of the area + * @param x2 right coordinate of the area + * @param y2 bottom coordinate of the area + */ +void lv_area_set(lv_area_t * area_p, lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2); + +/** + * Copy an area + * @param dest pointer to the destination area + * @param src pointer to the source area + */ +inline static void lv_area_copy(lv_area_t * dest, const lv_area_t * src) +{ + dest->x1 = src->x1; + dest->y1 = src->y1; + dest->x2 = src->x2; + dest->y2 = src->y2; +} + +/** + * Get the width of an area + * @param area_p pointer to an area + * @return the width of the area (if x1 == x2 -> width = 1) + */ +static inline lv_coord_t lv_area_get_width(const lv_area_t * area_p) +{ + return (lv_coord_t)(area_p->x2 - area_p->x1 + 1); +} + +/** + * Get the height of an area + * @param area_p pointer to an area + * @return the height of the area (if y1 == y2 -> height = 1) + */ +static inline lv_coord_t lv_area_get_height(const lv_area_t * area_p) +{ + return (lv_coord_t)(area_p->y2 - area_p->y1 + 1); +} + +/** + * Set the width of an area + * @param area_p pointer to an area + * @param w the new width of the area (w == 1 makes x1 == x2) + */ +void lv_area_set_width(lv_area_t * area_p, lv_coord_t w); + +/** + * Set the height of an area + * @param area_p pointer to an area + * @param h the new height of the area (h == 1 makes y1 == y2) + */ +void lv_area_set_height(lv_area_t * area_p, lv_coord_t h); + +/** + * Set the position of an area (width and height will be kept) + * @param area_p pointer to an area + * @param x the new x coordinate of the area + * @param y the new y coordinate of the area + */ +void _lv_area_set_pos(lv_area_t * area_p, lv_coord_t x, lv_coord_t y); + +/** + * Return with area of an area (x * y) + * @param area_p pointer to an area + * @return size of area + */ +uint32_t lv_area_get_size(const lv_area_t * area_p); + +void lv_area_increase(lv_area_t * area, lv_coord_t w_extra, lv_coord_t h_extra); + +void lv_area_move(lv_area_t * area, lv_coord_t x_ofs, lv_coord_t y_ofs); + +/** + * Get the common parts of two areas + * @param res_p pointer to an area, the result will be stored her + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + * @return false: the two area has NO common parts, res_p is invalid + */ +bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Join two areas into a third which involves the other two + * @param res_p pointer to an area, the result will be stored here + * @param a1_p pointer to the first area + * @param a2_p pointer to the second area + */ +void _lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if a point is on an area + * @param a_p pointer to an area + * @param p_p pointer to a point + * @param radius radius of area (e.g. for rounded rectangle) + * @return false:the point is out of the area + */ +bool _lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, lv_coord_t radius); + +/** + * Check if two area has common parts + * @param a1_p pointer to an area. + * @param a2_p pointer to an other area + * @return false: a1_p and a2_p has no common parts + */ +bool _lv_area_is_on(const lv_area_t * a1_p, const lv_area_t * a2_p); + +/** + * Check if an area is fully on an other + * @param ain_p pointer to an area which could be in 'aholder_p' + * @param aholder_p pointer to an area which could involve 'ain_p' + * @param radius radius of `aholder_p` (e.g. for rounded rectangle) + * @return true: `ain_p` is fully inside `aholder_p` + */ +bool _lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p, lv_coord_t radius); + + +/** + * Check if an area is fully out of an other + * @param aout_p pointer to an area which could be in 'aholder_p' + * @param aholder_p pointer to an area which could involve 'ain_p' + * @param radius radius of `aholder_p` (e.g. for rounded rectangle) + * @return true: `aout_p` is fully outside `aholder_p` + */ +bool _lv_area_is_out(const lv_area_t * aout_p, const lv_area_t * aholder_p, lv_coord_t radius); + +/** + * Check if 2 area is the same + * @param a pointer to an area + * @param b pointer to another area + */ +bool _lv_area_is_equal(const lv_area_t * a, const lv_area_t * b); + +/** + * Align an area to an other + * @param base an are where the other will be aligned + * @param to_align the area to align + * @param align `LV_ALIGN_...` + */ +void lv_area_align(const lv_area_t * base, lv_area_t * to_align, lv_align_t align, lv_coord_t ofs_x, lv_coord_t ofs_y); + +void lv_point_transform(lv_point_t * p, int32_t angle, int32_t zoom, const lv_point_t * pivot); + +/********************** + * MACROS + **********************/ + +#if LV_USE_LARGE_COORD +#define _LV_COORD_TYPE_SHIFT (29U) +#else +#define _LV_COORD_TYPE_SHIFT (13U) +#endif + +#define _LV_COORD_TYPE_MASK (3 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE(x) ((x) & _LV_COORD_TYPE_MASK) /*Extract type specifiers*/ +#define _LV_COORD_PLAIN(x) ((x) & ~_LV_COORD_TYPE_MASK) /*Remove type specifiers*/ + +#define _LV_COORD_TYPE_PX (0 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE_SPEC (1 << _LV_COORD_TYPE_SHIFT) +#define _LV_COORD_TYPE_PX_NEG (3 << _LV_COORD_TYPE_SHIFT) + +#define LV_COORD_IS_PX(x) (_LV_COORD_TYPE(x) == _LV_COORD_TYPE_PX || \ + _LV_COORD_TYPE(x) == _LV_COORD_TYPE_PX_NEG ? true : false) +#define LV_COORD_IS_SPEC(x) (_LV_COORD_TYPE(x) == _LV_COORD_TYPE_SPEC ? true : false) + +#define LV_COORD_SET_SPEC(x) ((x) | _LV_COORD_TYPE_SPEC) + +/*Special coordinates*/ +#define LV_PCT(x) (x < 0 ? LV_COORD_SET_SPEC(1000 - (x)) : LV_COORD_SET_SPEC(x)) +#define LV_COORD_IS_PCT(x) ((LV_COORD_IS_SPEC(x) && _LV_COORD_PLAIN(x) <= 2000) ? true : false) +#define LV_COORD_GET_PCT(x) (_LV_COORD_PLAIN(x) > 1000 ? 1000 - _LV_COORD_PLAIN(x) : _LV_COORD_PLAIN(x)) +#define LV_SIZE_CONTENT LV_COORD_SET_SPEC(2001) + +LV_EXPORT_CONST_INT(LV_SIZE_CONTENT); + +/*Max coordinate value*/ +#define LV_COORD_MAX ((1 << _LV_COORD_TYPE_SHIFT) - 1) +#define LV_COORD_MIN (-LV_COORD_MAX) + +LV_EXPORT_CONST_INT(LV_COORD_MAX); +LV_EXPORT_CONST_INT(LV_COORD_MIN); + +/** + * Convert a percentage value to `lv_coord_t`. + * Percentage values are stored in special range + * @param x the percentage (0..1000) + * @return a coordinate that stores the percentage + */ +static inline lv_coord_t lv_pct(lv_coord_t x) +{ + return LV_PCT(x); +} + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/misc/lv_assert.h b/include/liblvgl/misc/lv_assert.h new file mode 100644 index 0000000..4625297 --- /dev/null +++ b/include/liblvgl/misc/lv_assert.h @@ -0,0 +1,79 @@ +/** + * @file lv_assert.h + * + */ + +#ifndef LV_ASSERT_H +#define LV_ASSERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "lv_log.h" +#include "lv_mem.h" +#include LV_ASSERT_HANDLER_INCLUDE + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#define LV_ASSERT(expr) \ + do { \ + if(!(expr)) { \ + LV_LOG_ERROR("Asserted at expression: %s", #expr); \ + LV_ASSERT_HANDLER \ + } \ + } while(0) + +#define LV_ASSERT_MSG(expr, msg) \ + do { \ + if(!(expr)) { \ + LV_LOG_ERROR("Asserted at expression: %s (%s)", #expr, msg); \ + LV_ASSERT_HANDLER \ + } \ + } while(0) + +/*----------------- + * ASSERTS + *-----------------*/ + +#if LV_USE_ASSERT_NULL +# define LV_ASSERT_NULL(p) LV_ASSERT_MSG(p != NULL, "NULL pointer"); +#else +# define LV_ASSERT_NULL(p) +#endif + +#if LV_USE_ASSERT_MALLOC +# define LV_ASSERT_MALLOC(p) LV_ASSERT_MSG(p != NULL, "Out of memory"); +#else +# define LV_ASSERT_MALLOC(p) +#endif + +#if LV_USE_ASSERT_MEM_INTEGRITY +# define LV_ASSERT_MEM_INTEGRITY() LV_ASSERT_MSG(lv_mem_test() == LV_RES_OK, "Memory integrity error"); +#else +# define LV_ASSERT_MEM_INTEGRITY() +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ASSERT_H*/ diff --git a/include/liblvgl/misc/lv_async.h b/include/liblvgl/misc/lv_async.h new file mode 100644 index 0000000..4ad5756 --- /dev/null +++ b/include/liblvgl/misc/lv_async.h @@ -0,0 +1,61 @@ +/** + * @file lv_async.h + * + */ + +#ifndef LV_ASYNC_H +#define LV_ASYNC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Type for async callback. + */ +typedef void (*lv_async_cb_t)(void *); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Call an asynchronous function the next time lv_timer_handler() is run. This function is likely to return + * **before** the call actually happens! + * @param async_xcb a callback which is the task itself. + * (the 'x' in the argument name indicates that it's not a fully generic function because it not follows + * the `func_name(object, callback, ...)` convention) + * @param user_data custom parameter + */ +lv_res_t lv_async_call(lv_async_cb_t async_xcb, void * user_data); + +/** + * Cancel an asynchronous function call + * @param async_xcb a callback which is the task itself. + * @param user_data custom parameter + */ +lv_res_t lv_async_call_cancel(lv_async_cb_t async_xcb, void * user_data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ASYNC_H*/ diff --git a/include/liblvgl/misc/lv_bidi.h b/include/liblvgl/misc/lv_bidi.h new file mode 100644 index 0000000..fafb4a2 --- /dev/null +++ b/include/liblvgl/misc/lv_bidi.h @@ -0,0 +1,141 @@ +/** + * @file lv_bidi.h + * + */ + +#ifndef LV_BIDI_H +#define LV_BIDI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include "lv_txt.h" + +/********************* + * DEFINES + *********************/ +/*Special non printable strong characters. + *They can be inserted to texts to affect the run's direction*/ +#define LV_BIDI_LRO "\xE2\x80\xAD" /*U+202D*/ +#define LV_BIDI_RLO "\xE2\x80\xAE" /*U+202E*/ + +/********************** + * TYPEDEFS + **********************/ +enum { + LV_BASE_DIR_LTR = 0x00, + LV_BASE_DIR_RTL = 0x01, + LV_BASE_DIR_AUTO = 0x02, + + LV_BASE_DIR_NEUTRAL = 0x20, + LV_BASE_DIR_WEAK = 0x21, +}; + +typedef uint8_t lv_base_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +#if LV_USE_BIDI + +/** + * Convert a text to get the characters in the correct visual order according to + * Unicode Bidirectional Algorithm + * @param str_in the text to process + * @param str_out store the result here. Has the be `strlen(str_in)` length + * @param base_dir `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` + */ +void _lv_bidi_process(const char * str_in, char * str_out, lv_base_dir_t base_dir); + +/** + * Auto-detect the direction of a text based on the first strong character + * @param txt the text to process + * @return `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` + */ +lv_base_dir_t _lv_bidi_detect_base_dir(const char * txt); + +/** + * Get the logical position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` + * @param visual_pos the visual character position which logical position should be get + * @param is_rtl tell the char at `visual_pos` is RTL or LTR context + * @return the logical character position + */ +uint16_t _lv_bidi_get_logical_pos(const char * str_in, char ** bidi_txt, uint32_t len, lv_base_dir_t base_dir, + uint32_t visual_pos, bool * is_rtl); + +/** + * Get the visual position of a character in a line + * @param str_in the input string. Can be only one line. + * @param bidi_txt internally the text is bidi processed which buffer can be get here. + * If not required anymore has to freed with `lv_mem_free()` + * Can be `NULL` is unused + * @param len length of the line in character count + * @param base_dir base direction of the text: `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` + * @param logical_pos the logical character position which visual position should be get + * @param is_rtl tell the char at `logical_pos` is RTL or LTR context + * @return the visual character position + */ +uint16_t _lv_bidi_get_visual_pos(const char * str_in, char ** bidi_txt, uint16_t len, lv_base_dir_t base_dir, + uint32_t logical_pos, bool * is_rtl); + +/** + * Bidi process a paragraph of text + * @param str_in the string to process + * @param str_out store the result here + * @param len length of the text + * @param base_dir base dir of the text + * @param pos_conv_out an `uint16_t` array to store the related logical position of the character. + * Can be `NULL` is unused + * @param pos_conv_len length of `pos_conv_out` in element count + */ +void _lv_bidi_process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_base_dir_t base_dir, + uint16_t * pos_conv_out, uint16_t pos_conv_len); + +/** + * Get the real text alignment from the a text alignment, base direction and a text. + * @param align LV_TEXT_ALIGN_..., write back the calculated align here (LV_TEXT_ALIGN_LEFT/RIGHT/CENTER) + * @param base_dir LV_BASE_DIR_..., write the calculated base dir here (LV_BASE_DIR_LTR/RTL) + * @param txt a text, used with LV_BASE_DIR_AUTO to determine the base direction + */ +void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt); + + +/********************** + * MACROS + **********************/ + +#else /*LV_USE_BIDI*/ +/** + * For compatibility if LV_USE_BIDI = 0 + * Get the real text alignment from the a text alignment, base direction and a text. + * @param align For LV_TEXT_ALIGN_AUTO give LV_TEXT_ALIGN_LEFT else leave unchanged, write back the calculated align here + * @param base_dir Unused + * @param txt Unused + */ +static inline void lv_bidi_calculate_align(lv_text_align_t * align, lv_base_dir_t * base_dir, const char * txt) +{ + LV_UNUSED(txt); + LV_UNUSED(base_dir); + if(*align == LV_TEXT_ALIGN_AUTO) * align = LV_TEXT_ALIGN_LEFT; +} +#endif /*LV_USE_BIDI*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_BIDI_H*/ diff --git a/include/liblvgl/misc/lv_color.h b/include/liblvgl/misc/lv_color.h new file mode 100644 index 0000000..8e80a61 --- /dev/null +++ b/include/liblvgl/misc/lv_color.h @@ -0,0 +1,708 @@ +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "lv_assert.h" +#include "lv_math.h" +#include "lv_types.h" + +/*Error checking*/ +#if LV_COLOR_DEPTH == 24 +#error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)" +#endif + +#if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0 +#error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h" +#endif + +#include + +/********************* + * DEFINES + *********************/ +LV_EXPORT_CONST_INT(LV_COLOR_DEPTH); +LV_EXPORT_CONST_INT(LV_COLOR_16_SWAP); + +/** + * Opacity percentages. + */ +enum { + LV_OPA_TRANSP = 0, + LV_OPA_0 = 0, + LV_OPA_10 = 25, + LV_OPA_20 = 51, + LV_OPA_30 = 76, + LV_OPA_40 = 102, + LV_OPA_50 = 127, + LV_OPA_60 = 153, + LV_OPA_70 = 178, + LV_OPA_80 = 204, + LV_OPA_90 = 229, + LV_OPA_100 = 255, + LV_OPA_COVER = 255, +}; + +#define LV_OPA_MIN 2 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 253 /*Opacities above this will fully cover*/ + +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_SIZE 8 +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_SIZE 16 +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_SIZE 32 +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +#if defined(__cplusplus) && !defined(_LV_COLOR_HAS_MODERN_CPP) +/** +* MSVC compiler's definition of the __cplusplus indicating 199711L regardless to C++ standard version +* see https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-cplusplus +* so we use _MSC_VER macro instead of __cplusplus +*/ +#ifdef _MSC_VER +#if _MSC_VER >= 1900 /*Visual Studio 2015*/ +#define _LV_COLOR_HAS_MODERN_CPP 1 +#endif +#else +#if __cplusplus >= 201103L +#define _LV_COLOR_HAS_MODERN_CPP 1 +#endif +#endif +#endif /*__cplusplus*/ + +#ifndef _LV_COLOR_HAS_MODERN_CPP +#define _LV_COLOR_HAS_MODERN_CPP 0 +#endif + +#if _LV_COLOR_HAS_MODERN_CPP +/*Fix msvc compiler error C4576 inside C++ code*/ +#define _LV_COLOR_MAKE_TYPE_HELPER lv_color_t +#else +#define _LV_COLOR_MAKE_TYPE_HELPER (lv_color_t) +#endif + +/*--------------------------------------- + * Macros for all existing color depths + * to set/get values of the color channels + *------------------------------------------*/ +# define LV_COLOR_SET_R1(c, v) (c).ch.red = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_G1(c, v) (c).ch.green = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_B1(c, v) (c).ch.blue = (uint8_t)((v) & 0x1) +# define LV_COLOR_SET_A1(c, v) do {} while(0) + +# define LV_COLOR_GET_R1(c) (c).ch.red +# define LV_COLOR_GET_G1(c) (c).ch.green +# define LV_COLOR_GET_B1(c) (c).ch.blue +# define LV_COLOR_GET_A1(c) 0xFF + +# define _LV_COLOR_ZERO_INITIALIZER1 {0x00} +# define LV_COLOR_MAKE1(r8, g8, b8) {(uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))} + +# define LV_COLOR_SET_R8(c, v) (c).ch.red = (uint8_t)((v) & 0x7U) +# define LV_COLOR_SET_G8(c, v) (c).ch.green = (uint8_t)((v) & 0x7U) +# define LV_COLOR_SET_B8(c, v) (c).ch.blue = (uint8_t)((v) & 0x3U) +# define LV_COLOR_SET_A8(c, v) do {} while(0) + +# define LV_COLOR_GET_R8(c) (c).ch.red +# define LV_COLOR_GET_G8(c) (c).ch.green +# define LV_COLOR_GET_B8(c) (c).ch.blue +# define LV_COLOR_GET_A8(c) 0xFF + +# define _LV_COLOR_ZERO_INITIALIZER8 {{0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE8(r8, g8, b8) {{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}} + +# define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)((v) & 0x1FU) +#if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)((v) & 0x3FU) +#else +# define LV_COLOR_SET_G16(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);} +#endif +# define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)((v) & 0x1FU) +# define LV_COLOR_SET_A16(c, v) do {} while(0) + +# define LV_COLOR_GET_R16(c) (c).ch.red +#if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_GET_G16(c) (c).ch.green +#else +# define LV_COLOR_GET_G16(c) (((c).ch.green_h << 3) + (c).ch.green_l) +#endif +# define LV_COLOR_GET_B16(c) (c).ch.blue +# define LV_COLOR_GET_A16(c) 0xFF + +#if LV_COLOR_16_SWAP == 0 +# define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x3FU), (uint8_t)((r8 >> 3) & 0x1FU)}} +#else +# define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 3) & 0x1FU), (uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x7U)}} +#endif + +# define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint8_t)((v) & 0xFF) +# define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint8_t)((v) & 0xFF) + +# define LV_COLOR_GET_R32(c) (c).ch.red +# define LV_COLOR_GET_G32(c) (c).ch.green +# define LV_COLOR_GET_B32(c) (c).ch.blue +# define LV_COLOR_GET_A32(c) (c).ch.alpha + +# define _LV_COLOR_ZERO_INITIALIZER32 {{0x00, 0x00, 0x00, 0x00}} +# define LV_COLOR_MAKE32(r8, g8, b8) {{b8, g8, r8, 0xff}} /*Fix 0xff alpha*/ + +/*--------------------------------------- + * Macros for the current color depth + * to set/get values of the color channels + *------------------------------------------*/ +#define LV_COLOR_SET_R(c, v) LV_CONCAT(LV_COLOR_SET_R, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_G(c, v) LV_CONCAT(LV_COLOR_SET_G, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_B(c, v) LV_CONCAT(LV_COLOR_SET_B, LV_COLOR_DEPTH)(c, v) +#define LV_COLOR_SET_A(c, v) LV_CONCAT(LV_COLOR_SET_A, LV_COLOR_DEPTH)(c, v) + +#define LV_COLOR_GET_R(c) LV_CONCAT(LV_COLOR_GET_R, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_G(c) LV_CONCAT(LV_COLOR_GET_G, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_B(c) LV_CONCAT(LV_COLOR_GET_B, LV_COLOR_DEPTH)(c) +#define LV_COLOR_GET_A(c) LV_CONCAT(LV_COLOR_GET_A, LV_COLOR_DEPTH)(c) + +#define _LV_COLOR_ZERO_INITIALIZER LV_CONCAT(_LV_COLOR_ZERO_INITIALIZER, LV_COLOR_DEPTH) +#define LV_COLOR_MAKE(r8, g8, b8) LV_CONCAT(LV_COLOR_MAKE, LV_COLOR_DEPTH)(r8, g8, b8) + +/********************** + * TYPEDEFS + **********************/ + +typedef union { + uint8_t full; /*must be declared first to set all bits of byte via initializer list*/ + union { + uint8_t blue : 1; + uint8_t green : 1; + uint8_t red : 1; + } ch; +} lv_color1_t; + +typedef union { + struct { + uint8_t blue : 2; + uint8_t green : 3; + uint8_t red : 3; + } ch; + uint8_t full; +} lv_color8_t; + +typedef union { + struct { +#if LV_COLOR_16_SWAP == 0 + uint16_t blue : 5; + uint16_t green : 6; + uint16_t red : 5; +#else + uint16_t green_h : 3; + uint16_t red : 5; + uint16_t blue : 5; + uint16_t green_l : 3; +#endif + } ch; + uint16_t full; +} lv_color16_t; + +typedef union { + struct { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + } ch; + uint32_t full; +} lv_color32_t; + +typedef LV_CONCAT3(uint, LV_COLOR_SIZE, _t) lv_color_int_t; +typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t; + +typedef struct { + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_t; + +//! @cond Doxygen_Suppress +/*No idea where the guard is required but else throws warnings in the docs*/ +typedef uint8_t lv_opa_t; +//! @endcond + +struct _lv_color_filter_dsc_t; + +typedef lv_color_t (*lv_color_filter_cb_t)(const struct _lv_color_filter_dsc_t *, lv_color_t, lv_opa_t); + +typedef struct _lv_color_filter_dsc_t { + lv_color_filter_cb_t filter_cb; + void * user_data; +} lv_color_filter_dsc_t; + + +typedef enum { + LV_PALETTE_RED, + LV_PALETTE_PINK, + LV_PALETTE_PURPLE, + LV_PALETTE_DEEP_PURPLE, + LV_PALETTE_INDIGO, + LV_PALETTE_BLUE, + LV_PALETTE_LIGHT_BLUE, + LV_PALETTE_CYAN, + LV_PALETTE_TEAL, + LV_PALETTE_GREEN, + LV_PALETTE_LIGHT_GREEN, + LV_PALETTE_LIME, + LV_PALETTE_YELLOW, + LV_PALETTE_AMBER, + LV_PALETTE_ORANGE, + LV_PALETTE_DEEP_ORANGE, + LV_PALETTE_BROWN, + LV_PALETTE_BLUE_GREY, + LV_PALETTE_GREY, + _LV_PALETTE_LAST, + LV_PALETTE_NONE = 0xff, +} lv_palette_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*In color conversations: + * - When converting to bigger color type the LSB weight of 1 LSB is calculated + * E.g. 16 bit Red has 5 bits + * 8 bit Red has 3 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^3 - 1) = 31 / 7 = 4 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 3 bits + * 16 bit Red has 5 bits + * ---------------------- + * Shift right with 5 - 3 = 2 + */ +static inline uint8_t lv_color_to1(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + return color.full; +#elif LV_COLOR_DEPTH == 8 + if((LV_COLOR_GET_R(color) & 0x4) || (LV_COLOR_GET_G(color) & 0x4) || (LV_COLOR_GET_B(color) & 0x2)) { + return 1; + } + else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 + if((LV_COLOR_GET_R(color) & 0x10) || (LV_COLOR_GET_G(color) & 0x20) || (LV_COLOR_GET_B(color) & 0x10)) { + return 1; + } + else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((LV_COLOR_GET_R(color) & 0x80) || (LV_COLOR_GET_G(color) & 0x80) || (LV_COLOR_GET_B(color) & 0x80)) { + return 1; + } + else { + return 0; + } +#endif +} + +static inline uint8_t lv_color_to8(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) + return 0; + else + return 0xFF; +#elif LV_COLOR_DEPTH == 8 + return color.full; +#elif LV_COLOR_DEPTH == 16 + lv_color8_t ret; + LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 2); /*5 - 3 = 2*/ + LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 3); /*6 - 3 = 3*/ + LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 3); /*5 - 2 = 3*/ + return ret.full; +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 5); /*8 - 3 = 5*/ + LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 5); /*8 - 3 = 5*/ + LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 6); /*8 - 2 = 6*/ + return ret.full; +#endif +} + +static inline uint16_t lv_color_to16(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) + return 0; + else + return 0xFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color16_t ret; + LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) * 4); /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) * 9); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) * 10); /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; + LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) >> 3); /*8 - 5 = 3*/ + LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) >> 2); /*8 - 6 = 2*/ + LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) >> 3); /*8 - 5 = 3*/ + return ret.full; +#endif +} + +static inline uint32_t lv_color_to32(lv_color_t color) +{ +#if LV_COLOR_DEPTH == 1 + if(color.full == 0) + return 0xFF000000; + else + return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + LV_COLOR_SET_R32(ret, LV_COLOR_GET_R(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + LV_COLOR_SET_G32(ret, LV_COLOR_GET_G(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + LV_COLOR_SET_B32(ret, LV_COLOR_GET_B(color) * 85); /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + LV_COLOR_SET_A32(ret, 0xFF); + return ret.full; +#elif LV_COLOR_DEPTH == 16 + /** + * The floating point math for conversion is: + * valueto = valuefrom * ( (2^bitsto - 1) / (float)(2^bitsfrom - 1) ) + * The faster integer math for conversion is: + * valueto = ( valuefrom * multiplier + adder ) >> divisor + * multiplier = FLOOR( ( (2^bitsto - 1) << divisor ) / (float)(2^bitsfrom - 1) ) + * + * Find the first divisor where ( adder >> divisor ) <= 0 + * + * 5-bit to 8-bit: ( 31 * multiplier + adder ) >> divisor = 255 + * divisor multiplier adder min (0) max (31) + * 0 8 7 7 255 + * 1 16 14 7 255 + * 2 32 28 7 255 + * 3 65 25 3 255 + * 4 131 19 1 255 + * 5 263 7 0 255 + * + * 6-bit to 8-bit: 255 = ( 63 * multiplier + adder ) >> divisor + * divisor multiplier adder min (0) max (63) + * 0 4 3 3 255 + * 1 8 6 3 255 + * 2 16 12 3 255 + * 3 32 24 3 255 + * 4 64 48 3 255 + * 5 129 33 1 255 + * 6 259 3 0 255 + */ + + lv_color32_t ret; + LV_COLOR_SET_R32(ret, (LV_COLOR_GET_R(color) * 263 + 7) >> 5); + LV_COLOR_SET_G32(ret, (LV_COLOR_GET_G(color) * 259 + 3) >> 6); + LV_COLOR_SET_B32(ret, (LV_COLOR_GET_B(color) * 263 + 7) >> 5); + LV_COLOR_SET_A32(ret, 0xFF); + return ret.full; +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +//! @cond Doxygen_Suppress + +/** + * Mix two colors with a given ratio. + * @param c1 the first color to mix (usually the foreground) + * @param c2 the second color to mix (usually the background) + * @param mix The ratio of the colors. 0: full `c2`, 255: full `c1`, 127: half `c1` and half`c2` + * @return the mixed color + */ +LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; + +#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0 && LV_COLOR_MIX_ROUND_OFS == 0 + /*Source: https://stackoverflow.com/a/50012418/1999969*/ + mix = (uint32_t)((uint32_t)mix + 4) >> 3; + uint32_t bg = (uint32_t)((uint32_t)c2.full | ((uint32_t)c2.full << 16)) & + 0x7E0F81F; /*0b00000111111000001111100000011111*/ + uint32_t fg = (uint32_t)((uint32_t)c1.full | ((uint32_t)c1.full << 16)) & 0x7E0F81F; + uint32_t result = ((((fg - bg) * mix) >> 5) + bg) & 0x7E0F81F; + ret.full = (uint16_t)((result >> 16) | result); +#elif LV_COLOR_DEPTH != 1 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + LV_COLOR_SET_R(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_G(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_G(c1) * mix + LV_COLOR_GET_G(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_B(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_B(c1) * mix + LV_COLOR_GET_B(c2) * + (255 - mix) + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_A(ret, 0xFF); +#else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +#endif + + return ret; +} + +LV_ATTRIBUTE_FAST_MEM static inline void lv_color_premult(lv_color_t c, uint8_t mix, uint16_t * out) +{ +#if LV_COLOR_DEPTH != 1 + out[0] = (uint16_t)LV_COLOR_GET_R(c) * mix; + out[1] = (uint16_t)LV_COLOR_GET_G(c) * mix; + out[2] = (uint16_t)LV_COLOR_GET_B(c) * mix; +#else + (void) mix; + /*Pre-multiplication can't be used with 1 bpp*/ + out[0] = LV_COLOR_GET_R(c); + out[1] = LV_COLOR_GET_G(c); + out[2] = LV_COLOR_GET_B(c); +#endif + +} + +/** + * Mix two colors with a given ratio. It runs faster then `lv_color_mix` but requires some pre computation. + * @param premult_c1 The first color. Should be preprocessed with `lv_color_premult(c1)` + * @param c2 The second color. As it is no pre computation required on it + * @param mix The ratio of the colors. 0: full `c1`, 255: full `c2`, 127: half `c1` and half `c2`. + * Should be modified like mix = `255 - mix` + * @return the mixed color + * @note 255 won't give clearly `c1`. + */ +LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix_premult(uint16_t * premult_c1, lv_color_t c2, uint8_t mix) +{ + lv_color_t ret; +#if LV_COLOR_DEPTH != 1 + /*LV_COLOR_DEPTH == 8 or 32*/ + LV_COLOR_SET_R(ret, LV_UDIV255(premult_c1[0] + LV_COLOR_GET_R(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_G(ret, LV_UDIV255(premult_c1[1] + LV_COLOR_GET_G(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_B(ret, LV_UDIV255(premult_c1[2] + LV_COLOR_GET_B(c2) * mix + LV_COLOR_MIX_ROUND_OFS)); + LV_COLOR_SET_A(ret, 0xFF); +#else + /*LV_COLOR_DEPTH == 1*/ + /*Restore color1*/ + lv_color_t c1; + LV_COLOR_SET_R(c1, premult_c1[0]); + LV_COLOR_SET_G(c1, premult_c1[1]); + LV_COLOR_SET_B(c1, premult_c1[2]); + ret.full = mix > LV_OPA_50 ? c2.full : c1.full; +#endif + + return ret; +} + +/** + * Mix two colors. Both color can have alpha value. + * @param bg_color background color + * @param bg_opa alpha of the background color + * @param fg_color foreground color + * @param fg_opa alpha of the foreground color + * @param res_color the result color + * @param res_opa the result opacity + */ +LV_ATTRIBUTE_FAST_MEM static inline void lv_color_mix_with_alpha(lv_color_t bg_color, lv_opa_t bg_opa, + lv_color_t fg_color, lv_opa_t fg_opa, + lv_color_t * res_color, lv_opa_t * res_opa) +{ + /*Pick the foreground if it's fully opaque or the Background is fully transparent*/ + if(fg_opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) { + res_color->full = fg_color.full; + *res_opa = fg_opa; + } + /*Transparent foreground: use the Background*/ + else if(fg_opa <= LV_OPA_MIN) { + res_color->full = bg_color.full; + *res_opa = bg_opa; + } + /*Opaque background: use simple mix*/ + else if(bg_opa >= LV_OPA_MAX) { + *res_color = lv_color_mix(fg_color, bg_color, fg_opa); + *res_opa = LV_OPA_COVER; + } + /*Both colors have alpha. Expensive calculation need to be applied*/ + else { + /*Save the parameters and the result. If they will be asked again don't compute again*/ + static lv_opa_t fg_opa_save = 0; + static lv_opa_t bg_opa_save = 0; + static lv_color_t fg_color_save = _LV_COLOR_ZERO_INITIALIZER; + static lv_color_t bg_color_save = _LV_COLOR_ZERO_INITIALIZER; + static lv_color_t res_color_saved = _LV_COLOR_ZERO_INITIALIZER; + static lv_opa_t res_opa_saved = 0; + + if(fg_opa != fg_opa_save || bg_opa != bg_opa_save || fg_color.full != fg_color_save.full || + bg_color.full != bg_color_save.full) { + fg_opa_save = fg_opa; + bg_opa_save = bg_opa; + fg_color_save.full = fg_color.full; + bg_color_save.full = bg_color.full; + /*Info: + * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/ + res_opa_saved = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8); + LV_ASSERT(res_opa_saved != 0); + lv_opa_t ratio = (uint16_t)((uint16_t)fg_opa * 255) / res_opa_saved; + res_color_saved = lv_color_mix(fg_color, bg_color, ratio); + + } + + res_color->full = res_color_saved.full; + *res_opa = res_opa_saved; + } +} + +//! @endcond + +/** + * Get the brightness of a color + * @param color a color + * @return the brightness [0..255] + */ +static inline uint8_t lv_color_brightness(lv_color_t color) +{ + lv_color32_t c32; + c32.full = lv_color_to32(color); + uint16_t bright = (uint16_t)(3u * LV_COLOR_GET_R32(c32) + LV_COLOR_GET_B32(c32) + 4u * LV_COLOR_GET_G32(c32)); + return (uint8_t)(bright >> 3); +} + +static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b) +{ + return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(r, g, b); +} + +static inline lv_color_t lv_color_hex(uint32_t c) +{ +#if LV_COLOR_DEPTH == 16 + lv_color_t r; +#if LV_COLOR_16_SWAP == 0 + /* Convert a 4 bytes per pixel in format ARGB32 to R5G6B5 format + naive way (by calling lv_color_make with components): + r = ((c & 0xFF0000) >> 19) + g = ((c & 0xFF00) >> 10) + b = ((c & 0xFF) >> 3) + rgb565 = (r << 11) | (g << 5) | b + That's 3 mask, 5 bitshift and 2 or operations + + A bit better: + r = ((c & 0xF80000) >> 8) + g = ((c & 0xFC00) >> 5) + b = ((c & 0xFF) >> 3) + rgb565 = r | g | b + That's 3 mask, 3 bitshifts and 2 or operations */ + r.full = (uint16_t)(((c & 0xF80000) >> 8) | ((c & 0xFC00) >> 5) | ((c & 0xFF) >> 3)); +#else + /* We want: rrrr rrrr GGGg gggg bbbb bbbb => gggb bbbb rrrr rGGG */ + r.full = (uint16_t)(((c & 0xF80000) >> 16) | ((c & 0xFC00) >> 13) | ((c & 0x1C00) << 3) | ((c & 0xF8) << 5)); +#endif + return r; +#elif LV_COLOR_DEPTH == 32 + lv_color_t r; + r.full = c | 0xFF000000; + return r; +#else /*LV_COLOR_DEPTH == 8*/ + return lv_color_make((uint8_t)((c >> 16) & 0xFF), (uint8_t)((c >> 8) & 0xFF), (uint8_t)(c & 0xFF)); +#endif +} + +static inline lv_color_t lv_color_hex3(uint32_t c) +{ + return lv_color_make((uint8_t)(((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), (uint8_t)((c & 0xF0) | ((c & 0xF0) >> 4)), + (uint8_t)((c & 0xF) | ((c & 0xF) << 4))); +} + +static inline void lv_color_filter_dsc_init(lv_color_filter_dsc_t * dsc, lv_color_filter_cb_t cb) +{ + dsc->filter_cb = cb; +} + +//! @cond Doxygen_Suppress +//! +LV_ATTRIBUTE_FAST_MEM void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num); + +//! @endcond +lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl); + +lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl); + +lv_color_t lv_color_change_lightness(lv_color_t c, lv_opa_t lvl); + +/** + * Convert a HSV color to RGB + * @param h hue [0..359] + * @param s saturation [0..100] + * @param v value [0..100] + * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth) + */ +lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v); + +/** + * Convert a 32-bit RGB color to HSV + * @param r8 8-bit red + * @param g8 8-bit green + * @param b8 8-bit blue + * @return the given RGB color in HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8); + +/** + * Convert a color to HSV + * @param color color + * @return the given color in HSV + */ +lv_color_hsv_t lv_color_to_hsv(lv_color_t color); + +/** + * Just a wrapper around LV_COLOR_CHROMA_KEY because it might be more convenient to use a function in some cases + * @return LV_COLOR_CHROMA_KEY + */ +static inline lv_color_t lv_color_chroma_key(void) +{ + return LV_COLOR_CHROMA_KEY; +} + +/********************** + * PREDEFINED COLORS + **********************/ +/*Source: https://vuetifyjs.com/en/styles/colors/#material-colors*/ + +lv_color_t lv_palette_main(lv_palette_t p); +static inline lv_color_t lv_color_white(void) +{ + return lv_color_make(0xff, 0xff, 0xff); +} +static inline lv_color_t lv_color_black(void) +{ + return lv_color_make(0x00, 0x0, 0x00); +} +lv_color_t lv_palette_lighten(lv_palette_t p, uint8_t lvl); +lv_color_t lv_palette_darken(lv_palette_t p, uint8_t lvl); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_COLOR_H*/ diff --git a/include/liblvgl/misc/lv_fs.h b/include/liblvgl/misc/lv_fs.h new file mode 100644 index 0000000..13b2eeb --- /dev/null +++ b/include/liblvgl/misc/lv_fs.h @@ -0,0 +1,262 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 +#define LV_FS_MAX_PATH_LENGTH 256 + +/********************** + * TYPEDEFS + **********************/ + +/** + * Errors in the file system module. + */ +enum { + LV_FS_RES_OK = 0, + LV_FS_RES_HW_ERR, /*Low level hardware error*/ + LV_FS_RES_FS_ERR, /*Error in the file system structure*/ + LV_FS_RES_NOT_EX, /*Driver, file or directory is not exists*/ + LV_FS_RES_FULL, /*Disk full*/ + LV_FS_RES_LOCKED, /*The file is already opened*/ + LV_FS_RES_DENIED, /*Access denied. Check 'fs_open' modes and write protect*/ + LV_FS_RES_BUSY, /*The file system now can't handle it, try later*/ + LV_FS_RES_TOUT, /*Process time outed*/ + LV_FS_RES_NOT_IMP, /*Requested function is not implemented*/ + LV_FS_RES_OUT_OF_MEM, /*Not enough memory for an internal operation*/ + LV_FS_RES_INV_PARAM, /*Invalid parameter among arguments*/ + LV_FS_RES_UNKNOWN, /*Other unknown error*/ +}; +typedef uint8_t lv_fs_res_t; + +/** + * File open mode. + */ +enum { + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + + +/** + * Seek modes. + */ +typedef enum { + LV_FS_SEEK_SET = 0x00, /**< Set the position from absolutely (from the start of file)*/ + LV_FS_SEEK_CUR = 0x01, /**< Set the position from the current position*/ + LV_FS_SEEK_END = 0x02, /**< Set the position from the end of the file*/ +} lv_fs_whence_t; + +typedef struct _lv_fs_drv_t { + char letter; + uint16_t cache_size; + bool (*ready_cb)(struct _lv_fs_drv_t * drv); + + void * (*open_cb)(struct _lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close_cb)(struct _lv_fs_drv_t * drv, void * file_p); + lv_fs_res_t (*read_cb)(struct _lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write_cb)(struct _lv_fs_drv_t * drv, void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek_cb)(struct _lv_fs_drv_t * drv, void * file_p, uint32_t pos, lv_fs_whence_t whence); + lv_fs_res_t (*tell_cb)(struct _lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); + + void * (*dir_open_cb)(struct _lv_fs_drv_t * drv, const char * path); + lv_fs_res_t (*dir_read_cb)(struct _lv_fs_drv_t * drv, void * rddir_p, char * fn); + lv_fs_res_t (*dir_close_cb)(struct _lv_fs_drv_t * drv, void * rddir_p); + +#if LV_USE_USER_DATA + void * user_data; /**< Custom file user data*/ +#endif +} lv_fs_drv_t; + +typedef struct { + uint32_t start; + uint32_t end; + uint32_t file_position; + void * buffer; +} lv_fs_file_cache_t; + +typedef struct { + void * file_d; + lv_fs_drv_t * drv; + lv_fs_file_cache_t * cache; +} lv_fs_file_t; + +typedef struct { + void * dir_d; + lv_fs_drv_t * drv; +} lv_fs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void _lv_fs_init(void); + +/** + * Initialize a file system driver with default values. + * It is used to surly have known values in the fields ant not memory junk. + * After it you can set the fields. + * @param drv pointer to driver variable to initialize + */ +void lv_fs_drv_init(lv_fs_drv_t * drv); + +/** + * Add a new drive + * @param drv pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. Only pointer is saved, so the + * driver should be static or dynamically allocated. + */ +void lv_fs_drv_register(lv_fs_drv_t * drv); + +/** + * Give a pointer to a driver from its letter + * @param letter the driver letter + * @return pointer to a driver or NULL if not found + */ +lv_fs_drv_t * lv_fs_get_drv(char letter); + +/** + * Test if a drive is ready or not. If the `ready` function was not initialized `true` will be + * returned. + * @param letter letter of the drive + * @return true: drive is ready; false: drive is not ready + */ +bool lv_fs_is_ready(char letter); + +/** + * Open a file + * @param file_p pointer to a lv_fs_file_t variable + * @param path path to the file beginning with the driver letter (e.g. S:/folder/file.txt) + * @param mode read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD | FS_MODE_WR + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mode); + +/** + * Close an already opened file + * @param file_p pointer to a lv_fs_file_t variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_close(lv_fs_file_t * file_p); + +/** + * Read from a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer where the read bytes are stored + * @param btr Bytes To Read + * @param br the number of real read bytes (Bytes Read). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_read(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write into a file + * @param file_p pointer to a lv_fs_file_t variable + * @param buf pointer to a buffer with the bytes to write + * @param btw Bytes To Write + * @param bw the number of real written bytes (Bytes Written). NULL if unused. + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_write(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the position of the 'cursor' (read write pointer) in a file + * @param file_p pointer to a lv_fs_file_t variable + * @param pos the new position expressed in bytes index (0: start of file) + * @param whence tells from where set the position. See @lv_fs_whence_t + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_seek(lv_fs_file_t * file_p, uint32_t pos, lv_fs_whence_t whence); + +/** + * Give the position of the read write pointer + * @param file_p pointer to a lv_fs_file_t variable + * @param pos_p pointer to store the position of the read write pointer + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_tell(lv_fs_file_t * file_p, uint32_t * pos); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'lv_fs_dir_t' variable + * @param path path to a directory + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path); + +/** + * Read the next filename form a directory. + * The name of the directories will begin with '/' + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @param fn pointer to a buffer to store the filename + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_read(lv_fs_dir_t * rddir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'fs_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_dir_close(lv_fs_dir_t * rddir_p); + +/** + * Fill a buffer with the letters of existing drivers + * @param buf buffer to store the letters ('\0' added after the last letter) + * @return the buffer + */ +char * lv_fs_get_letters(char * buf); + +/** + * Return with the extension of the filename + * @param fn string with a filename + * @return pointer to the beginning extension or empty string if no extension + */ +const char * lv_fs_get_ext(const char * fn); + +/** + * Step up one level + * @param path pointer to a file name + * @return the truncated file name + */ +char * lv_fs_up(char * path); + +/** + * Get the last element of a path (e.g. U:/folder/file -> file) + * @param path pointer to a file name + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_FS_H*/ diff --git a/include/liblvgl/misc/lv_gc.h b/include/liblvgl/misc/lv_gc.h new file mode 100644 index 0000000..7a98d10 --- /dev/null +++ b/include/liblvgl/misc/lv_gc.h @@ -0,0 +1,97 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include +#include "lv_mem.h" +#include "lv_ll.h" +#include "lv_timer.h" +#include "lv_types.h" +#include "liblvgl/draw/lv_img_cache.h" +#include "liblvgl/draw/lv_draw_mask.h" +#include "liblvgl/core/lv_obj_pos.h" + +/********************* + * DEFINES + *********************/ +#if LV_IMG_CACHE_DEF_SIZE +# define LV_IMG_CACHE_DEF 1 +#else +# define LV_IMG_CACHE_DEF 0 +#endif + +#define LV_DISPATCH(f, t, n) f(t, n) +#define LV_DISPATCH_COND(f, t, n, m, v) LV_CONCAT3(LV_DISPATCH, m, v)(f, t, n) + +#define LV_DISPATCH00(f, t, n) LV_DISPATCH(f, t, n) +#define LV_DISPATCH01(f, t, n) +#define LV_DISPATCH10(f, t, n) +#define LV_DISPATCH11(f, t, n) LV_DISPATCH(f, t, n) + +#define LV_ITERATE_ROOTS(f) \ + LV_DISPATCH(f, lv_ll_t, _lv_timer_ll) /*Linked list to store the lv_timers*/ \ + LV_DISPATCH(f, lv_ll_t, _lv_disp_ll) /*Linked list of display device*/ \ + LV_DISPATCH(f, lv_ll_t, _lv_indev_ll) /*Linked list of input device*/ \ + LV_DISPATCH(f, lv_ll_t, _lv_fsdrv_ll) \ + LV_DISPATCH(f, lv_ll_t, _lv_anim_ll) \ + LV_DISPATCH(f, lv_ll_t, _lv_group_ll) \ + LV_DISPATCH(f, lv_ll_t, _lv_img_decoder_ll) \ + LV_DISPATCH(f, lv_ll_t, _lv_obj_style_trans_ll) \ + LV_DISPATCH(f, lv_layout_dsc_t *, _lv_layout_list) \ + LV_DISPATCH_COND(f, _lv_img_cache_entry_t*, _lv_img_cache_array, LV_IMG_CACHE_DEF, 1) \ + LV_DISPATCH_COND(f, _lv_img_cache_entry_t, _lv_img_cache_single, LV_IMG_CACHE_DEF, 0) \ + LV_DISPATCH(f, lv_timer_t*, _lv_timer_act) \ + LV_DISPATCH(f, lv_mem_buf_arr_t , lv_mem_buf) \ + LV_DISPATCH_COND(f, _lv_draw_mask_radius_circle_dsc_arr_t , _lv_circle_cache, LV_DRAW_COMPLEX, 1) \ + LV_DISPATCH_COND(f, _lv_draw_mask_saved_arr_t , _lv_draw_mask_list, LV_DRAW_COMPLEX, 1) \ + LV_DISPATCH(f, void * , _lv_theme_default_styles) \ + LV_DISPATCH(f, void * , _lv_theme_basic_styles) \ + LV_DISPATCH_COND(f, uint8_t *, _lv_font_decompr_buf, LV_USE_FONT_COMPRESSED, 1) \ + LV_DISPATCH(f, uint8_t * , _lv_grad_cache_mem) \ + LV_DISPATCH(f, uint8_t * , _lv_style_custom_prop_flag_lookup_table) + +#define LV_DEFINE_ROOT(root_type, root_name) root_type root_name; +#define LV_ROOTS LV_ITERATE_ROOTS(LV_DEFINE_ROOT) + +#if LV_ENABLE_GC == 1 +#if LV_MEM_CUSTOM != 1 +#error "GC requires CUSTOM_MEM" +#endif /*LV_MEM_CUSTOM*/ +#include LV_GC_INCLUDE +#else /*LV_ENABLE_GC*/ +#define LV_GC_ROOT(x) x +#define LV_EXTERN_ROOT(root_type, root_name) extern root_type root_name; +LV_ITERATE_ROOTS(LV_EXTERN_ROOT) +#endif /*LV_ENABLE_GC*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void _lv_gc_clear_roots(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_GC_H*/ diff --git a/include/liblvgl/misc/lv_ll.h b/include/liblvgl/misc/lv_ll.h new file mode 100644 index 0000000..d38f692 --- /dev/null +++ b/include/liblvgl/misc/lv_ll.h @@ -0,0 +1,167 @@ +/** + * @file lv_ll.h + * Handle linked lists. The nodes are dynamically allocated by the 'lv_mem' module. + */ + +#ifndef LV_LL_H +#define LV_LL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** Dummy type to make handling easier*/ +typedef uint8_t lv_ll_node_t; + +/** Description of a linked list*/ +typedef struct { + uint32_t n_size; + lv_ll_node_t * head; + lv_ll_node_t * tail; +} lv_ll_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize linked list + * @param ll_p pointer to lv_ll_t variable + * @param node_size the size of 1 node in bytes + */ +void _lv_ll_init(lv_ll_t * ll_p, uint32_t node_size); + +/** + * Add a new head to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new head + */ +void * _lv_ll_ins_head(lv_ll_t * ll_p); + +/** + * Insert a new node in front of the n_act node + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the new node + */ +void * _lv_ll_ins_prev(lv_ll_t * ll_p, void * n_act); + +/** + * Add a new tail to a linked list + * @param ll_p pointer to linked list + * @return pointer to the new tail + */ +void * _lv_ll_ins_tail(lv_ll_t * ll_p); + +/** + * Remove the node 'node_p' from 'll_p' linked list. + * It does not free the memory of node. + * @param ll_p pointer to the linked list of 'node_p' + * @param node_p pointer to node in 'll_p' linked list + */ +void _lv_ll_remove(lv_ll_t * ll_p, void * node_p); + +/** + * Remove and free all elements from a linked list. The list remain valid but become empty. + * @param ll_p pointer to linked list + */ +void _lv_ll_clear(lv_ll_t * ll_p); + +/** + * Move a node to a new linked list + * @param ll_ori_p pointer to the original (old) linked list + * @param ll_new_p pointer to the new linked list + * @param node pointer to a node + * @param head true: be the head in the new list + * false be the tail in the new list + */ +void _lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head); + +/** + * Return with head node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the head of 'll_p' + */ +void * _lv_ll_get_head(const lv_ll_t * ll_p); + +/** + * Return with tail node of the linked list + * @param ll_p pointer to linked list + * @return pointer to the tail of 'll_p' + */ +void * _lv_ll_get_tail(const lv_ll_t * ll_p); + +/** + * Return with the pointer of the next node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the next node + */ +void * _lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return with the pointer of the previous node after 'n_act' + * @param ll_p pointer to linked list + * @param n_act pointer a node + * @return pointer to the previous node + */ +void * _lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act); + +/** + * Return the length of the linked list. + * @param ll_p pointer to linked list + * @return length of the linked list + */ +uint32_t _lv_ll_get_len(const lv_ll_t * ll_p); + +/** + * TODO + * @param ll_p + * @param n1_p + * @param n2_p +void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p); + */ + +/** + * Move a node before an other node in the same linked list + * @param ll_p pointer to a linked list + * @param n_act pointer to node to move + * @param n_after pointer to a node which should be after `n_act` + */ +void _lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after); + +/** + * Check if a linked list is empty + * @param ll_p pointer to a linked list + * @return true: the linked list is empty; false: not empty + */ +bool _lv_ll_is_empty(lv_ll_t * ll_p); + +/********************** + * MACROS + **********************/ + +#define _LV_LL_READ(list, i) for(i = _lv_ll_get_head(list); i != NULL; i = _lv_ll_get_next(list, i)) + +#define _LV_LL_READ_BACK(list, i) for(i = _lv_ll_get_tail(list); i != NULL; i = _lv_ll_get_prev(list, i)) + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/misc/lv_log.h b/include/liblvgl/misc/lv_log.h new file mode 100644 index 0000000..cd61905 --- /dev/null +++ b/include/liblvgl/misc/lv_log.h @@ -0,0 +1,154 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include + +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `LV_USE_LOG`*/ + +#define LV_LOG_LEVEL_TRACE 0 /**< A lot of logs to give detailed information*/ +#define LV_LOG_LEVEL_INFO 1 /**< Log important events*/ +#define LV_LOG_LEVEL_WARN 2 /**< Log if something unwanted happened but didn't caused problem*/ +#define LV_LOG_LEVEL_ERROR 3 /**< Only critical issue, when the system may fail*/ +#define LV_LOG_LEVEL_USER 4 /**< Custom logs from the user*/ +#define LV_LOG_LEVEL_NONE 5 /**< Do not log anything*/ +#define _LV_LOG_LEVEL_NUM 6 /**< Number of log levels*/ + +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_TRACE); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_INFO); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_WARN); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_ERROR); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_USER); +LV_EXPORT_CONST_INT(LV_LOG_LEVEL_NONE); + +typedef int8_t lv_log_level_t; + +#if LV_USE_LOG +/********************** + * TYPEDEFS + **********************/ + +/** + * Log print function. Receives a string buffer to print". + */ +typedef void (*lv_log_print_g_cb_t)(const char * buf); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print/write function to call when a log is added. + * It can format its "File path", "Line number" and "Description" as required + * and send the formatted log message to a console or serial port. + * @param print_cb a function pointer to print a log + */ +void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb); + +/** + * Print a log message via `printf` if enabled with `LV_LOG_PRINTF` in `lv_conf.h` + * and/or a print callback if registered with `lv_log_register_print_cb` + * @param format printf-like format string + * @param ... parameters for `format` + */ +void lv_log(const char * format, ...) LV_FORMAT_ATTRIBUTE(1, 2); + +/** + * Add a log + * @param level the level of log. (From `lv_log_level_t` enum) + * @param file name of the file when the log added + * @param line line number in the source code where the log added + * @param func name of the function when the log added + * @param format printf-like format string + * @param ... parameters for `format` + */ +void _lv_log_add(lv_log_level_t level, const char * file, int line, + const char * func, const char * format, ...) LV_FORMAT_ATTRIBUTE(5, 6); + +/********************** + * MACROS + **********************/ +#ifndef LV_LOG_TRACE +# if LV_LOG_LEVEL <= LV_LOG_LEVEL_TRACE +# define LV_LOG_TRACE(...) _lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__) +# else +# define LV_LOG_TRACE(...) do {}while(0) +# endif +#endif + +#ifndef LV_LOG_INFO +# if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO +# define LV_LOG_INFO(...) _lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) +# else +# define LV_LOG_INFO(...) do {}while(0) +# endif +#endif + +#ifndef LV_LOG_WARN +# if LV_LOG_LEVEL <= LV_LOG_LEVEL_WARN +# define LV_LOG_WARN(...) _lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__) +# else +# define LV_LOG_WARN(...) do {}while(0) +# endif +#endif + +#ifndef LV_LOG_ERROR +# if LV_LOG_LEVEL <= LV_LOG_LEVEL_ERROR +# define LV_LOG_ERROR(...) _lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__) +# else +# define LV_LOG_ERROR(...) do {}while(0) +# endif +#endif + +#ifndef LV_LOG_USER +# if LV_LOG_LEVEL <= LV_LOG_LEVEL_USER +# define LV_LOG_USER(...) _lv_log_add(LV_LOG_LEVEL_USER, __FILE__, __LINE__, __func__, __VA_ARGS__) +# else +# define LV_LOG_USER(...) do {}while(0) +# endif +#endif + +#ifndef LV_LOG +# if LV_LOG_LEVEL < LV_LOG_LEVEL_NONE +# define LV_LOG(...) lv_log(__VA_ARGS__) +# else +# define LV_LOG(...) do {} while(0) +# endif +#endif + +#else /*LV_USE_LOG*/ + +/*Do nothing if `LV_USE_LOG 0`*/ +#define _lv_log_add(level, file, line, ...) +#define LV_LOG_TRACE(...) do {}while(0) +#define LV_LOG_INFO(...) do {}while(0) +#define LV_LOG_WARN(...) do {}while(0) +#define LV_LOG_ERROR(...) do {}while(0) +#define LV_LOG_USER(...) do {}while(0) +#define LV_LOG(...) do {}while(0) + +#endif /*LV_USE_LOG*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LOG_H*/ diff --git a/include/liblvgl/misc/lv_lru.h b/include/liblvgl/misc/lv_lru.h new file mode 100644 index 0000000..3e9729e --- /dev/null +++ b/include/liblvgl/misc/lv_lru.h @@ -0,0 +1,87 @@ +/** + * @file lv_lru.h + * + */ + +#ifndef LV_LRU_H +#define LV_LRU_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "liblvgl/lv_conf_internal.h" + +#include "lv_types.h" + +#include +#include + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_LRU_OK = 0, + LV_LRU_MISSING_CACHE, + LV_LRU_MISSING_KEY, + LV_LRU_MISSING_VALUE, + LV_LRU_LOCK_ERROR, + LV_LRU_VALUE_TOO_LARGE +} lv_lru_res_t; + +typedef void (lv_lru_free_t)(void * v); +typedef struct _lv_lru_item_t lv_lru_item_t; + +typedef struct lv_lru_t { + lv_lru_item_t ** items; + uint64_t access_count; + size_t free_memory; + size_t total_memory; + size_t average_item_length; + size_t hash_table_size; + uint32_t seed; + lv_lru_free_t * value_free; + lv_lru_free_t * key_free; + lv_lru_item_t * free_items; +} lv_lru_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_lru_t * lv_lru_create(size_t cache_size, size_t average_length, lv_lru_free_t * value_free, + lv_lru_free_t * key_free); + +void lv_lru_del(lv_lru_t * cache); + +lv_lru_res_t lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, void * value, size_t value_length); + +lv_lru_res_t lv_lru_get(lv_lru_t * cache, const void * key, size_t key_size, void ** value); + +lv_lru_res_t lv_lru_remove(lv_lru_t * cache, const void * key, size_t key_size); + +/** + * remove the least recently used item + * + * @todo we can optimise this by finding the n lru items, where n = required_space / average_length + */ +void lv_lru_remove_lru_item(lv_lru_t * cache); +/********************** + * MACROS + **********************/ +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LRU_H*/ diff --git a/include/liblvgl/misc/lv_math.h b/include/liblvgl/misc/lv_math.h new file mode 100644 index 0000000..24f9ea6 --- /dev/null +++ b/include/liblvgl/misc/lv_math.h @@ -0,0 +1,143 @@ +/** + * @file lv_math.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include + +/********************* + * DEFINES + *********************/ +#define LV_TRIGO_SIN_MAX 32767 +#define LV_TRIGO_SHIFT 15 /**< >> LV_TRIGO_SHIFT to normalize*/ + +#define LV_BEZIER_VAL_MAX 1024 /**< Max time in Bezier functions (not [0..1] to use integers)*/ +#define LV_BEZIER_VAL_SHIFT 10 /**< log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t i; + uint16_t f; +} lv_sqrt_res_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +//! @cond Doxygen_Suppress +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +LV_ATTRIBUTE_FAST_MEM int16_t lv_trigo_sin(int16_t angle); + +static inline LV_ATTRIBUTE_FAST_MEM int16_t lv_trigo_cos(int16_t angle) +{ + return lv_trigo_sin(angle + 90); +} + +//! @endcond + +/** + * Calculate a value of a Cubic Bezier function. + * @param t time in range of [0..LV_BEZIER_VAL_MAX] + * @param u0 start values in range of [0..LV_BEZIER_VAL_MAX] + * @param u1 control value 1 values in range of [0..LV_BEZIER_VAL_MAX] + * @param u2 control value 2 in range of [0..LV_BEZIER_VAL_MAX] + * @param u3 end values in range of [0..LV_BEZIER_VAL_MAX] + * @return the value calculated from the given parameters in range of [0..LV_BEZIER_VAL_MAX] + */ +uint32_t lv_bezier3(uint32_t t, uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3); + +/** + * Calculate the atan2 of a vector. + * @param x + * @param y + * @return the angle in degree calculated from the given parameters in range of [0..360] + */ +uint16_t lv_atan2(int x, int y); + +//! @cond Doxygen_Suppress + +/** + * Get the square root of a number + * @param x integer which square root should be calculated + * @param q store the result here. q->i: integer part, q->f: fractional part in 1/256 unit + * @param mask optional to skip some iterations if the magnitude of the root is known. + * Set to 0x8000 by default. + * If root < 16: mask = 0x80 + * If root < 256: mask = 0x800 + * Else: mask = 0x8000 + */ +LV_ATTRIBUTE_FAST_MEM void lv_sqrt(uint32_t x, lv_sqrt_res_t * q, uint32_t mask); + +//! @endcond + +/** + * Calculate the integer exponents. + * @param base + * @param power + * @return base raised to the power exponent + */ +int64_t lv_pow(int64_t base, int8_t exp); + +/** + * Get the mapped of a number given an input and output range + * @param x integer which mapped value should be calculated + * @param min_in min input range + * @param max_in max input range + * @param min_out max output range + * @param max_out max output range + * @return the mapped number + */ +int32_t lv_map(int32_t x, int32_t min_in, int32_t max_in, int32_t min_out, int32_t max_out); + +/** + * Get a pseudo random number in the given range + * @param min the minimum value + * @param max the maximum value + * @return return the random number. min <= return_value <= max + */ +uint32_t lv_rand(uint32_t min, uint32_t max); + +/********************** + * MACROS + **********************/ +#define LV_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define LV_MIN3(a, b, c) (LV_MIN(LV_MIN(a,b), c)) +#define LV_MIN4(a, b, c, d) (LV_MIN(LV_MIN(a,b), LV_MIN(c,d))) + +#define LV_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define LV_MAX3(a, b, c) (LV_MAX(LV_MAX(a,b), c)) +#define LV_MAX4(a, b, c, d) (LV_MAX(LV_MAX(a,b), LV_MAX(c,d))) + +#define LV_CLAMP(min, val, max) (LV_MAX(min, (LV_MIN(val, max)))) + +#define LV_ABS(x) ((x) > 0 ? (x) : (-(x))) +#define LV_UDIV255(x) (((x) * 0x8081U) >> 0x17) + +#define LV_IS_SIGNED(t) (((t)(-1)) < ((t)0)) +#define LV_UMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0xFULL << ((sizeof(t) * 8ULL) - 4ULL))) +#define LV_SMAX_OF(t) (((0x1ULL << ((sizeof(t) * 8ULL) - 1ULL)) - 1ULL) | (0x7ULL << ((sizeof(t) * 8ULL) - 4ULL))) +#define LV_MAX_OF(t) ((unsigned long)(LV_IS_SIGNED(t) ? LV_SMAX_OF(t) : LV_UMAX_OF(t))) + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/misc/lv_mem.h b/include/liblvgl/misc/lv_mem.h new file mode 100644 index 0000000..fd202ab --- /dev/null +++ b/include/liblvgl/misc/lv_mem.h @@ -0,0 +1,243 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include + +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Heap information structure. + */ +typedef struct { + uint32_t total_size; /**< Total heap size*/ + uint32_t free_cnt; + uint32_t free_size; /**< Size of available memory*/ + uint32_t free_biggest_size; + uint32_t used_cnt; + uint32_t max_used; /**< Max size of Heap memory used*/ + uint8_t used_pct; /**< Percentage used*/ + uint8_t frag_pct; /**< Amount of fragmentation*/ +} lv_mem_monitor_t; + +typedef struct { + void * p; + uint16_t size; + uint8_t used : 1; +} lv_mem_buf_t; + +typedef lv_mem_buf_t lv_mem_buf_arr_t[LV_MEM_BUF_MAX_NUM]; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(void); + +/** + * Clean up the memory buffer which frees all the allocated memories. + * @note It work only if `LV_MEM_CUSTOM == 0` + */ +void lv_mem_deinit(void); + +/** + * Allocate a memory dynamically + * @param size size of the memory to allocate in bytes + * @return pointer to the allocated memory + */ +void * lv_mem_alloc(size_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(void * data); + +/** + * Reallocate a memory with a new size. The old content will be kept. + * @param data pointer to an allocated memory. + * Its content will be copied to the new memory block and freed + * @param new_size the desired new size in byte + * @return pointer to the new memory, NULL on failure + */ +void * lv_mem_realloc(void * data_p, size_t new_size); + +/** + * + * @return + */ +lv_res_t lv_mem_test(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a lv_mem_monitor_t variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + + +/** + * Get a temporal buffer with the given size. + * @param size the required size + */ +void * lv_mem_buf_get(uint32_t size); + +/** + * Release a memory buffer + * @param p buffer to release + */ +void lv_mem_buf_release(void * p); + +/** + * Free all memory buffers + */ +void lv_mem_buf_free_all(void); + +//! @cond Doxygen_Suppress + +#if LV_MEMCPY_MEMSET_STD + +/** + * Wrapper for the standard memcpy + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +static inline void * lv_memcpy(void * dst, const void * src, size_t len) +{ + return memcpy(dst, src, len); +} + +/** + * Wrapper for the standard memcpy + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +static inline void * lv_memcpy_small(void * dst, const void * src, size_t len) +{ + return memcpy(dst, src, len); +} + +/** + * Wrapper for the standard memset + * @param dst pointer to the destination buffer + * @param v value to set [0..255] + * @param len number of byte to set + */ +static inline void lv_memset(void * dst, uint8_t v, size_t len) +{ + memset(dst, v, len); +} + +/** + * Wrapper for the standard memset with fixed 0x00 value + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +static inline void lv_memset_00(void * dst, size_t len) +{ + memset(dst, 0x00, len); +} + +/** + * Wrapper for the standard memset with fixed 0xFF value + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +static inline void lv_memset_ff(void * dst, size_t len) +{ + memset(dst, 0xFF, len); +} + +#else +/** + * Same as `memcpy` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +LV_ATTRIBUTE_FAST_MEM void * lv_memcpy(void * dst, const void * src, size_t len); + +/** + * Same as `memcpy` but optimized to copy only a few bytes. + * @param dst pointer to the destination buffer + * @param src pointer to the source buffer + * @param len number of byte to copy + */ +LV_ATTRIBUTE_FAST_MEM static inline void * lv_memcpy_small(void * dst, const void * src, size_t len) +{ + uint8_t * d8 = (uint8_t *)dst; + const uint8_t * s8 = (const uint8_t *)src; + + while(len) { + *d8 = *s8; + d8++; + s8++; + len--; + } + + return dst; +} + +/** + * Same as `memset` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param v value to set [0..255] + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void lv_memset(void * dst, uint8_t v, size_t len); + +/** + * Same as `memset(dst, 0x00, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void lv_memset_00(void * dst, size_t len); + +/** + * Same as `memset(dst, 0xFF, len)` but optimized for 4 byte operation. + * @param dst pointer to the destination buffer + * @param len number of byte to set + */ +LV_ATTRIBUTE_FAST_MEM void lv_memset_ff(void * dst, size_t len); + +//! @endcond + +#endif + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_MEM_H*/ diff --git a/include/liblvgl/misc/lv_printf.h b/include/liblvgl/misc/lv_printf.h new file mode 100644 index 0000000..4cbbd84 --- /dev/null +++ b/include/liblvgl/misc/lv_printf.h @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +/*Original repository: https://github.com/mpaland/printf*/ + +#ifndef _LV_PRINTF_H_ +#define _LV_PRINTF_H_ + +#if defined(__has_include) + #if __has_include() + #include + /* platform-specific printf format for int32_t, usually "d" or "ld" */ + #define LV_PRId32 PRId32 + #define LV_PRIu32 PRIu32 + #else + #define LV_PRId32 "d" + #define LV_PRIu32 "u" + #endif +#else + /* hope this is correct for ports without __has_include or without inttypes.h */ + #define LV_PRId32 "d" + #define LV_PRIu32 "u" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../lv_conf_internal.h" + +#if LV_SPRINTF_CUSTOM == 0 + +#include +#include + +#include "lv_types.h" + +typedef struct { + const char * fmt; + va_list * va; +} lv_vaformat_t; + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +int lv_snprintf(char * buffer, size_t count, const char * format, ...) LV_FORMAT_ATTRIBUTE(3, 4); +int lv_vsnprintf(char * buffer, size_t count, const char * format, va_list va) LV_FORMAT_ATTRIBUTE(3, 0); + +#else +#include LV_SPRINTF_INCLUDE +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif // _LV_PRINTF_H_ diff --git a/include/liblvgl/misc/lv_style.h b/include/liblvgl/misc/lv_style.h new file mode 100644 index 0000000..44a542d --- /dev/null +++ b/include/liblvgl/misc/lv_style.h @@ -0,0 +1,592 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "liblvgl/font/lv_font.h" +#include "lv_color.h" +#include "lv_area.h" +#include "lv_anim.h" +#include "lv_txt.h" +#include "lv_types.h" +#include "lv_assert.h" +#include "lv_bidi.h" + +/********************* + * DEFINES + *********************/ + +#define LV_STYLE_SENTINEL_VALUE 0xAABBCCDD + +/** + * Flags for style behavior + * + * The rest of the flags will have _FLAG added to their name in v9. + */ +#define LV_STYLE_PROP_FLAG_NONE (0) +#define LV_STYLE_PROP_INHERIT (1 << 0) /*Inherited*/ +#define LV_STYLE_PROP_EXT_DRAW (1 << 1) /*Requires ext. draw size update when changed*/ +#define LV_STYLE_PROP_LAYOUT_REFR (1 << 2) /*Requires layout update when changed*/ +#define LV_STYLE_PROP_PARENT_LAYOUT_REFR (1 << 3) /*Requires layout update on parent when changed*/ +#define LV_STYLE_PROP_LAYER_REFR (1 << 4) /*Affects layer handling*/ +#define LV_STYLE_PROP_ALL (0x1F) /*Indicating all flags*/ + +/** + * Other constants + */ +#define LV_IMG_ZOOM_NONE 256 /*Value for not zooming the image*/ +LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE); + +// *INDENT-OFF* +#if LV_USE_ASSERT_STYLE +#define LV_STYLE_CONST_INIT(var_name, prop_array) \ + const lv_style_t var_name = { \ + .sentinel = LV_STYLE_SENTINEL_VALUE, \ + .v_p = { .const_props = prop_array }, \ + .has_group = 0xFF, \ + .prop1 = LV_STYLE_PROP_ANY, \ + .prop_cnt = (sizeof(prop_array) / sizeof((prop_array)[0])), \ + } +#else +#define LV_STYLE_CONST_INIT(var_name, prop_array) \ + const lv_style_t var_name = { \ + .v_p = { .const_props = prop_array }, \ + .has_group = 0xFF, \ + .prop1 = LV_STYLE_PROP_ANY, \ + .prop_cnt = (sizeof(prop_array) / sizeof((prop_array)[0])), \ + } +#endif +// *INDENT-ON* + +#define LV_STYLE_PROP_META_INHERIT 0x8000 +#define LV_STYLE_PROP_META_INITIAL 0x4000 +#define LV_STYLE_PROP_META_MASK (LV_STYLE_PROP_META_INHERIT | LV_STYLE_PROP_META_INITIAL) + +#define LV_STYLE_PROP_ID_MASK(prop) ((lv_style_prop_t)((prop) & ~LV_STYLE_PROP_META_MASK)) + +/********************** + * TYPEDEFS + **********************/ + +/** + * Possible options how to blend opaque drawings + */ +enum { + LV_BLEND_MODE_NORMAL, /**< Simply mix according to the opacity value*/ + LV_BLEND_MODE_ADDITIVE, /**< Add the respective color channels*/ + LV_BLEND_MODE_SUBTRACTIVE,/**< Subtract the foreground from the background*/ + LV_BLEND_MODE_MULTIPLY, /**< Multiply the foreground and background*/ + LV_BLEND_MODE_REPLACE, /**< Replace background with foreground in the area*/ +}; + +typedef uint8_t lv_blend_mode_t; + +/** + * Some options to apply decorations on texts. + * 'OR'ed values can be used. + */ +enum { + LV_TEXT_DECOR_NONE = 0x00, + LV_TEXT_DECOR_UNDERLINE = 0x01, + LV_TEXT_DECOR_STRIKETHROUGH = 0x02, +}; + +typedef uint8_t lv_text_decor_t; + +/** + * Selects on which sides border should be drawn + * 'OR'ed values can be used. + */ +enum { + LV_BORDER_SIDE_NONE = 0x00, + LV_BORDER_SIDE_BOTTOM = 0x01, + LV_BORDER_SIDE_TOP = 0x02, + LV_BORDER_SIDE_LEFT = 0x04, + LV_BORDER_SIDE_RIGHT = 0x08, + LV_BORDER_SIDE_FULL = 0x0F, + LV_BORDER_SIDE_INTERNAL = 0x10, /**< FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_side_t; + +/** + * The direction of the gradient. + */ +enum { + LV_GRAD_DIR_NONE, /**< No gradient (the `grad_color` property is ignored)*/ + LV_GRAD_DIR_VER, /**< Vertical (top to bottom) gradient*/ + LV_GRAD_DIR_HOR, /**< Horizontal (left to right) gradient*/ +}; + +typedef uint8_t lv_grad_dir_t; + +/** + * The dithering algorithm for the gradient + * Depends on LV_DITHER_GRADIENT + */ +enum { + LV_DITHER_NONE, /**< No dithering, colors are just quantized to the output resolution*/ + LV_DITHER_ORDERED, /**< Ordered dithering. Faster to compute and use less memory but lower quality*/ + LV_DITHER_ERR_DIFF, /**< Error diffusion mode. Slower to compute and use more memory but give highest dither quality*/ +}; + +typedef uint8_t lv_dither_mode_t; + +/** A gradient stop definition. + * This matches a color and a position in a virtual 0-255 scale. + */ +typedef struct { + lv_color_t color; /**< The stop color */ + uint8_t frac; /**< The stop position in 1/255 unit */ +} lv_gradient_stop_t; + +/** A descriptor of a gradient. */ +typedef struct { + lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; /**< A gradient stop array */ + uint8_t stops_count; /**< The number of used stops in the array */ + lv_grad_dir_t dir : 3; /**< The gradient direction. + * Any of LV_GRAD_DIR_HOR, LV_GRAD_DIR_VER, LV_GRAD_DIR_NONE */ + lv_dither_mode_t dither : 3; /**< Whether to dither the gradient or not. + * Any of LV_DITHER_NONE, LV_DITHER_ORDERED, LV_DITHER_ERR_DIFF */ +} lv_grad_dsc_t; + +/** + * A common type to handle all the property types in the same way. + */ +typedef union { + int32_t num; /**< Number integer number (opacity, enums, booleans or "normal" numbers)*/ + const void * ptr; /**< Constant pointers (font, cone text, etc)*/ + lv_color_t color; /**< Colors*/ +} lv_style_value_t; + +/** + * Enumeration of all built in style properties + * + * Props are split into groups of 16. When adding a new prop to a group, ensure it does not overflow into the next one. + */ +typedef enum { + LV_STYLE_PROP_INV = 0, + + /*Group 0*/ + LV_STYLE_WIDTH = 1, + LV_STYLE_MIN_WIDTH = 2, + LV_STYLE_MAX_WIDTH = 3, + LV_STYLE_HEIGHT = 4, + LV_STYLE_MIN_HEIGHT = 5, + LV_STYLE_MAX_HEIGHT = 6, + LV_STYLE_X = 7, + LV_STYLE_Y = 8, + LV_STYLE_ALIGN = 9, + LV_STYLE_LAYOUT = 10, + LV_STYLE_RADIUS = 11, + + /*Group 1*/ + LV_STYLE_PAD_TOP = 16, + LV_STYLE_PAD_BOTTOM = 17, + LV_STYLE_PAD_LEFT = 18, + LV_STYLE_PAD_RIGHT = 19, + LV_STYLE_PAD_ROW = 20, + LV_STYLE_PAD_COLUMN = 21, + LV_STYLE_BASE_DIR = 22, + LV_STYLE_CLIP_CORNER = 23, + + /*Group 2*/ + LV_STYLE_BG_COLOR = 32, + LV_STYLE_BG_OPA = 33, + LV_STYLE_BG_GRAD_COLOR = 34, + LV_STYLE_BG_GRAD_DIR = 35, + LV_STYLE_BG_MAIN_STOP = 36, + LV_STYLE_BG_GRAD_STOP = 37, + LV_STYLE_BG_GRAD = 38, + LV_STYLE_BG_DITHER_MODE = 39, + LV_STYLE_BG_IMG_SRC = 40, + LV_STYLE_BG_IMG_OPA = 41, + LV_STYLE_BG_IMG_RECOLOR = 42, + LV_STYLE_BG_IMG_RECOLOR_OPA = 43, + LV_STYLE_BG_IMG_TILED = 44, + + /*Group 3*/ + LV_STYLE_BORDER_COLOR = 48, + LV_STYLE_BORDER_OPA = 49, + LV_STYLE_BORDER_WIDTH = 50, + LV_STYLE_BORDER_SIDE = 51, + LV_STYLE_BORDER_POST = 52, + LV_STYLE_OUTLINE_WIDTH = 53, + LV_STYLE_OUTLINE_COLOR = 54, + LV_STYLE_OUTLINE_OPA = 55, + LV_STYLE_OUTLINE_PAD = 56, + + /*Group 4*/ + LV_STYLE_SHADOW_WIDTH = 64, + LV_STYLE_SHADOW_OFS_X = 65, + LV_STYLE_SHADOW_OFS_Y = 66, + LV_STYLE_SHADOW_SPREAD = 67, + LV_STYLE_SHADOW_COLOR = 68, + LV_STYLE_SHADOW_OPA = 69, + LV_STYLE_IMG_OPA = 70, + LV_STYLE_IMG_RECOLOR = 71, + LV_STYLE_IMG_RECOLOR_OPA = 72, + LV_STYLE_LINE_WIDTH = 73, + LV_STYLE_LINE_DASH_WIDTH = 74, + LV_STYLE_LINE_DASH_GAP = 75, + LV_STYLE_LINE_ROUNDED = 76, + LV_STYLE_LINE_COLOR = 77, + LV_STYLE_LINE_OPA = 78, + + /*Group 5*/ + LV_STYLE_ARC_WIDTH = 80, + LV_STYLE_ARC_ROUNDED = 81, + LV_STYLE_ARC_COLOR = 82, + LV_STYLE_ARC_OPA = 83, + LV_STYLE_ARC_IMG_SRC = 84, + LV_STYLE_TEXT_COLOR = 85, + LV_STYLE_TEXT_OPA = 86, + LV_STYLE_TEXT_FONT = 87, + LV_STYLE_TEXT_LETTER_SPACE = 88, + LV_STYLE_TEXT_LINE_SPACE = 89, + LV_STYLE_TEXT_DECOR = 90, + LV_STYLE_TEXT_ALIGN = 91, + + /*Group 6*/ + LV_STYLE_OPA = 96, + LV_STYLE_COLOR_FILTER_DSC = 97, + LV_STYLE_COLOR_FILTER_OPA = 98, + LV_STYLE_ANIM = 99, + LV_STYLE_ANIM_TIME = 100, + LV_STYLE_ANIM_SPEED = 101, + LV_STYLE_TRANSITION = 102, + LV_STYLE_BLEND_MODE = 103, + LV_STYLE_TRANSFORM_WIDTH = 104, + LV_STYLE_TRANSFORM_HEIGHT = 105, + LV_STYLE_TRANSLATE_X = 106, + LV_STYLE_TRANSLATE_Y = 107, + LV_STYLE_TRANSFORM_ZOOM = 108, + LV_STYLE_TRANSFORM_ANGLE = 109, + LV_STYLE_TRANSFORM_PIVOT_X = 110, + LV_STYLE_TRANSFORM_PIVOT_Y = 111, + + _LV_STYLE_LAST_BUILT_IN_PROP = 111, + _LV_STYLE_NUM_BUILT_IN_PROPS = _LV_STYLE_LAST_BUILT_IN_PROP + 1, + + LV_STYLE_PROP_ANY = 0xFFFF, + _LV_STYLE_PROP_CONST = 0xFFFF /* magic value for const styles */ +} lv_style_prop_t; + +enum { + LV_STYLE_RES_NOT_FOUND, + LV_STYLE_RES_FOUND, + LV_STYLE_RES_INHERIT +}; + +typedef uint8_t lv_style_res_t; + +/** + * Descriptor for style transitions + */ +typedef struct { + const lv_style_prop_t * props; /**< An array with the properties to animate.*/ +#if LV_USE_USER_DATA + void * user_data; /**< A custom user data that will be passed to the animation's user_data */ +#endif + lv_anim_path_cb_t path_xcb; /**< A path for the animation.*/ + uint32_t time; /**< Duration of the transition in [ms]*/ + uint32_t delay; /**< Delay before the transition in [ms]*/ +} lv_style_transition_dsc_t; + +/** + * Descriptor of a constant style property. + */ +typedef struct { + lv_style_prop_t prop; + lv_style_value_t value; +} lv_style_const_prop_t; + +/** + * Descriptor of a style (a collection of properties and values). + */ +typedef struct { + +#if LV_USE_ASSERT_STYLE + uint32_t sentinel; +#endif + + /*If there is only one property store it directly. + *For more properties allocate an array*/ + union { + lv_style_value_t value1; + uint8_t * values_and_props; + const lv_style_const_prop_t * const_props; + } v_p; + + uint16_t prop1; + uint8_t has_group; + uint8_t prop_cnt; +} lv_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initialize a style + * @param style pointer to a style to initialize + * @note Do not call `lv_style_init` on styles that already have some properties + * because this function won't free the used memory, just sets a default state for the style. + * In other words be sure to initialize styles only once! + */ +void lv_style_init(lv_style_t * style); + +/** + * Clear all properties from a style and free all allocated memories. + * @param style pointer to a style + */ +void lv_style_reset(lv_style_t * style); + +/** + * Register a new style property for custom usage + * @return a new property ID, or LV_STYLE_PROP_INV if there are no more available. + * @example + * lv_style_prop_t MY_PROP; + * static inline void lv_style_set_my_prop(lv_style_t * style, lv_color_t value) { + * lv_style_value_t v = {.color = value}; lv_style_set_prop(style, MY_PROP, v); } + * + * ... + * MY_PROP = lv_style_register_prop(); + * ... + * lv_style_set_my_prop(&style1, lv_palette_main(LV_PALETTE_RED)); + */ +lv_style_prop_t lv_style_register_prop(uint8_t flag); + +/** + * Get the number of custom properties that have been registered thus far. + */ +lv_style_prop_t lv_style_get_num_custom_props(void); + +/** + * Remove a property from a style + * @param style pointer to a style + * @param prop a style property ORed with a state. + * @return true: the property was found and removed; false: the property wasn't found + */ +bool lv_style_remove_prop(lv_style_t * style, lv_style_prop_t prop); + +/** + * Set the value of property in a style. + * This function shouldn't be used directly by the user. + * Instead use `lv_style_set_()`. E.g. `lv_style_set_bg_color()` + * @param style pointer to style + * @param prop the ID of a property (e.g. `LV_STYLE_BG_COLOR`) + * @param value `lv_style_value_t` variable in which a field is set according to the type of `prop` + */ +void lv_style_set_prop(lv_style_t * style, lv_style_prop_t prop, lv_style_value_t value); + +/** + * Set a special meta state for a property in a style. + * This function shouldn't be used directly by the user. + * @param style pointer to style + * @param prop the ID of a property (e.g. `LV_STYLE_BG_COLOR`) + * @param meta the meta value to attach to the property in the style + */ +void lv_style_set_prop_meta(lv_style_t * style, lv_style_prop_t prop, uint16_t meta); + +/** + * Get the value of a property + * @param style pointer to a style + * @param prop the ID of a property + * @param value pointer to a `lv_style_value_t` variable to store the value + * @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged) + * LV_RES_OK: the property was fond, and `value` is set accordingly + * @note For performance reasons there are no sanity check on `style` + */ +lv_style_res_t lv_style_get_prop(const lv_style_t * style, lv_style_prop_t prop, lv_style_value_t * value); + +/** + * Initialize a transition descriptor. + * @param tr pointer to a transition descriptor to initialize + * @param props an array with the properties to transition. The last element must be zero. + * @param path_cb an animation path (ease) callback. If `NULL` liner path will be used. + * @param time duration of the transition in [ms] + * @param delay delay before the transition in [ms] + * @param user_data any custom data that will be saved in the transition animation and will be available when `path_cb` is called + * @example + * const static lv_style_prop_t trans_props[] = { LV_STYLE_BG_OPA, LV_STYLE_BG_COLOR, 0 }; + * static lv_style_transition_dsc_t trans1; + * lv_style_transition_dsc_init(&trans1, trans_props, NULL, 300, 0, NULL); + */ +void lv_style_transition_dsc_init(lv_style_transition_dsc_t * tr, const lv_style_prop_t props[], + lv_anim_path_cb_t path_cb, uint32_t time, uint32_t delay, void * user_data); + +/** + * Get the default value of a property + * @param prop the ID of a property + * @return the default value + */ +lv_style_value_t lv_style_prop_get_default(lv_style_prop_t prop); + +/** + * Get the value of a property + * @param style pointer to a style + * @param prop the ID of a property + * @param value pointer to a `lv_style_value_t` variable to store the value + * @return LV_RES_INV: the property wasn't found in the style (`value` is unchanged) + * LV_RES_OK: the property was fond, and `value` is set accordingly + * @note For performance reasons there are no sanity check on `style` + * @note This function is the same as ::lv_style_get_prop but inlined. Use it only on performance critical places + */ +static inline lv_style_res_t lv_style_get_prop_inlined(const lv_style_t * style, lv_style_prop_t prop, + lv_style_value_t * value) +{ + if(style->prop1 == LV_STYLE_PROP_ANY) { + const lv_style_const_prop_t * const_prop; + uint32_t i; + for(i = 0; i < style->prop_cnt; i++) { + const_prop = style->v_p.const_props + i; + lv_style_prop_t prop_id = LV_STYLE_PROP_ID_MASK(const_prop->prop); + if(prop_id == prop) { + if(const_prop->prop & LV_STYLE_PROP_META_INHERIT) + return LV_STYLE_RES_INHERIT; + *value = (const_prop->prop & LV_STYLE_PROP_META_INITIAL) ? lv_style_prop_get_default(prop_id) : const_prop->value; + return LV_STYLE_RES_FOUND; + } + } + return LV_STYLE_RES_NOT_FOUND; + } + + if(style->prop_cnt == 0) return LV_STYLE_RES_NOT_FOUND; + + if(style->prop_cnt > 1) { + uint8_t * tmp = style->v_p.values_and_props + style->prop_cnt * sizeof(lv_style_value_t); + uint16_t * props = (uint16_t *)tmp; + uint32_t i; + for(i = 0; i < style->prop_cnt; i++) { + lv_style_prop_t prop_id = LV_STYLE_PROP_ID_MASK(props[i]); + if(prop_id == prop) { + if(props[i] & LV_STYLE_PROP_META_INHERIT) + return LV_STYLE_RES_INHERIT; + if(props[i] & LV_STYLE_PROP_META_INITIAL) + *value = lv_style_prop_get_default(prop_id); + else { + lv_style_value_t * values = (lv_style_value_t *)style->v_p.values_and_props; + *value = values[i]; + } + return LV_STYLE_RES_FOUND; + } + } + } + else if(LV_STYLE_PROP_ID_MASK(style->prop1) == prop) { + if(style->prop1 & LV_STYLE_PROP_META_INHERIT) + return LV_STYLE_RES_INHERIT; + *value = (style->prop1 & LV_STYLE_PROP_META_INITIAL) ? lv_style_prop_get_default(LV_STYLE_PROP_ID_MASK( + style->prop1)) : style->v_p.value1; + return LV_STYLE_RES_FOUND; + } + return LV_STYLE_RES_NOT_FOUND; +} + +/** + * Checks if a style is empty (has no properties) + * @param style pointer to a style + * @return true if the style is empty + */ +bool lv_style_is_empty(const lv_style_t * style); + +/** + * Tell the group of a property. If the a property from a group is set in a style the (1 << group) bit of style->has_group is set. + * It allows early skipping the style if the property is not exists in the style at all. + * @param prop a style property + * @return the group [0..7] 7 means all the custom properties with index > 112 + */ +uint8_t _lv_style_get_prop_group(lv_style_prop_t prop); + +/** + * Get the flags of a built-in or custom property. + * + * @param prop a style property + * @return the flags of the property + */ +uint8_t _lv_style_prop_lookup_flags(lv_style_prop_t prop); + +#include "lv_style_gen.h" + +static inline void lv_style_set_size(lv_style_t * style, lv_coord_t value) +{ + lv_style_set_width(style, value); + lv_style_set_height(style, value); +} + +static inline void lv_style_set_pad_all(lv_style_t * style, lv_coord_t value) +{ + lv_style_set_pad_left(style, value); + lv_style_set_pad_right(style, value); + lv_style_set_pad_top(style, value); + lv_style_set_pad_bottom(style, value); +} + +static inline void lv_style_set_pad_hor(lv_style_t * style, lv_coord_t value) +{ + lv_style_set_pad_left(style, value); + lv_style_set_pad_right(style, value); +} + +static inline void lv_style_set_pad_ver(lv_style_t * style, lv_coord_t value) +{ + lv_style_set_pad_top(style, value); + lv_style_set_pad_bottom(style, value); +} + +static inline void lv_style_set_pad_gap(lv_style_t * style, lv_coord_t value) +{ + lv_style_set_pad_row(style, value); + lv_style_set_pad_column(style, value); +} + +/** + * @brief Check if the style property has a specified behavioral flag. + * + * Do not pass multiple flags to this function as backwards-compatibility is not guaranteed + * for that. + * + * @param prop Property ID + * @param flag Flag + * @return true if the flag is set for this property + */ +static inline bool lv_style_prop_has_flag(lv_style_prop_t prop, uint8_t flag) +{ + return _lv_style_prop_lookup_flags(prop) & flag; +} + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#if LV_USE_ASSERT_STYLE +# define LV_ASSERT_STYLE(style_p) \ + do { \ + LV_ASSERT_MSG(style_p != NULL, "The style is NULL"); \ + LV_ASSERT_MSG(style_p->sentinel == LV_STYLE_SENTINEL_VALUE, "Style is not initialized or corrupted"); \ + } while(0) +#else +# define LV_ASSERT_STYLE(p) do{}while(0) +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/include/liblvgl/misc/lv_style_gen.h b/include/liblvgl/misc/lv_style_gen.h new file mode 100644 index 0000000..8bf3b68 --- /dev/null +++ b/include/liblvgl/misc/lv_style_gen.h @@ -0,0 +1,504 @@ +void lv_style_set_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_min_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_max_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_height(lv_style_t * style, lv_coord_t value); +void lv_style_set_min_height(lv_style_t * style, lv_coord_t value); +void lv_style_set_max_height(lv_style_t * style, lv_coord_t value); +void lv_style_set_x(lv_style_t * style, lv_coord_t value); +void lv_style_set_y(lv_style_t * style, lv_coord_t value); +void lv_style_set_align(lv_style_t * style, lv_align_t value); +void lv_style_set_transform_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_transform_height(lv_style_t * style, lv_coord_t value); +void lv_style_set_translate_x(lv_style_t * style, lv_coord_t value); +void lv_style_set_translate_y(lv_style_t * style, lv_coord_t value); +void lv_style_set_transform_zoom(lv_style_t * style, lv_coord_t value); +void lv_style_set_transform_angle(lv_style_t * style, lv_coord_t value); +void lv_style_set_transform_pivot_x(lv_style_t * style, lv_coord_t value); +void lv_style_set_transform_pivot_y(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_top(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_bottom(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_left(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_right(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_row(lv_style_t * style, lv_coord_t value); +void lv_style_set_pad_column(lv_style_t * style, lv_coord_t value); +void lv_style_set_bg_color(lv_style_t * style, lv_color_t value); +void lv_style_set_bg_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_bg_grad_color(lv_style_t * style, lv_color_t value); +void lv_style_set_bg_grad_dir(lv_style_t * style, lv_grad_dir_t value); +void lv_style_set_bg_main_stop(lv_style_t * style, lv_coord_t value); +void lv_style_set_bg_grad_stop(lv_style_t * style, lv_coord_t value); +void lv_style_set_bg_grad(lv_style_t * style, const lv_grad_dsc_t * value); +void lv_style_set_bg_dither_mode(lv_style_t * style, lv_dither_mode_t value); +void lv_style_set_bg_img_src(lv_style_t * style, const void * value); +void lv_style_set_bg_img_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_bg_img_recolor(lv_style_t * style, lv_color_t value); +void lv_style_set_bg_img_recolor_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_bg_img_tiled(lv_style_t * style, bool value); +void lv_style_set_border_color(lv_style_t * style, lv_color_t value); +void lv_style_set_border_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_border_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_border_side(lv_style_t * style, lv_border_side_t value); +void lv_style_set_border_post(lv_style_t * style, bool value); +void lv_style_set_outline_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_outline_color(lv_style_t * style, lv_color_t value); +void lv_style_set_outline_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_outline_pad(lv_style_t * style, lv_coord_t value); +void lv_style_set_shadow_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_shadow_ofs_x(lv_style_t * style, lv_coord_t value); +void lv_style_set_shadow_ofs_y(lv_style_t * style, lv_coord_t value); +void lv_style_set_shadow_spread(lv_style_t * style, lv_coord_t value); +void lv_style_set_shadow_color(lv_style_t * style, lv_color_t value); +void lv_style_set_shadow_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_img_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_img_recolor(lv_style_t * style, lv_color_t value); +void lv_style_set_img_recolor_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_line_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_line_dash_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_line_dash_gap(lv_style_t * style, lv_coord_t value); +void lv_style_set_line_rounded(lv_style_t * style, bool value); +void lv_style_set_line_color(lv_style_t * style, lv_color_t value); +void lv_style_set_line_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_arc_width(lv_style_t * style, lv_coord_t value); +void lv_style_set_arc_rounded(lv_style_t * style, bool value); +void lv_style_set_arc_color(lv_style_t * style, lv_color_t value); +void lv_style_set_arc_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_arc_img_src(lv_style_t * style, const void * value); +void lv_style_set_text_color(lv_style_t * style, lv_color_t value); +void lv_style_set_text_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_text_font(lv_style_t * style, const lv_font_t * value); +void lv_style_set_text_letter_space(lv_style_t * style, lv_coord_t value); +void lv_style_set_text_line_space(lv_style_t * style, lv_coord_t value); +void lv_style_set_text_decor(lv_style_t * style, lv_text_decor_t value); +void lv_style_set_text_align(lv_style_t * style, lv_text_align_t value); +void lv_style_set_radius(lv_style_t * style, lv_coord_t value); +void lv_style_set_clip_corner(lv_style_t * style, bool value); +void lv_style_set_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_color_filter_dsc(lv_style_t * style, const lv_color_filter_dsc_t * value); +void lv_style_set_color_filter_opa(lv_style_t * style, lv_opa_t value); +void lv_style_set_anim(lv_style_t * style, const lv_anim_t * value); +void lv_style_set_anim_time(lv_style_t * style, uint32_t value); +void lv_style_set_anim_speed(lv_style_t * style, uint32_t value); +void lv_style_set_transition(lv_style_t * style, const lv_style_transition_dsc_t * value); +void lv_style_set_blend_mode(lv_style_t * style, lv_blend_mode_t value); +void lv_style_set_layout(lv_style_t * style, uint16_t value); +void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value); + +#define LV_STYLE_CONST_WIDTH(val) \ + { \ + .prop = LV_STYLE_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_MIN_WIDTH(val) \ + { \ + .prop = LV_STYLE_MIN_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_MAX_WIDTH(val) \ + { \ + .prop = LV_STYLE_MAX_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_HEIGHT(val) \ + { \ + .prop = LV_STYLE_HEIGHT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_MIN_HEIGHT(val) \ + { \ + .prop = LV_STYLE_MIN_HEIGHT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_MAX_HEIGHT(val) \ + { \ + .prop = LV_STYLE_MAX_HEIGHT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_X(val) \ + { \ + .prop = LV_STYLE_X, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_Y(val) \ + { \ + .prop = LV_STYLE_Y, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ALIGN(val) \ + { \ + .prop = LV_STYLE_ALIGN, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_WIDTH(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_HEIGHT(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_HEIGHT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSLATE_X(val) \ + { \ + .prop = LV_STYLE_TRANSLATE_X, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSLATE_Y(val) \ + { \ + .prop = LV_STYLE_TRANSLATE_Y, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_ZOOM(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_ZOOM, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_ANGLE(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_ANGLE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_PIVOT_X(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_PIVOT_X, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSFORM_PIVOT_Y(val) \ + { \ + .prop = LV_STYLE_TRANSFORM_PIVOT_Y, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_TOP(val) \ + { \ + .prop = LV_STYLE_PAD_TOP, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_BOTTOM(val) \ + { \ + .prop = LV_STYLE_PAD_BOTTOM, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_LEFT(val) \ + { \ + .prop = LV_STYLE_PAD_LEFT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_RIGHT(val) \ + { \ + .prop = LV_STYLE_PAD_RIGHT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_ROW(val) \ + { \ + .prop = LV_STYLE_PAD_ROW, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_PAD_COLUMN(val) \ + { \ + .prop = LV_STYLE_PAD_COLUMN, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_COLOR(val) \ + { \ + .prop = LV_STYLE_BG_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_BG_OPA(val) \ + { \ + .prop = LV_STYLE_BG_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_GRAD_COLOR(val) \ + { \ + .prop = LV_STYLE_BG_GRAD_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_BG_GRAD_DIR(val) \ + { \ + .prop = LV_STYLE_BG_GRAD_DIR, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_MAIN_STOP(val) \ + { \ + .prop = LV_STYLE_BG_MAIN_STOP, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_GRAD_STOP(val) \ + { \ + .prop = LV_STYLE_BG_GRAD_STOP, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_GRAD(val) \ + { \ + .prop = LV_STYLE_BG_GRAD, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_BG_DITHER_MODE(val) \ + { \ + .prop = LV_STYLE_BG_DITHER_MODE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_IMG_SRC(val) \ + { \ + .prop = LV_STYLE_BG_IMG_SRC, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_BG_IMG_OPA(val) \ + { \ + .prop = LV_STYLE_BG_IMG_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_IMG_RECOLOR(val) \ + { \ + .prop = LV_STYLE_BG_IMG_RECOLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_BG_IMG_RECOLOR_OPA(val) \ + { \ + .prop = LV_STYLE_BG_IMG_RECOLOR_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BG_IMG_TILED(val) \ + { \ + .prop = LV_STYLE_BG_IMG_TILED, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BORDER_COLOR(val) \ + { \ + .prop = LV_STYLE_BORDER_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_BORDER_OPA(val) \ + { \ + .prop = LV_STYLE_BORDER_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BORDER_WIDTH(val) \ + { \ + .prop = LV_STYLE_BORDER_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BORDER_SIDE(val) \ + { \ + .prop = LV_STYLE_BORDER_SIDE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BORDER_POST(val) \ + { \ + .prop = LV_STYLE_BORDER_POST, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_OUTLINE_WIDTH(val) \ + { \ + .prop = LV_STYLE_OUTLINE_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_OUTLINE_COLOR(val) \ + { \ + .prop = LV_STYLE_OUTLINE_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_OUTLINE_OPA(val) \ + { \ + .prop = LV_STYLE_OUTLINE_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_OUTLINE_PAD(val) \ + { \ + .prop = LV_STYLE_OUTLINE_PAD, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_SHADOW_WIDTH(val) \ + { \ + .prop = LV_STYLE_SHADOW_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_SHADOW_OFS_X(val) \ + { \ + .prop = LV_STYLE_SHADOW_OFS_X, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_SHADOW_OFS_Y(val) \ + { \ + .prop = LV_STYLE_SHADOW_OFS_Y, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_SHADOW_SPREAD(val) \ + { \ + .prop = LV_STYLE_SHADOW_SPREAD, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_SHADOW_COLOR(val) \ + { \ + .prop = LV_STYLE_SHADOW_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_SHADOW_OPA(val) \ + { \ + .prop = LV_STYLE_SHADOW_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_IMG_OPA(val) \ + { \ + .prop = LV_STYLE_IMG_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_IMG_RECOLOR(val) \ + { \ + .prop = LV_STYLE_IMG_RECOLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_IMG_RECOLOR_OPA(val) \ + { \ + .prop = LV_STYLE_IMG_RECOLOR_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LINE_WIDTH(val) \ + { \ + .prop = LV_STYLE_LINE_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LINE_DASH_WIDTH(val) \ + { \ + .prop = LV_STYLE_LINE_DASH_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LINE_DASH_GAP(val) \ + { \ + .prop = LV_STYLE_LINE_DASH_GAP, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LINE_ROUNDED(val) \ + { \ + .prop = LV_STYLE_LINE_ROUNDED, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LINE_COLOR(val) \ + { \ + .prop = LV_STYLE_LINE_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_LINE_OPA(val) \ + { \ + .prop = LV_STYLE_LINE_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ARC_WIDTH(val) \ + { \ + .prop = LV_STYLE_ARC_WIDTH, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ARC_ROUNDED(val) \ + { \ + .prop = LV_STYLE_ARC_ROUNDED, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ARC_COLOR(val) \ + { \ + .prop = LV_STYLE_ARC_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_ARC_OPA(val) \ + { \ + .prop = LV_STYLE_ARC_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ARC_IMG_SRC(val) \ + { \ + .prop = LV_STYLE_ARC_IMG_SRC, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_TEXT_COLOR(val) \ + { \ + .prop = LV_STYLE_TEXT_COLOR, .value = { .color = val } \ + } + +#define LV_STYLE_CONST_TEXT_OPA(val) \ + { \ + .prop = LV_STYLE_TEXT_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TEXT_FONT(val) \ + { \ + .prop = LV_STYLE_TEXT_FONT, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_TEXT_LETTER_SPACE(val) \ + { \ + .prop = LV_STYLE_TEXT_LETTER_SPACE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TEXT_LINE_SPACE(val) \ + { \ + .prop = LV_STYLE_TEXT_LINE_SPACE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TEXT_DECOR(val) \ + { \ + .prop = LV_STYLE_TEXT_DECOR, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TEXT_ALIGN(val) \ + { \ + .prop = LV_STYLE_TEXT_ALIGN, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_RADIUS(val) \ + { \ + .prop = LV_STYLE_RADIUS, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_CLIP_CORNER(val) \ + { \ + .prop = LV_STYLE_CLIP_CORNER, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_OPA(val) \ + { \ + .prop = LV_STYLE_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_COLOR_FILTER_DSC(val) \ + { \ + .prop = LV_STYLE_COLOR_FILTER_DSC, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_COLOR_FILTER_OPA(val) \ + { \ + .prop = LV_STYLE_COLOR_FILTER_OPA, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ANIM(val) \ + { \ + .prop = LV_STYLE_ANIM, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_ANIM_TIME(val) \ + { \ + .prop = LV_STYLE_ANIM_TIME, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_ANIM_SPEED(val) \ + { \ + .prop = LV_STYLE_ANIM_SPEED, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_TRANSITION(val) \ + { \ + .prop = LV_STYLE_TRANSITION, .value = { .ptr = val } \ + } + +#define LV_STYLE_CONST_BLEND_MODE(val) \ + { \ + .prop = LV_STYLE_BLEND_MODE, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_LAYOUT(val) \ + { \ + .prop = LV_STYLE_LAYOUT, .value = { .num = (int32_t)val } \ + } + +#define LV_STYLE_CONST_BASE_DIR(val) \ + { \ + .prop = LV_STYLE_BASE_DIR, .value = { .num = (int32_t)val } \ + } diff --git a/include/liblvgl/misc/lv_templ.h b/include/liblvgl/misc/lv_templ.h new file mode 100644 index 0000000..f7e3c26 --- /dev/null +++ b/include/liblvgl/misc/lv_templ.h @@ -0,0 +1,37 @@ +/** + * @file lv_templ.h + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/include/liblvgl/misc/lv_timer.h b/include/liblvgl/misc/lv_timer.h new file mode 100644 index 0000000..16572d3 --- /dev/null +++ b/include/liblvgl/misc/lv_timer.h @@ -0,0 +1,183 @@ +/** + * @file lv_timer.h + */ + +#ifndef LV_TIMER_H +#define LV_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/hal/lv_hal_tick.h" + +#include +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TIMER_HANDLER +#define LV_ATTRIBUTE_TIMER_HANDLER +#endif + +#define LV_NO_TIMER_READY 0xFFFFFFFF + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_timer_t; + +/** + * Timers execute this type of functions. + */ +typedef void (*lv_timer_cb_t)(struct _lv_timer_t *); + +/** + * Descriptor of a lv_timer + */ +typedef struct _lv_timer_t { + uint32_t period; /**< How often the timer should run*/ + uint32_t last_run; /**< Last time the timer ran*/ + lv_timer_cb_t timer_cb; /**< Timer function*/ + void * user_data; /**< Custom user data*/ + int32_t repeat_count; /**< 1: One time; -1 : infinity; n>0: residual times*/ + uint32_t paused : 1; +} lv_timer_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_timer module + */ +void _lv_timer_core_init(void); + +//! @cond Doxygen_Suppress + +/** + * Call it periodically to handle lv_timers. + * @return time till it needs to be run next (in ms) + */ +LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void); + +//! @endcond + +/** + * Call it in the super-loop of main() or threads. It will run lv_timer_handler() + * with a given period in ms. You can use it with sleep or delay in OS environment. + * This function is used to simplify the porting. + * @param __ms the period for running lv_timer_handler() + */ +static inline LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler_run_in_period(uint32_t ms) +{ + static uint32_t last_tick = 0; + uint32_t curr_tick = lv_tick_get(); + + if((curr_tick - last_tick) >= (ms)) { + last_tick = curr_tick; + return lv_timer_handler(); + } + return 1; +} + +/** + * Create an "empty" timer. It needs to initialized with at least + * `lv_timer_set_cb` and `lv_timer_set_period` + * @return pointer to the created timer + */ +lv_timer_t * lv_timer_create_basic(void); + +/** + * Create a new lv_timer + * @param timer_xcb a callback to call periodically. + * (the 'x' in the argument name indicates that it's not a fully generic function because it not follows + * the `func_name(object, callback, ...)` convention) + * @param period call period in ms unit + * @param user_data custom parameter + * @return pointer to the new timer + */ +lv_timer_t * lv_timer_create(lv_timer_cb_t timer_xcb, uint32_t period, void * user_data); + +/** + * Delete a lv_timer + * @param timer pointer to an lv_timer + */ +void lv_timer_del(lv_timer_t * timer); + +/** + * Pause/resume a timer. + * @param timer pointer to an lv_timer + */ +void lv_timer_pause(lv_timer_t * timer); + +void lv_timer_resume(lv_timer_t * timer); + +/** + * Set the callback the timer (the function to call periodically) + * @param timer pointer to a timer + * @param timer_cb the function to call periodically + */ +void lv_timer_set_cb(lv_timer_t * timer, lv_timer_cb_t timer_cb); + +/** + * Set new period for a lv_timer + * @param timer pointer to a lv_timer + * @param period the new period + */ +void lv_timer_set_period(lv_timer_t * timer, uint32_t period); + +/** + * Make a lv_timer ready. It will not wait its period. + * @param timer pointer to a lv_timer. + */ +void lv_timer_ready(lv_timer_t * timer); + +/** + * Set the number of times a timer will repeat. + * @param timer pointer to a lv_timer. + * @param repeat_count -1 : infinity; 0 : stop ; n>0: residual times + */ +void lv_timer_set_repeat_count(lv_timer_t * timer, int32_t repeat_count); + +/** + * Reset a lv_timer. + * It will be called the previously set period milliseconds later. + * @param timer pointer to a lv_timer. + */ +void lv_timer_reset(lv_timer_t * timer); + +/** + * Enable or disable the whole lv_timer handling + * @param en true: lv_timer handling is running, false: lv_timer handling is suspended + */ +void lv_timer_enable(bool en); + +/** + * Get idle percentage + * @return the lv_timer idle in percentage + */ +uint8_t lv_timer_get_idle(void); + +/** + * Iterate through the timers + * @param timer NULL to start iteration or the previous return value to get the next timer + * @return the next timer or NULL if there is no more timer + */ +lv_timer_t * lv_timer_get_next(lv_timer_t * timer); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/misc/lv_tlsf.h b/include/liblvgl/misc/lv_tlsf.h new file mode 100644 index 0000000..f12590b --- /dev/null +++ b/include/liblvgl/misc/lv_tlsf.h @@ -0,0 +1,95 @@ +#include "../lv_conf_internal.h" +#if LV_MEM_CUSTOM == 0 + +#ifndef LV_TLSF_H +#define LV_TLSF_H + +/* +** Two Level Segregated Fit memory allocator, version 3.1. +** Written by Matthew Conte +** http://tlsf.baisoku.org +** +** Based on the original documentation by Miguel Masmano: +** http://www.gii.upv.es/tlsf/main/docs +** +** This implementation was written to the specification +** of the document, therefore no GPL restrictions apply. +** +** Copyright (c) 2006-2016, Matthew Conte +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of the copyright holder nor the +** names of its contributors may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* lv_tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* lv_pool_t: a block of memory that TLSF can manage. */ +typedef void * lv_tlsf_t; +typedef void * lv_pool_t; + +/* Create/destroy a memory pool. */ +lv_tlsf_t lv_tlsf_create(void * mem); +lv_tlsf_t lv_tlsf_create_with_pool(void * mem, size_t bytes); +void lv_tlsf_destroy(lv_tlsf_t tlsf); +lv_pool_t lv_tlsf_get_pool(lv_tlsf_t tlsf); + +/* Add/remove memory pools. */ +lv_pool_t lv_tlsf_add_pool(lv_tlsf_t tlsf, void * mem, size_t bytes); +void lv_tlsf_remove_pool(lv_tlsf_t tlsf, lv_pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void * lv_tlsf_malloc(lv_tlsf_t tlsf, size_t bytes); +void * lv_tlsf_memalign(lv_tlsf_t tlsf, size_t align, size_t bytes); +void * lv_tlsf_realloc(lv_tlsf_t tlsf, void * ptr, size_t size); +size_t lv_tlsf_free(lv_tlsf_t tlsf, const void * ptr); + +/* Returns internal block size, not original request size */ +size_t lv_tlsf_block_size(void * ptr); + +/* Overheads/limits of internal structures. */ +size_t lv_tlsf_size(void); +size_t lv_tlsf_align_size(void); +size_t lv_tlsf_block_size_min(void); +size_t lv_tlsf_block_size_max(void); +size_t lv_tlsf_pool_overhead(void); +size_t lv_tlsf_alloc_overhead(void); + +/* Debugging. */ +typedef void (*lv_tlsf_walker)(void * ptr, size_t size, int used, void * user); +void lv_tlsf_walk_pool(lv_pool_t pool, lv_tlsf_walker walker, void * user); +/* Returns nonzero if any internal consistency check fails. */ +int lv_tlsf_check(lv_tlsf_t tlsf); +int lv_tlsf_check_pool(lv_pool_t pool); + +#if defined(__cplusplus) +}; +#endif + +#endif /*LV_TLSF_H*/ + +#endif /* LV_MEM_CUSTOM == 0 */ diff --git a/include/liblvgl/misc/lv_txt.h b/include/liblvgl/misc/lv_txt.h new file mode 100644 index 0000000..ae60e8b --- /dev/null +++ b/include/liblvgl/misc/lv_txt.h @@ -0,0 +1,264 @@ +/** + * @file lv_txt.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#include +#include +#include "lv_area.h" +#include "liblvgl/font/lv_font.h" +#include "lv_printf.h" +#include "lv_types.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TXT_COLOR_CMD +#define LV_TXT_COLOR_CMD "#" +#endif + +#define LV_TXT_ENC_UTF8 1 +#define LV_TXT_ENC_ASCII 2 + +/********************** + * TYPEDEFS + **********************/ + +/** + * Options for text rendering. + */ +enum { + LV_TEXT_FLAG_NONE = 0x00, + LV_TEXT_FLAG_RECOLOR = 0x01, /**< Enable parsing of recolor command*/ + LV_TEXT_FLAG_EXPAND = 0x02, /**< Ignore max-width to avoid automatic word wrapping*/ + LV_TEXT_FLAG_FIT = 0x04, /**< Max-width is already equal to the longest line. (Used to skip some calculation)*/ +}; +typedef uint8_t lv_text_flag_t; + +/** + * State machine for text renderer.*/ +enum { + LV_TEXT_CMD_STATE_WAIT, /**< Waiting for command*/ + LV_TEXT_CMD_STATE_PAR, /**< Processing the parameter*/ + LV_TEXT_CMD_STATE_IN, /**< Processing the command*/ +}; +typedef uint8_t lv_text_cmd_state_t; + +/** Label align policy*/ +enum { + LV_TEXT_ALIGN_AUTO, /**< Align text auto*/ + LV_TEXT_ALIGN_LEFT, /**< Align text to left*/ + LV_TEXT_ALIGN_CENTER, /**< Align text to center*/ + LV_TEXT_ALIGN_RIGHT, /**< Align text to right*/ +}; +typedef uint8_t lv_text_align_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get size of a text + * @param size_res pointer to a 'point_t' variable to store the result + * @param text pointer to a text + * @param font pointer to font of the text + * @param letter_space letter space of the text + * @param line_space line space of the text + * @param flags settings for the text from ::lv_text_flag_t + * @param max_width max width of the text (break the lines to fit this size). Set COORD_MAX to avoid + * line breaks + */ +void lv_txt_get_size(lv_point_t * size_res, const char * text, const lv_font_t * font, lv_coord_t letter_space, + lv_coord_t line_space, lv_coord_t max_width, lv_text_flag_t flag); + +/** + * Get the next line of text. Check line length and break chars too. + * @param txt a '\0' terminated string + * @param font pointer to a font + * @param letter_space letter space + * @param max_width max width of the text (break the lines to fit this size). Set COORD_MAX to avoid + * line breaks + * @param used_width When used_width != NULL, save the width of this line if + * flag == LV_TEXT_FLAG_NONE, otherwise save -1. + * @param flags settings for the text from 'txt_flag_type' enum + * @return the index of the first char of the new line (in byte index not letter index. With UTF-8 + * they are different) + */ +uint32_t _lv_txt_get_next_line(const char * txt, const lv_font_t * font, lv_coord_t letter_space, + lv_coord_t max_width, lv_coord_t * used_width, lv_text_flag_t flag); + +/** + * Give the length of a text with a given font + * @param txt a '\0' terminate string + * @param length length of 'txt' in byte count and not characters (Á is 1 character but 2 bytes in + * UTF-8) + * @param font pointer to a font + * @param letter_space letter space + * @param flags settings for the text from 'txt_flag_t' enum + * @return length of a char_num long text + */ +lv_coord_t lv_txt_get_width(const char * txt, uint32_t length, const lv_font_t * font, lv_coord_t letter_space, + lv_text_flag_t flag); + +/** + * Check next character in a string and decide if the character is part of the command or not + * @param state pointer to a txt_cmd_state_t variable which stores the current state of command + * processing + * @param c the current character + * @return true: the character is part of a command and should not be written, + * false: the character should be written + */ +bool _lv_txt_is_cmd(lv_text_cmd_state_t * state, uint32_t c); + +/** + * Insert a string into an other + * @param txt_buf the original text (must be big enough for the result text and NULL terminated) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert, must be '\0' terminated + */ +void _lv_txt_ins(char * txt_buf, uint32_t pos, const char * ins_txt); + +/** + * Delete a part of a string + * @param txt string to modify, must be '\0' terminated and should point to a heap or stack frame, not read-only memory. + * @param pos position where to start the deleting (0: before the first char, 1: after the first + * char etc.) + * @param len number of characters to delete + */ +void _lv_txt_cut(char * txt, uint32_t pos, uint32_t len); + +/** + * return a new formatted text. Memory will be allocated to store the text. + * @param fmt `printf`-like format + * @return pointer to the allocated text string. + */ +char * _lv_txt_set_text_vfmt(const char * fmt, va_list ap) LV_FORMAT_ATTRIBUTE(1, 0); + +/** + * Decode two encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param letter the first decoded Unicode character or 0 on invalid data code + * @param letter_next the second decoded Unicode character or 0 on invalid data code + * @param ofs start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + */ +void _lv_txt_encoded_letter_next_2(const char * txt, uint32_t * letter, uint32_t * letter_next, uint32_t * ofs); + +/** + * Test if char is break char or not (a text can broken here or not) + * @param letter a letter + * @return false: 'letter' is not break char + */ +static inline bool _lv_txt_is_break_char(uint32_t letter) +{ + uint8_t i; + bool ret = false; + + /* each chinese character can be break */ + if(letter >= 0x4E00 && letter <= 0x9FA5) { + return true; + } + + /*Compare the letter to TXT_BREAK_CHARS*/ + for(i = 0; LV_TXT_BREAK_CHARS[i] != '\0'; i++) { + if(letter == (uint32_t)LV_TXT_BREAK_CHARS[i]) { + ret = true; /*If match then it is break char*/ + break; + } + } + + return ret; +} + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CHARACTER ENCODING INTERFACE + ***************************************************************/ + +/** + * Give the size of an encoded character + * @param str pointer to a character in a string + * @return length of the encoded character (1,2,3 ...). O in invalid + */ +extern uint8_t (*_lv_txt_encoded_size)(const char *); + +/** + * Convert a Unicode letter to encoded + * @param letter_uni a Unicode letter + * @return Encoded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ü') + */ +extern uint32_t (*_lv_txt_unicode_to_encoded)(uint32_t); + +/** + * Convert a wide character, e.g. 'Á' little endian to be compatible with the encoded format. + * @param c a wide character + * @return `c` in the encoded format + */ +extern uint32_t (*_lv_txt_encoded_conv_wc)(uint32_t c); + +/** + * Decode the next encoded character from a string. + * @param txt pointer to '\0' terminated string + * @param i start index in 'txt' where to start. + * After the call it will point to the next encoded char in 'txt'. + * NULL to use txt[0] as index + * @return the decoded Unicode character or 0 on invalid data code + */ +extern uint32_t (*_lv_txt_encoded_next)(const char *, uint32_t *); + +/** + * Get the previous encoded character form a string. + * @param txt pointer to '\0' terminated string + * @param i_start index in 'txt' where to start. After the call it will point to the previous + * encoded char in 'txt'. + * @return the decoded Unicode character or 0 on invalid data + */ +extern uint32_t (*_lv_txt_encoded_prev)(const char *, uint32_t *); + +/** + * Convert a letter index (in the encoded text) to byte index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param enc_id letter index + * @return byte index of the 'enc_id'th letter + */ +extern uint32_t (*_lv_txt_encoded_get_byte_id)(const char *, uint32_t); + +/** + * Convert a byte index (in an encoded text) to character index. + * E.g. in UTF-8 "AÁRT" index of 'R' is 2 but start at byte 3 because 'Á' is 2 bytes long + * @param txt a '\0' terminated UTF-8 string + * @param byte_id byte index + * @return character index of the letter at 'byte_id'th position + */ +extern uint32_t (*_lv_txt_encoded_get_char_id)(const char *, uint32_t); + +/** + * Get the number of characters (and NOT bytes) in a string. + * E.g. in UTF-8 "ÁBC" is 3 characters (but 4 bytes) + * @param txt a '\0' terminated char string + * @return number of characters + */ +extern uint32_t (*_lv_txt_get_encoded_length)(const char *); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TXT_H*/ diff --git a/include/liblvgl/misc/lv_txt_ap.h b/include/liblvgl/misc/lv_txt_ap.h new file mode 100644 index 0000000..3519bb6 --- /dev/null +++ b/include/liblvgl/misc/lv_txt_ap.h @@ -0,0 +1,49 @@ +/** + * @file lv_txt_ap.h + * + */ + +#ifndef LV_TXT_AP_H +#define LV_TXT_AP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_txt.h" +#include "liblvgl/draw/lv_draw.h" + +#if LV_USE_ARABIC_PERSIAN_CHARS == 1 + +/********************* + * DEFINES + *********************/ + +#define LV_UNDEF_ARABIC_PERSIAN_CHARS (UINT32_MAX) +#define LV_AP_ALPHABET_BASE_CODE 0x0622 +#define LV_AP_END_CHARS_LIST {0,0,0,0,0,{0,0}} +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +uint32_t _lv_txt_ap_calc_bytes_cnt(const char * txt); +void _lv_txt_ap_proc(const char * txt, char * txt_out); + +/********************** + * MACROS + **********************/ + +#endif // LV_USE_ARABIC_PERSIAN_CHARS + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TXT_AP_H*/ diff --git a/include/liblvgl/misc/lv_types.h b/include/liblvgl/misc/lv_types.h new file mode 100644 index 0000000..84aee10 --- /dev/null +++ b/include/liblvgl/misc/lv_types.h @@ -0,0 +1,94 @@ +/** + * @file lv_types.h + * + */ + +#ifndef LV_TYPES_H +#define LV_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ + +// If __UINTPTR_MAX__ or UINTPTR_MAX are available, use them to determine arch size +#if defined(__UINTPTR_MAX__) && __UINTPTR_MAX__ > 0xFFFFFFFF +#define LV_ARCH_64 + +#elif defined(UINTPTR_MAX) && UINTPTR_MAX > 0xFFFFFFFF +#define LV_ARCH_64 + +// Otherwise use compiler-dependent means to determine arch size +#elif defined(_WIN64) || defined(__x86_64__) || defined(__ppc64__) || defined (__aarch64__) +#define LV_ARCH_64 + +#endif + +/********************** + * TYPEDEFS + **********************/ + +/** + * LVGL error codes. + */ +enum { + LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action + function or an operation was failed*/ + LV_RES_OK, /*The object is valid (no deleted) after the action*/ +}; +typedef uint8_t lv_res_t; + +#if defined(__cplusplus) || __STDC_VERSION__ >= 199901L +// If c99 or newer, use the definition of uintptr_t directly from +typedef uintptr_t lv_uintptr_t; + +#else + +// Otherwise, use the arch size determination +#ifdef LV_ARCH_64 +typedef uint64_t lv_uintptr_t; +#else +typedef uint32_t lv_uintptr_t; +#endif + +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#define LV_UNUSED(x) ((void)x) + +#define _LV_CONCAT(x, y) x ## y +#define LV_CONCAT(x, y) _LV_CONCAT(x, y) + +#define _LV_CONCAT3(x, y, z) x ## y ## z +#define LV_CONCAT3(x, y, z) _LV_CONCAT3(x, y, z) + +#if defined(PYCPARSER) || defined(__CC_ARM) +#define LV_FORMAT_ATTRIBUTE(fmtstr, vararg) +#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4) +#define LV_FORMAT_ATTRIBUTE(fmtstr, vararg) __attribute__((format(gnu_printf, fmtstr, vararg))) +#elif (defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)) +#define LV_FORMAT_ATTRIBUTE(fmtstr, vararg) __attribute__((format(printf, fmtstr, vararg))) +#else +#define LV_FORMAT_ATTRIBUTE(fmtstr, vararg) +#endif + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TYPES_H*/ diff --git a/include/liblvgl/misc/lv_utils.h b/include/liblvgl/misc/lv_utils.h new file mode 100644 index 0000000..84d2bb9 --- /dev/null +++ b/include/liblvgl/misc/lv_utils.h @@ -0,0 +1,58 @@ +/** + * @file lv_utils.h + * + */ + +#ifndef LV_UTILS_H +#define LV_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** Searches base[0] to base[n - 1] for an item that matches *key. + * + * @note The function cmp must return negative if it's first + * argument (the search key) is less that it's second (a table entry), + * zero if equal, and positive if greater. + * + * @note Items in the array must be in ascending order. + * + * @param key Pointer to item being searched for + * @param base Pointer to first element to search + * @param n Number of elements + * @param size Size of each element + * @param cmp Pointer to comparison function (see #unicode_list_compare as a comparison function + * example) + * + * @return a pointer to a matching item, or NULL if none exists. + */ +void * _lv_utils_bsearch(const void * key, const void * base, uint32_t n, uint32_t size, + int32_t (*cmp)(const void * pRef, const void * pElement)); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif diff --git a/include/liblvgl/widgets/lv_arc.h b/include/liblvgl/widgets/lv_arc.h new file mode 100644 index 0000000..96f4629 --- /dev/null +++ b/include/liblvgl/widgets/lv_arc.h @@ -0,0 +1,256 @@ +/** + * @file lv_arc.h + * + */ + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_ARC != 0 + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_ARC_MODE_NORMAL, + LV_ARC_MODE_SYMMETRICAL, + LV_ARC_MODE_REVERSE +}; +typedef uint8_t lv_arc_mode_t; + +typedef struct { + lv_obj_t obj; + uint16_t rotation; + uint16_t indic_angle_start; + uint16_t indic_angle_end; + uint16_t bg_angle_start; + uint16_t bg_angle_end; + int16_t value; /*Current value of the arc*/ + int16_t min_value; /*Minimum value of the arc*/ + int16_t max_value; /*Maximum value of the arc*/ + uint16_t dragging : 1; + uint16_t type : 2; + uint16_t min_close : 1; /*1: the last pressed angle was closer to minimum end*/ + uint16_t chg_rate; /*Drag angle rate of change of the arc (degrees/sec)*/ + uint32_t last_tick; /*Last dragging event timestamp of the arc*/ + int16_t last_angle; /*Last dragging angle of the arc*/ +} lv_arc_t; + +extern const lv_obj_class_t lv_arc_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_arc_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_ARC_DRAW_PART_BACKGROUND, /**< The background arc*/ + LV_ARC_DRAW_PART_FOREGROUND, /**< The foreground arc*/ + LV_ARC_DRAW_PART_KNOB, /**< The knob*/ +} lv_arc_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an arc object + * @param parent pointer to an object, it will be the parent of the new arc + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * parent); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start angle of an arc. 0 deg: right, 90 bottom, etc. + * @param obj pointer to an arc object + * @param start the start angle + */ +void lv_arc_set_start_angle(lv_obj_t * obj, uint16_t start); + +/** + * Set the end angle of an arc. 0 deg: right, 90 bottom, etc. + * @param obj pointer to an arc object + * @param end the end angle + */ +void lv_arc_set_end_angle(lv_obj_t * obj, uint16_t end); + +/** + * Set the start and end angles + * @param obj pointer to an arc object + * @param start the start angle + * @param end the end angle + */ +void lv_arc_set_angles(lv_obj_t * obj, uint16_t start, uint16_t end); + +/** + * Set the start angle of an arc background. 0 deg: right, 90 bottom, etc. + * @param obj pointer to an arc object + * @param start the start angle + */ +void lv_arc_set_bg_start_angle(lv_obj_t * obj, uint16_t start); + +/** + * Set the start angle of an arc background. 0 deg: right, 90 bottom etc. + * @param obj pointer to an arc object + * @param end the end angle + */ +void lv_arc_set_bg_end_angle(lv_obj_t * obj, uint16_t end); + +/** + * Set the start and end angles of the arc background + * @param obj pointer to an arc object + * @param start the start angle + * @param end the end angle + */ +void lv_arc_set_bg_angles(lv_obj_t * obj, uint16_t start, uint16_t end); + +/** + * Set the rotation for the whole arc + * @param obj pointer to an arc object + * @param rotation rotation angle + */ +void lv_arc_set_rotation(lv_obj_t * obj, uint16_t rotation); + +/** + * Set the type of arc. + * @param obj pointer to arc object + * @param mode arc's mode + */ +void lv_arc_set_mode(lv_obj_t * obj, lv_arc_mode_t type); + +/** + * Set a new value on the arc + * @param obj pointer to an arc object + * @param value new value + */ +void lv_arc_set_value(lv_obj_t * obj, int16_t value); + +/** + * Set minimum and the maximum values of an arc + * @param obj pointer to the arc object + * @param min minimum value + * @param max maximum value + */ +void lv_arc_set_range(lv_obj_t * obj, int16_t min, int16_t max); + +/** + * Set a change rate to limit the speed how fast the arc should reach the pressed point. + * @param obj pointer to an arc object + * @param rate the change rate + */ +void lv_arc_set_change_rate(lv_obj_t * obj, uint16_t rate); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param obj pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * obj); + +/** + * Get the end angle of an arc. + * @param obj pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * obj); + +/** + * Get the start angle of an arc background. + * @param obj pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_bg_angle_start(lv_obj_t * obj); + +/** + * Get the end angle of an arc background. + * @param obj pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_bg_angle_end(lv_obj_t * obj); + +/** + * Get the value of an arc + * @param obj pointer to an arc object + * @return the value of the arc + */ +int16_t lv_arc_get_value(const lv_obj_t * obj); + +/** + * Get the minimum value of an arc + * @param obj pointer to an arc object + * @return the minimum value of the arc + */ +int16_t lv_arc_get_min_value(const lv_obj_t * obj); + +/** + * Get the maximum value of an arc + * @param obj pointer to an arc object + * @return the maximum value of the arc + */ +int16_t lv_arc_get_max_value(const lv_obj_t * obj); + +/** + * Get whether the arc is type or not. + * @param obj pointer to an arc object + * @return arc's mode + */ +lv_arc_mode_t lv_arc_get_mode(const lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/** + * Align an object to the current position of the arc (knob) + * @param obj pointer to an arc object + * @param obj_to_align pointer to an object to align + * @param r_offset consider the radius larger with this value (< 0: for smaller radius) + */ +void lv_arc_align_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_align, lv_coord_t r_offset); + +/** + * Rotate an object to the current position of the arc (knob) + * @param obj pointer to an arc object + * @param obj_to_align pointer to an object to rotate + * @param r_offset consider the radius larger with this value (< 0: for smaller radius) + */ +void lv_arc_rotate_obj_to_angle(const lv_obj_t * obj, lv_obj_t * obj_to_rotate, lv_coord_t r_offset); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_ARC*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ARC_H*/ diff --git a/include/liblvgl/widgets/lv_bar.h b/include/liblvgl/widgets/lv_bar.h new file mode 100644 index 0000000..55d1711 --- /dev/null +++ b/include/liblvgl/widgets/lv_bar.h @@ -0,0 +1,164 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_BAR != 0 + +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/misc/lv_anim.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_BAR_MODE_NORMAL, + LV_BAR_MODE_SYMMETRICAL, + LV_BAR_MODE_RANGE +}; +typedef uint8_t lv_bar_mode_t; + +typedef struct { + lv_obj_t * bar; + int32_t anim_start; + int32_t anim_end; + int32_t anim_state; +} _lv_bar_anim_t; + +typedef struct { + lv_obj_t obj; + int32_t cur_value; /**< Current value of the bar*/ + int32_t min_value; /**< Minimum value of the bar*/ + int32_t max_value; /**< Maximum value of the bar*/ + int32_t start_value; /**< Start value of the bar*/ + lv_area_t indic_area; /**< Save the indicator area. Might be used by derived types*/ + _lv_bar_anim_t cur_value_anim; + _lv_bar_anim_t start_value_anim; + lv_bar_mode_t mode : 2; /**< Type of bar*/ +} lv_bar_t; + +extern const lv_obj_class_t lv_bar_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_bar_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_BAR_DRAW_PART_INDICATOR, /**< The indicator*/ +} lv_bar_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar object + * @param parent pointer to an object, it will be the parent of the new bar + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately + */ +void lv_bar_set_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim); + +/** + * Set a new start value on the bar + * @param obj pointer to a bar object + * @param value new start value + * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately + */ +void lv_bar_set_start_value(lv_obj_t * obj, int32_t start_value, lv_anim_enable_t anim); + +/** + * Set minimum and the maximum values of a bar + * @param obj pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * obj, int32_t min, int32_t max); + +/** + * Set the type of bar. + * @param obj pointer to bar object + * @param mode bar type from ::lv_bar_mode_t + */ +void lv_bar_set_mode(lv_obj_t * obj, lv_bar_mode_t mode); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param obj pointer to a bar object + * @return the value of the bar + */ +int32_t lv_bar_get_value(const lv_obj_t * obj); + +/** + * Get the start value of a bar + * @param obj pointer to a bar object + * @return the start value of the bar + */ +int32_t lv_bar_get_start_value(const lv_obj_t * obj); + +/** + * Get the minimum value of a bar + * @param obj pointer to a bar object + * @return the minimum value of the bar + */ +int32_t lv_bar_get_min_value(const lv_obj_t * obj); + +/** + * Get the maximum value of a bar + * @param obj pointer to a bar object + * @return the maximum value of the bar + */ +int32_t lv_bar_get_max_value(const lv_obj_t * obj); + +/** + * Get the type of bar. + * @param obj pointer to bar object + * @return bar type from ::lv_bar_mode_t + */ +lv_bar_mode_t lv_bar_get_mode(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_BAR*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_BAR_H*/ diff --git a/include/liblvgl/widgets/lv_btn.h b/include/liblvgl/widgets/lv_btn.h new file mode 100644 index 0000000..893e6a0 --- /dev/null +++ b/include/liblvgl/widgets/lv_btn.h @@ -0,0 +1,56 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_BTN != 0 +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; +} lv_btn_t; + +extern const lv_obj_class_t lv_btn_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button object + * @param parent pointer to an object, it will be the parent of the new button + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * parent); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_BTN*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_BTN_H*/ diff --git a/include/liblvgl/widgets/lv_btnmatrix.h b/include/liblvgl/widgets/lv_btnmatrix.h new file mode 100644 index 0000000..31d62bb --- /dev/null +++ b/include/liblvgl/widgets/lv_btnmatrix.h @@ -0,0 +1,225 @@ +/** + * @file lv_btnmatrix.h + * + */ + +#ifndef LV_BTNMATRIX_H +#define LV_BTNMATRIX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_BTNMATRIX != 0 + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_BTNMATRIX_BTN_NONE 0xFFFF +LV_EXPORT_CONST_INT(LV_BTNMATRIX_BTN_NONE); + +/********************** + * TYPEDEFS + **********************/ + +/** Type to store button control bits (disabled, hidden etc.) + * The first 3 bits are used to store the width*/ +enum { + _LV_BTNMATRIX_WIDTH = 0x0007, /**< Reserved to stire the size units*/ + LV_BTNMATRIX_CTRL_HIDDEN = 0x0008, /**< Button hidden*/ + LV_BTNMATRIX_CTRL_NO_REPEAT = 0x0010, /**< Do not repeat press this button.*/ + LV_BTNMATRIX_CTRL_DISABLED = 0x0020, /**< Disable this button.*/ + LV_BTNMATRIX_CTRL_CHECKABLE = 0x0040, /**< The button can be toggled.*/ + LV_BTNMATRIX_CTRL_CHECKED = 0x0080, /**< Button is currently toggled (e.g. checked).*/ + LV_BTNMATRIX_CTRL_CLICK_TRIG = 0x0100, /**< 1: Send LV_EVENT_VALUE_CHANGE on CLICK, 0: Send LV_EVENT_VALUE_CHANGE on PRESS*/ + LV_BTNMATRIX_CTRL_POPOVER = 0x0200, /**< Show a popover when pressing this key*/ + LV_BTNMATRIX_CTRL_RECOLOR = 0x1000, /**< Enable text recoloring with `#color`*/ + _LV_BTNMATRIX_CTRL_RESERVED = 0x2000, /**< Reserved for later use*/ + LV_BTNMATRIX_CTRL_CUSTOM_1 = 0x4000, /**< Custom free to use flag*/ + LV_BTNMATRIX_CTRL_CUSTOM_2 = 0x8000, /**< Custom free to use flag*/ +}; + +typedef uint16_t lv_btnmatrix_ctrl_t; + +typedef bool (*lv_btnmatrix_btn_draw_cb_t)(lv_obj_t * btnm, uint32_t btn_id, const lv_area_t * draw_area, + const lv_area_t * clip_area); + +/*Data of button matrix*/ +typedef struct { + lv_obj_t obj; + const char ** map_p; /*Pointer to the current map*/ + lv_area_t * button_areas; /*Array of areas of buttons*/ + lv_btnmatrix_ctrl_t * ctrl_bits; /*Array of control bytes*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t row_cnt; /*Number of rows in 'map_p'(Handled by the library)*/ + uint16_t btn_id_sel; /*Index of the active button (being pressed/released etc) or LV_BTNMATRIX_BTN_NONE*/ + uint8_t one_check : 1; /*Single button toggled at once*/ +} lv_btnmatrix_t; + +extern const lv_obj_class_t lv_btnmatrix_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_btnmatrix_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_BTNMATRIX_DRAW_PART_BTN, /**< The rectangle and label of buttons*/ +} lv_btnmatrix_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix object + * @param parent pointer to an object, it will be the parent of the new button matrix + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnmatrix_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. The + * button matrix keeps a reference to the map and so the string array must not + * be deallocated during the life of the matrix. + * @param obj pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". Use "\n" to make a line break. + */ +void lv_btnmatrix_set_map(lv_obj_t * obj, const char * map[]); + +/** + * Set the button control map (hidden, disabled etc.) for a button matrix. + * The control map array will be copied and so may be deallocated after this + * function returns. + * @param obj pointer to a button matrix object + * @param ctrl_map pointer to an array of `lv_btn_ctrl_t` control bytes. The + * length of the array and position of the elements must match + * the number and order of the individual buttons (i.e. excludes + * newline entries). + * An element of the map should look like e.g.: + * `ctrl_map[0] = width | LV_BTNMATRIX_CTRL_NO_REPEAT | LV_BTNMATRIX_CTRL_TGL_ENABLE` + */ +void lv_btnmatrix_set_ctrl_map(lv_obj_t * obj, const lv_btnmatrix_ctrl_t ctrl_map[]); + +/** + * Set the selected buttons + * @param obj pointer to button matrix object + * @param btn_id 0 based index of the button to modify. (Not counting new lines) + */ +void lv_btnmatrix_set_selected_btn(lv_obj_t * obj, uint16_t btn_id); + +/** + * Set the attributes of a button of the button matrix + * @param obj pointer to button matrix object + * @param btn_id 0 based index of the button to modify. (Not counting new lines) + * @param ctrl OR-ed attributs. E.g. `LV_BTNMATRIX_CTRL_NO_REPEAT | LV_BTNMATRIX_CTRL_CHECKABLE` + */ +void lv_btnmatrix_set_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl); + +/** + * Clear the attributes of a button of the button matrix + * @param obj pointer to button matrix object + * @param btn_id 0 based index of the button to modify. (Not counting new lines) + * @param ctrl OR-ed attributs. E.g. `LV_BTNMATRIX_CTRL_NO_REPEAT | LV_BTNMATRIX_CTRL_CHECKABLE` + */ +void lv_btnmatrix_clear_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl); + +/** + * Set attributes of all buttons of a button matrix + * @param obj pointer to a button matrix object + * @param ctrl attribute(s) to set from `lv_btnmatrix_ctrl_t`. Values can be ORed. + */ +void lv_btnmatrix_set_btn_ctrl_all(lv_obj_t * obj, lv_btnmatrix_ctrl_t ctrl); + +/** + * Clear the attributes of all buttons of a button matrix + * @param obj pointer to a button matrix object + * @param ctrl attribute(s) to set from `lv_btnmatrix_ctrl_t`. Values can be ORed. + * @param en true: set the attributes; false: clear the attributes + */ +void lv_btnmatrix_clear_btn_ctrl_all(lv_obj_t * obj, lv_btnmatrix_ctrl_t ctrl); + +/** + * Set a single button's relative width. + * This method will cause the matrix be regenerated and is a relatively + * expensive operation. It is recommended that initial width be specified using + * `lv_btnmatrix_set_ctrl_map` and this method only be used for dynamic changes. + * @param obj pointer to button matrix object + * @param btn_id 0 based index of the button to modify. + * @param width relative width compared to the buttons in the same row. [1..7] + */ +void lv_btnmatrix_set_btn_width(lv_obj_t * obj, uint16_t btn_id, uint8_t width); + +/** + * Make the button matrix like a selector widget (only one button may be checked at a time). + * `LV_BTNMATRIX_CTRL_CHECKABLE` must be enabled on the buttons to be selected using + * `lv_btnmatrix_set_ctrl()` or `lv_btnmatrix_set_btn_ctrl_all()`. + * @param obj pointer to a button matrix object + * @param en whether "one check" mode is enabled + */ +void lv_btnmatrix_set_one_checked(lv_obj_t * obj, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param obj pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnmatrix_get_map(const lv_obj_t * obj); + +/** + * Get the index of the lastly "activated" button by the user (pressed, released, focused etc) + * Useful in the `event_cb` to get the text of the button, check if hidden etc. + * @param obj pointer to button matrix object + * @return index of the last released button (LV_BTNMATRIX_BTN_NONE: if unset) + */ +uint16_t lv_btnmatrix_get_selected_btn(const lv_obj_t * obj); + +/** + * Get the button's text + * @param obj pointer to button matrix object + * @param btn_id the index a button not counting new line characters. + * @return text of btn_index` button + */ +const char * lv_btnmatrix_get_btn_text(const lv_obj_t * obj, uint16_t btn_id); + +/** + * Get the whether a control value is enabled or disabled for button of a button matrix + * @param obj pointer to a button matrix object + * @param btn_id the index of a button not counting new line characters. + * @param ctrl control values to check (ORed value can be used) + * @return true: the control attribute is enabled false: disabled + */ +bool lv_btnmatrix_has_btn_ctrl(lv_obj_t * obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl); + +/** + * Tell whether "one check" mode is enabled or not. + * @param obj Button matrix object + * @return true: "one check" mode is enabled; false: disabled + */ +bool lv_btnmatrix_get_one_checked(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_BTNMATRIX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_BTNMATRIX_H*/ diff --git a/include/liblvgl/widgets/lv_canvas.h b/include/liblvgl/widgets/lv_canvas.h new file mode 100644 index 0000000..f92a1c5 --- /dev/null +++ b/include/liblvgl/widgets/lv_canvas.h @@ -0,0 +1,280 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_CANVAS != 0 + +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/widgets/lv_img.h" +#include "liblvgl/draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +extern const lv_obj_class_t lv_canvas_class; + +/*Data of canvas*/ +typedef struct { + lv_img_t img; + lv_img_dsc_t dsc; +} lv_canvas_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param parent pointer to an object, it will be the parent of the new canvas + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a buffer for the canvas. + * @param buf a buffer where the content of the canvas will be. + * The required size is (lv_img_color_format_get_px_size(cf) * w) / 8 * h) + * It can be allocated with `lv_mem_alloc()` or + * it can be statically allocated array (e.g. static lv_color_t buf[100*50]) or + * it can be an address in RAM or external SRAM + * @param canvas pointer to a canvas object + * @param w width of the canvas + * @param h height of the canvas + * @param cf color format. `LV_IMG_CF_...` + */ +void lv_canvas_set_buffer(lv_obj_t * canvas, void * buf, lv_coord_t w, lv_coord_t h, lv_img_cf_t cf); + +/** + * Set the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param c color of the pixel + */ +void lv_canvas_set_px_color(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * DEPRECATED: added only for backward compatibility + */ +static inline void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c) +{ + lv_canvas_set_px_color(canvas, x, y, c); +} + +/** + * Set the opacity of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @param opa opacity of the pixel (0..255) + */ +void lv_canvas_set_px_opa(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_opa_t opa); + + +/** + * Set the palette color of a canvas with index format. Valid only for `LV_IMG_CF_INDEXED1/2/4/8` + * @param canvas pointer to canvas object + * @param id the palette color to set: + * - for `LV_IMG_CF_INDEXED1`: 0..1 + * - for `LV_IMG_CF_INDEXED2`: 0..3 + * - for `LV_IMG_CF_INDEXED4`: 0..15 + * - for `LV_IMG_CF_INDEXED8`: 0..255 + * @param c the color to set + */ +void lv_canvas_set_palette(lv_obj_t * canvas, uint8_t id, lv_color_t c); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the color of a pixel on the canvas + * @param canvas + * @param x x coordinate of the point to set + * @param y x coordinate of the point to set + * @return color of the point + */ +lv_color_t lv_canvas_get_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y); + +/** + * Get the image of the canvas as a pointer to an `lv_img_dsc_t` variable. + * @param canvas pointer to a canvas object + * @return pointer to the image descriptor. + */ +lv_img_dsc_t * lv_canvas_get_img(lv_obj_t * canvas); + +/*===================== + * Other functions + *====================*/ + +/** + * Copy a buffer to the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy. The color format has to match with the canvas's buffer color + * format + * @param x left side of the destination position + * @param y top side of the destination position + * @param w width of the buffer to copy + * @param h height of the buffer to copy + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t x, lv_coord_t y, lv_coord_t w, + lv_coord_t h); + +/** + * Transform and image and store the result on a canvas. + * @param canvas pointer to a canvas object to store the result of the transformation. + * @param img pointer to an image descriptor to transform. + * Can be the image descriptor of an other canvas too (`lv_canvas_get_img()`). + * @param angle the angle of rotation (0..3600), 0.1 deg resolution + * @param zoom zoom factor (256 no zoom); + * @param offset_x offset X to tell where to put the result data on destination canvas + * @param offset_y offset X to tell where to put the result data on destination canvas + * @param pivot_x pivot X of rotation. Relative to the source canvas + * Set to `source width / 2` to rotate around the center + * @param pivot_y pivot Y of rotation. Relative to the source canvas + * Set to `source height / 2` to rotate around the center + * @param antialias apply anti-aliasing during the transformation. Looks better but slower. + */ +void lv_canvas_transform(lv_obj_t * canvas, lv_img_dsc_t * img, int16_t angle, uint16_t zoom, lv_coord_t offset_x, + lv_coord_t offset_y, + int32_t pivot_x, int32_t pivot_y, bool antialias); + +/** + * Apply horizontal blur on the canvas + * @param canvas pointer to a canvas object + * @param area the area to blur. If `NULL` the whole canvas will be blurred. + * @param r radius of the blur + */ +void lv_canvas_blur_hor(lv_obj_t * canvas, const lv_area_t * area, uint16_t r); + +/** + * Apply vertical blur on the canvas + * @param canvas pointer to a canvas object + * @param area the area to blur. If `NULL` the whole canvas will be blurred. + * @param r radius of the blur + */ +void lv_canvas_blur_ver(lv_obj_t * canvas, const lv_area_t * area, uint16_t r); + +/** + * Fill the canvas with color + * @param canvas pointer to a canvas + * @param color the background color + * @param opa the desired opacity + */ +void lv_canvas_fill_bg(lv_obj_t * canvas, lv_color_t color, lv_opa_t opa); + +/** + * Draw a rectangle on the canvas + * @param canvas pointer to a canvas object + * @param x left coordinate of the rectangle + * @param y top coordinate of the rectangle + * @param w width of the rectangle + * @param h height of the rectangle + * @param draw_dsc descriptor of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, + const lv_draw_rect_dsc_t * draw_dsc); + +/** + * Draw a text on the canvas. + * @param canvas pointer to a canvas object + * @param x left coordinate of the text + * @param y top coordinate of the text + * @param max_w max width of the text. The text will be wrapped to fit into this size + * @param draw_dsc pointer to a valid label descriptor `lv_draw_label_dsc_t` + * @param txt text to display + */ +void lv_canvas_draw_text(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t max_w, + lv_draw_label_dsc_t * draw_dsc, const char * txt); + +/** + * Draw an image on the canvas + * @param canvas pointer to a canvas object + * @param x left coordinate of the image + * @param y top coordinate of the image + * @param src image source. Can be a pointer an `lv_img_dsc_t` variable or a path an image. + * @param draw_dsc pointer to a valid label descriptor `lv_draw_img_dsc_t` + */ +void lv_canvas_draw_img(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, const void * src, + const lv_draw_img_dsc_t * draw_dsc); + +/** + * Draw a line on the canvas + * @param canvas pointer to a canvas object + * @param points point of the line + * @param point_cnt number of points + * @param draw_dsc pointer to an initialized `lv_draw_line_dsc_t` variable + */ +void lv_canvas_draw_line(lv_obj_t * canvas, const lv_point_t points[], uint32_t point_cnt, + const lv_draw_line_dsc_t * draw_dsc); + +/** + * Draw a polygon on the canvas + * @param canvas pointer to a canvas object + * @param points point of the polygon + * @param point_cnt number of points + * @param draw_dsc pointer to an initialized `lv_draw_rect_dsc_t` variable + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, const lv_point_t points[], uint32_t point_cnt, + const lv_draw_rect_dsc_t * draw_dsc); + +/** + * Draw an arc on the canvas + * @param canvas pointer to a canvas object + * @param x origo x of the arc + * @param y origo y of the arc + * @param r radius of the arc + * @param start_angle start angle in degrees + * @param end_angle end angle in degrees + * @param draw_dsc pointer to an initialized `lv_draw_line_dsc_t` variable + */ +void lv_canvas_draw_arc(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_coord_t r, int32_t start_angle, + int32_t end_angle, const lv_draw_arc_dsc_t * draw_dsc); + +/********************** + * MACROS + **********************/ +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR(w, h) +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h) +#define LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h) + +/*+ 1: to be sure no fractional row*/ +#define LV_CANVAS_BUF_SIZE_ALPHA_1BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_2BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_4BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h) +#define LV_CANVAS_BUF_SIZE_ALPHA_8BIT(w, h) LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h) + +/*4 * X: for palette*/ +#define LV_CANVAS_BUF_SIZE_INDEXED_1BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_2BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_4BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h) +#define LV_CANVAS_BUF_SIZE_INDEXED_8BIT(w, h) LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h) + +#endif /*LV_USE_CANVAS*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/include/liblvgl/widgets/lv_checkbox.h b/include/liblvgl/widgets/lv_checkbox.h new file mode 100644 index 0000000..6b2bdc3 --- /dev/null +++ b/include/liblvgl/widgets/lv_checkbox.h @@ -0,0 +1,97 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CHECKBOX_H +#define LV_CHECKBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" +#include "liblvgl/core/lv_obj.h" + +#if LV_USE_CHECKBOX != 0 + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + char * txt; + uint32_t static_txt : 1; +} lv_checkbox_t; + +extern const lv_obj_class_t lv_checkbox_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_checkbox_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_CHECKBOX_DRAW_PART_BOX, /**< The tick box*/ +} lv_checkbox_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box object + * @param parent pointer to an object, it will be the parent of the new button + * @return pointer to the created check box + */ +lv_obj_t * lv_checkbox_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box. `txt` will be copied and may be deallocated + * after this function returns. + * @param cb pointer to a check box + * @param txt the text of the check box. NULL to refresh with the current text. + */ +void lv_checkbox_set_text(lv_obj_t * obj, const char * txt); + +/** + * Set the text of a check box. `txt` must not be deallocated during the life + * of this checkbox. + * @param cb pointer to a check box + * @param txt the text of the check box. + */ +void lv_checkbox_set_text_static(lv_obj_t * obj, const char * txt); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a check box + * @param cb pointer to check box object + * @return pointer to the text of the check box + */ +const char * lv_checkbox_get_text(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_CHECKBOX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CHECKBOX_H*/ diff --git a/include/liblvgl/widgets/lv_dropdown.h b/include/liblvgl/widgets/lv_dropdown.h new file mode 100644 index 0000000..9848b14 --- /dev/null +++ b/include/liblvgl/widgets/lv_dropdown.h @@ -0,0 +1,254 @@ +/** + * @file lv_dropdown.h + * + */ + +#ifndef LV_DROPDOWN_H +#define LV_DROPDOWN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_DROPDOWN != 0 + +/*Testing of dependencies*/ + +#if LV_USE_LABEL == 0 +#error "lv_dropdown: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1)" +#endif + +#include "../widgets/lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_DROPDOWN_POS_LAST 0xFFFF +LV_EXPORT_CONST_INT(LV_DROPDOWN_POS_LAST); + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + lv_obj_t * list; /**< The dropped down list*/ + const char * text; /**< Text to display on the dropdown's button*/ + const void * symbol; /**< Arrow or other icon when the drop-down list is closed*/ + char * options; /**< Options in a '\n' separated list*/ + uint16_t option_cnt; /**< Number of options*/ + uint16_t sel_opt_id; /**< Index of the currently selected option*/ + uint16_t sel_opt_id_orig; /**< Store the original index on focus*/ + uint16_t pr_opt_id; /**< Index of the currently pressed option*/ + lv_dir_t dir : 4; /**< Direction in which the list should open*/ + uint8_t static_txt : 1; /**< 1: Only a pointer is saved in `options`*/ + uint8_t selected_highlight: 1; /**< 1: Make the selected option highlighted in the list*/ +} lv_dropdown_t; + +typedef struct { + lv_obj_t obj; + lv_obj_t * dropdown; +} lv_dropdown_list_t; + +extern const lv_obj_class_t lv_dropdown_class; +extern const lv_obj_class_t lv_dropdownlist_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a drop-down list object + * @param parent pointer to an object, it will be the parent of the new drop-down list + * @return pointer to the created drop-down list + */ +lv_obj_t * lv_dropdown_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set text of the drop-down list's button. + * If set to `NULL` the selected option's text will be displayed on the button. + * If set to a specific text then that text will be shown regardless of the selected option. + * @param obj pointer to a drop-down list object + * @param txt the text as a string (Only its pointer is saved) + */ +void lv_dropdown_set_text(lv_obj_t * obj, const char * txt); + +/** + * Set the options in a drop-down list from a string. + * The options will be copied and saved in the object so the `options` can be destroyed after calling this function + * @param obj pointer to drop-down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_dropdown_set_options(lv_obj_t * obj, const char * options); + +/** + * Set the options in a drop-down list from a static string (global, static or dynamically allocated). + * Only the pointer of the option string will be saved. + * @param obj pointer to drop-down list object + * @param options a static string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_dropdown_set_options_static(lv_obj_t * obj, const char * options); + +/** + * Add an options to a drop-down list from a string. Only works for non-static options. + * @param obj pointer to drop-down list object + * @param option a string without '\n'. E.g. "Four" + * @param pos the insert position, indexed from 0, LV_DROPDOWN_POS_LAST = end of string + */ +void lv_dropdown_add_option(lv_obj_t * obj, const char * option, uint32_t pos); + +/** + * Clear all options in a drop-down list. Works with both static and dynamic options. + * @param obj pointer to drop-down list object + */ +void lv_dropdown_clear_options(lv_obj_t * obj); + +/** + * Set the selected option + * @param obj pointer to drop-down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_dropdown_set_selected(lv_obj_t * obj, uint16_t sel_opt); + +/** + * Set the direction of the a drop-down list + * @param obj pointer to a drop-down list object + * @param dir LV_DIR_LEFT/RIGHT/TOP/BOTTOM + */ +void lv_dropdown_set_dir(lv_obj_t * obj, lv_dir_t dir); + +/** + * Set an arrow or other symbol to display when on drop-down list's button. Typically a down caret or arrow. + * @param obj pointer to drop-down list object + * @param symbol a text like `LV_SYMBOL_DOWN`, an image (pointer or path) or NULL to not draw symbol icon + * @note angle and zoom transformation can be applied if the symbol is an image. + * E.g. when drop down is checked (opened) rotate the symbol by 180 degree + */ +void lv_dropdown_set_symbol(lv_obj_t * obj, const void * symbol); + +/** + * Set whether the selected option in the list should be highlighted or not + * @param obj pointer to drop-down list object + * @param en true: highlight enabled; false: disabled + */ +void lv_dropdown_set_selected_highlight(lv_obj_t * obj, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the list of a drop-down to allow styling or other modifications + * @param obj pointer to a drop-down list object + * @return pointer to the list of the drop-down + */ +lv_obj_t * lv_dropdown_get_list(lv_obj_t * obj); + +/** + * Get text of the drop-down list's button. + * @param obj pointer to a drop-down list object + * @return the text as string, `NULL` if no text + */ +const char * lv_dropdown_get_text(lv_obj_t * obj); + +/** + * Get the options of a drop-down list + * @param obj pointer to drop-down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_dropdown_get_options(const lv_obj_t * obj); + +/** + * Get the index of the selected option + * @param obj pointer to drop-down list object + * @return index of the selected option (0 ... number of option - 1); + */ +uint16_t lv_dropdown_get_selected(const lv_obj_t * obj); + +/** + * Get the total number of options + * @param obj pointer to drop-down list object + * @return the total number of options in the list + */ +uint16_t lv_dropdown_get_option_cnt(const lv_obj_t * obj); + +/** + * Get the current selected option as a string + * @param obj pointer to drop-down object + * @param buf pointer to an array to store the string + * @param buf_size size of `buf` in bytes. 0: to ignore it. + */ +void lv_dropdown_get_selected_str(const lv_obj_t * obj, char * buf, uint32_t buf_size); + +/** + * Get the index of an option. + * @param obj pointer to drop-down object + * @param option an option as string + * @return index of `option` in the list of all options. -1 if not found. + */ +int32_t lv_dropdown_get_option_index(lv_obj_t * obj, const char * option); + +/** + * Get the symbol on the drop-down list. Typically a down caret or arrow. + * @param obj pointer to drop-down list object + * @return the symbol or NULL if not enabled + */ +const char * lv_dropdown_get_symbol(lv_obj_t * obj); + +/** + * Get whether the selected option in the list should be highlighted or not + * @param obj pointer to drop-down list object + * @return true: highlight enabled; false: disabled + */ +bool lv_dropdown_get_selected_highlight(lv_obj_t * obj); + +/** + * Get the direction of the drop-down list + * @param obj pointer to a drop-down list object + * @return LV_DIR_LEF/RIGHT/TOP/BOTTOM + */ +lv_dir_t lv_dropdown_get_dir(const lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop.down list + * @param obj pointer to drop-down list object + */ +void lv_dropdown_open(lv_obj_t * dropdown_obj); + +/** + * Close (Collapse) the drop-down list + * @param obj pointer to drop-down list object + */ +void lv_dropdown_close(lv_obj_t * obj); + +/** + * Tells whether the list is opened or not + * @param obj pointer to a drop-down list object + * @return true if the list os opened + */ +bool lv_dropdown_is_open(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_DROPDOWN*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DROPDOWN_H*/ diff --git a/include/liblvgl/widgets/lv_img.h b/include/liblvgl/widgets/lv_img.h new file mode 100644 index 0000000..5513a26 --- /dev/null +++ b/include/liblvgl/widgets/lv_img.h @@ -0,0 +1,234 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_IMG != 0 + +/*Testing of dependencies*/ +#if LV_USE_LABEL == 0 +#error "lv_img: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1)" +#endif + +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/misc/lv_fs.h" +#include "liblvgl/draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Data of image + */ +typedef struct { + lv_obj_t obj; + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + lv_point_t offset; + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ + uint16_t angle; /*rotation angle of the image*/ + lv_point_t pivot; /*rotation center of the image*/ + uint16_t zoom; /*256 means no zoom, 512 double size, 128 half size*/ + uint8_t src_type : 2; /*See: lv_img_src_t*/ + uint8_t cf : 5; /*Color format from `lv_img_color_format_t`*/ + uint8_t antialias : 1; /*Apply anti-aliasing in transformations (rotate, zoom)*/ + uint8_t obj_size_mode: 2; /*Image size mode when image size and object size is different.*/ +} lv_img_t; + +extern const lv_obj_class_t lv_img_class; + +/** + * Image size mode, when image size and object size is different + */ +enum { + /** Zoom doesn't affect the coordinates of the object, + * however if zoomed in the image is drawn out of the its coordinates. + * The layout's won't change on zoom */ + LV_IMG_SIZE_MODE_VIRTUAL = 0, + + /** If the object size is set to SIZE_CONTENT, then object size equals zoomed image size. + * It causes layout recalculation. + * If the object size is set explicitly, the image will be cropped when zoomed in.*/ + LV_IMG_SIZE_MODE_REAL, +}; + +typedef uint8_t lv_img_size_mode_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image object + * @param parent pointer to an object, it will be the parent of the new image + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the image data to display on the object + * @param obj pointer to an image object + * @param src_img 1) pointer to an ::lv_img_dsc_t descriptor (converted by LVGL's image converter) (e.g. &my_img) or + * 2) path to an image file (e.g. "S:/dir/img.bin")or + * 3) a SYMBOL (e.g. LV_SYMBOL_OK) + */ +void lv_img_set_src(lv_obj_t * obj, const void * src); + +/** + * Set an offset for the source of an image so the image will be displayed from the new origin. + * @param obj pointer to an image + * @param x the new offset along x axis. + */ +void lv_img_set_offset_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set an offset for the source of an image. + * so the image will be displayed from the new origin. + * @param obj pointer to an image + * @param y the new offset along y axis. + */ +void lv_img_set_offset_y(lv_obj_t * obj, lv_coord_t y); + + +/** + * Set the rotation angle of the image. + * The image will be rotated around the set pivot set by `lv_img_set_pivot()` + * Note that indexed and alpha only images can't be transformed. + * @param obj pointer to an image object + * @param angle rotation angle in degree with 0.1 degree resolution (0..3600: clock wise) + */ +void lv_img_set_angle(lv_obj_t * obj, int16_t angle); + +/** + * Set the rotation center of the image. + * The image will be rotated around this point. + * @param obj pointer to an image object + * @param x rotation center x of the image + * @param y rotation center y of the image + */ +void lv_img_set_pivot(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + + +/** + * Set the zoom factor of the image. + * Note that indexed and alpha only images can't be transformed. + * @param img pointer to an image object + * @param zoom the zoom factor. + * @example 256 or LV_ZOOM_IMG_NONE for no zoom + * @example <256: scale down + * @example >256 scale up + * @example 128 half size + * @example 512 double size + */ +void lv_img_set_zoom(lv_obj_t * obj, uint16_t zoom); + +/** + * Enable/disable anti-aliasing for the transformations (rotate, zoom) or not. + * The quality is better with anti-aliasing looks better but slower. + * @param obj pointer to an image object + * @param antialias true: anti-aliased; false: not anti-aliased + */ +void lv_img_set_antialias(lv_obj_t * obj, bool antialias); + +/** + * Set the image object size mode. + * + * @param obj pointer to an image object + * @param mode the new size mode. + */ +void lv_img_set_size_mode(lv_obj_t * obj, lv_img_size_mode_t mode); +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param obj pointer to an image object + * @return the image source (symbol, file name or ::lv-img_dsc_t for C arrays) + */ +const void * lv_img_get_src(lv_obj_t * obj); + +/** + * Get the offset's x attribute of the image object. + * @param img pointer to an image + * @return offset X value. + */ +lv_coord_t lv_img_get_offset_x(lv_obj_t * obj); + +/** + * Get the offset's y attribute of the image object. + * @param obj pointer to an image + * @return offset Y value. + */ +lv_coord_t lv_img_get_offset_y(lv_obj_t * obj); + +/** + * Get the rotation angle of the image. + * @param obj pointer to an image object + * @return rotation angle in 0.1 degrees (0..3600) + */ +uint16_t lv_img_get_angle(lv_obj_t * obj); + +/** + * Get the pivot (rotation center) of the image. + * @param img pointer to an image object + * @param pivot store the rotation center here + */ +void lv_img_get_pivot(lv_obj_t * obj, lv_point_t * pivot); + +/** + * Get the zoom factor of the image. + * @param obj pointer to an image object + * @return zoom factor (256: no zoom) + */ +uint16_t lv_img_get_zoom(lv_obj_t * obj); + +/** + * Get whether the transformations (rotate, zoom) are anti-aliased or not + * @param obj pointer to an image object + * @return true: anti-aliased; false: not anti-aliased + */ +bool lv_img_get_antialias(lv_obj_t * obj); + +/** + * Get the size mode of the image + * @param obj pointer to an image object + * @return element of @ref lv_img_size_mode_t + */ +lv_img_size_mode_t lv_img_get_size_mode(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +/** Use this macro to declare an image in a C file*/ +#define LV_IMG_DECLARE(var_name) extern const lv_img_dsc_t var_name; + +#endif /*LV_USE_IMG*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMG_H*/ diff --git a/include/liblvgl/widgets/lv_label.h b/include/liblvgl/widgets/lv_label.h new file mode 100644 index 0000000..39a68db --- /dev/null +++ b/include/liblvgl/widgets/lv_label.h @@ -0,0 +1,246 @@ +/** + * @file lv_label.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_conf_internal.h" + +#if LV_USE_LABEL != 0 + +#include +#include "liblvgl/core/lv_obj.h" +#include "liblvgl/font/lv_font.h" +#include "liblvgl/font/lv_symbol_def.h" +#include "liblvgl/misc/lv_txt.h" +#include "liblvgl/draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_WAIT_CHAR_COUNT 3 +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF +#define LV_LABEL_TEXT_SELECTION_OFF LV_DRAW_LABEL_NO_TXT_SEL + +LV_EXPORT_CONST_INT(LV_LABEL_DOT_NUM); +LV_EXPORT_CONST_INT(LV_LABEL_POS_LAST); +LV_EXPORT_CONST_INT(LV_LABEL_TEXT_SELECTION_OFF); + +/********************** + * TYPEDEFS + **********************/ + +/** Long mode behaviors. Used in 'lv_label_ext_t'*/ +enum { + LV_LABEL_LONG_WRAP, /**< Keep the object width, wrap the too long lines and expand the object height*/ + LV_LABEL_LONG_DOT, /**< Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_SCROLL, /**< Keep the size and roll the text back and forth*/ + LV_LABEL_LONG_SCROLL_CIRCULAR, /**< Keep the size and roll the text circularly*/ + LV_LABEL_LONG_CLIP, /**< Keep the size and clip the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +typedef struct { + lv_obj_t obj; + char * text; + union { + char * tmp_ptr; /*Pointer to the allocated memory containing the character replaced by dots*/ + char tmp[LV_LABEL_DOT_NUM + 1]; /*Directly store the characters if <=4 characters*/ + } dot; + uint32_t dot_end; /*The real text length, used in dot mode*/ + +#if LV_LABEL_LONG_TXT_HINT + lv_draw_label_hint_t hint; +#endif + +#if LV_LABEL_TEXT_SELECTION + uint32_t sel_start; + uint32_t sel_end; +#endif + + lv_point_t offset; /*Text draw position offset*/ + lv_label_long_mode_t long_mode : 3; /*Determine what to do with the long texts*/ + uint8_t static_txt : 1; /*Flag to indicate the text is static*/ + uint8_t recolor : 1; /*Enable in-line letter re-coloring*/ + uint8_t expand : 1; /*Ignore real width (used by the library with LV_LABEL_LONG_SCROLL)*/ + uint8_t dot_tmp_alloc : 1; /*1: dot is allocated, 0: dot directly holds up to 4 chars*/ +} lv_label_t; + +extern const lv_obj_class_t lv_label_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a label object + * @param parent pointer to an object, it will be the parent of the new label. + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param obj pointer to a label object + * @param text '\0' terminated character string. NULL to refresh with the current text. + */ +void lv_label_set_text(lv_obj_t * obj, const char * text); + +/** + * Set a new formatted text for a label. Memory will be allocated to store the text by the label. + * @param obj pointer to a label object + * @param fmt `printf`-like format + * @example lv_label_set_text_fmt(label1, "%d user", user_num); + */ +void lv_label_set_text_fmt(lv_obj_t * obj, const char * fmt, ...) LV_FORMAT_ATTRIBUTE(2, 3); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exists. + * @param obj pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_text_static(lv_obj_t * obj, const char * text); + +/** + * Set the behavior of the label with longer text then the object size + * @param obj pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_WRAP/DOT/SCROLL/SCROLL_CIRC the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * obj, lv_label_long_mode_t long_mode); + +/** + * Enable the recoloring by in-line commands + * @param obj pointer to a label object + * @param en true: enable recoloring, false: disable + * @example "This is a #ff0000 red# word" + */ +void lv_label_set_recolor(lv_obj_t * obj, bool en); + +/** + * Set where text selection should start + * @param obj pointer to a label object + * @param index character index from where selection should start. `LV_LABEL_TEXT_SELECTION_OFF` for no selection + */ +void lv_label_set_text_sel_start(lv_obj_t * obj, uint32_t index); + +/** + * Set where text selection should end + * @param obj pointer to a label object + * @param index character index where selection should end. `LV_LABEL_TEXT_SELECTION_OFF` for no selection + */ +void lv_label_set_text_sel_end(lv_obj_t * obj, uint32_t index); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param obj pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * obj); + +/** + * Get the long mode of a label + * @param obj pointer to a label object + * @return the current long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * obj); + +/** + * Get the recoloring attribute + * @param obj pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * obj); + +/** + * Get the relative x and y coordinates of a letter + * @param obj pointer to a label object + * @param index index of the character [0 ... text length - 1]. + * Expressed in character index, not byte index (different in UTF-8) + * @param pos store the result here (E.g. index = 0 gives 0;0 coordinates if the text if aligned to the left) + */ +void lv_label_get_letter_pos(const lv_obj_t * obj, uint32_t char_id, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label. + * @param obj pointer to label object + * @param pos pointer to point with coordinates on a the label + * @return The index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter if aligned to the left) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint32_t lv_label_get_letter_on(const lv_obj_t * obj, lv_point_t * pos_in); + +/** + * Check if a character is drawn under a point. + * @param obj pointer to a label object + * @param pos Point to check for character under + * @return whether a character is drawn under the point + */ +bool lv_label_is_char_under_pos(const lv_obj_t * obj, lv_point_t * pos); + +/** + * @brief Get the selection start index. + * @param obj pointer to a label object. + * @return selection start index. `LV_LABEL_TEXT_SELECTION_OFF` if nothing is selected. + */ +uint32_t lv_label_get_text_selection_start(const lv_obj_t * obj); + +/** + * @brief Get the selection end index. + * @param obj pointer to a label object. + * @return selection end index. `LV_LABEL_TXT_SEL_OFF` if nothing is selected. + */ +uint32_t lv_label_get_text_selection_end(const lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to a label. The label text can not be static. + * @param obj pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index. + * 0: before first char. LV_LABEL_POS_LAST: after last char. + * @param txt pointer to the text to insert + */ +void lv_label_ins_text(lv_obj_t * obj, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param obj pointer to a label object + * @param pos character index from where to cut. Expressed in character index and not byte index. + * 0: start in from of the first character + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * obj, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_LABEL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/include/liblvgl/widgets/lv_line.h b/include/liblvgl/widgets/lv_line.h new file mode 100644 index 0000000..622ef81 --- /dev/null +++ b/include/liblvgl/widgets/lv_line.h @@ -0,0 +1,93 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_LINE != 0 + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct { + lv_obj_t obj; + const lv_point_t * point_array; /**< Pointer to an array with the points of the line*/ + uint16_t point_num; /**< Number of points in 'point_array'*/ + uint8_t y_inv : 1; /**< 1: y == 0 will be on the bottom*/ +} lv_line_t; + +extern const lv_obj_class_t lv_line_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line object + * @param parent pointer to an object, it will be the parent of the new line + * @return pointer to the created line + */ +lv_obj_t * lv_line_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param obj pointer to a line object + * @param points an array of points. Only the address is saved, so the array needs to be alive while the line exists + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * obj, const lv_point_t points[], uint16_t point_num); + +/** + * Enable (or disable) the y coordinate inversion. + * If enabled then y will be subtracted from the height of the object, + * therefore the y = 0 coordinate will be on the bottom. + * @param obj pointer to a line object + * @param en true: enable the y inversion, false:disable the y inversion + */ +void lv_line_set_y_invert(lv_obj_t * obj, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the y inversion attribute + * @param obj pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_LINE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_LINE_H*/ diff --git a/include/liblvgl/widgets/lv_objx_templ.h b/include/liblvgl/widgets/lv_objx_templ.h new file mode 100644 index 0000000..f363df4 --- /dev/null +++ b/include/liblvgl/widgets/lv_objx_templ.h @@ -0,0 +1,81 @@ +/** + * @file lv_templ.h + * + */ + +/** + * TODO Remove these instructions + * Search and replace: templ -> object short name with lower case(e.g. btn, label etc) + * TEMPL -> object short name with upper case (e.g. BTN, LABEL etc.) + * + */ + +#ifndef LV_TEMPL_H +#define LV_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_TEMPL != 0 + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_t ancestor; /*The ancestor widget, e.g. lv_slider_t slider*/ + /*New data for this type*/ +} lv_templ_t; + +extern const lv_obj_class_t lv_templ_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a templ object + * @param parent pointer to an object, it will be the parent of the new templ + * @return pointer to the created bar + */ +lv_obj_t * lv_templ_create(lv_obj_t * parent); + +/*====================== + * Add/remove functions + *=====================*/ + +/*===================== + * Setter functions + *====================*/ + +/*===================== + * Getter functions + *====================*/ + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_TEMPL*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/include/liblvgl/widgets/lv_roller.h b/include/liblvgl/widgets/lv_roller.h new file mode 100644 index 0000000..4984c26 --- /dev/null +++ b/include/liblvgl/widgets/lv_roller.h @@ -0,0 +1,138 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_ROLLER != 0 + +/*Testing of dependencies*/ +#if LV_USE_LABEL == 0 +#error "lv_roller: lv_label is required. Enable it in lv_conf.h (LV_USE_ROLLER 1)" +#endif + +#include "liblvgl/core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** Roller mode.*/ +enum { + LV_ROLLER_MODE_NORMAL, /**< Normal mode (roller ends at the end of the options).*/ + LV_ROLLER_MODE_INFINITE, /**< Infinite mode (roller can be scrolled forever).*/ +}; + +typedef uint8_t lv_roller_mode_t; + +typedef struct { + lv_obj_t obj; + uint16_t option_cnt; /**< Number of options*/ + uint16_t sel_opt_id; /**< Index of the current option*/ + uint16_t sel_opt_id_ori; /**< Store the original index on focus*/ + lv_roller_mode_t mode : 1; + uint32_t moved : 1; +} lv_roller_t; + +extern const lv_obj_class_t lv_roller_class; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param parent pointer to an object, it will be the parent of the new roller. + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the options on a roller + * @param obj pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + * @param mode `LV_ROLLER_MODE_NORMAL` or `LV_ROLLER_MODE_INFINITE` + */ +void lv_roller_set_options(lv_obj_t * obj, const char * options, lv_roller_mode_t mode); + +/** + * Set the selected option + * @param obj pointer to a roller object + * @param sel_opt index of the selected option (0 ... number of option - 1); + * @param anim_en LV_ANIM_ON: set with animation; LV_ANOM_OFF set immediately + */ +void lv_roller_set_selected(lv_obj_t * obj, uint16_t sel_opt, lv_anim_enable_t anim); + +/** + * Set the height to show the given number of rows (options) + * @param obj pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t * obj, uint8_t row_cnt); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the selected option + * @param obj pointer to a roller object + * @return index of the selected option (0 ... number of option - 1); + */ +uint16_t lv_roller_get_selected(const lv_obj_t * obj); + +/** + * Get the current selected option as a string. + * @param obj pointer to ddlist object + * @param buf pointer to an array to store the string + * @param buf_size size of `buf` in bytes. 0: to ignore it. + */ +void lv_roller_get_selected_str(const lv_obj_t * obj, char * buf, uint32_t buf_size); + + +/** + * Get the options of a roller + * @param obj pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_roller_get_options(const lv_obj_t * obj); + +/** + * Get the total number of options + * @param obj pointer to a roller object + * @return the total number of options + */ +uint16_t lv_roller_get_option_cnt(const lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_ROLLER*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/include/liblvgl/widgets/lv_slider.h b/include/liblvgl/widgets/lv_slider.h new file mode 100644 index 0000000..20c940f --- /dev/null +++ b/include/liblvgl/widgets/lv_slider.h @@ -0,0 +1,195 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_SLIDER != 0 + +/*Testing of dependencies*/ +#if LV_USE_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (LV_USE_BAR 1)" +#endif + +#include "liblvgl/core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_SLIDER_MODE_NORMAL = LV_BAR_MODE_NORMAL, + LV_SLIDER_MODE_SYMMETRICAL = LV_BAR_MODE_SYMMETRICAL, + LV_SLIDER_MODE_RANGE = LV_BAR_MODE_RANGE +}; +typedef uint8_t lv_slider_mode_t; + +typedef struct { + lv_bar_t bar; /*Add the ancestor's type first*/ + lv_area_t left_knob_area; + lv_area_t right_knob_area; + int32_t * value_to_set; /*Which bar value to set*/ + uint8_t dragging : 1; /*1: the slider is being dragged*/ + uint8_t left_knob_focus : 1; /*1: with encoder now the right knob can be adjusted*/ +} lv_slider_t; + +extern const lv_obj_class_t lv_slider_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_slider_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_SLIDER_DRAW_PART_KNOB, /**< The main (right) knob's rectangle*/ + LV_SLIDER_DRAW_PART_KNOB_LEFT, /**< The left knob's rectangle*/ +} lv_slider_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider object + * @param parent pointer to an object, it will be the parent of the new slider. + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param obj pointer to a slider object + * @param value the new value + * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately + */ +static inline void lv_slider_set_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim) +{ + lv_bar_set_value(obj, value, anim); +} + +/** + * Set a new value for the left knob of a slider + * @param obj pointer to a slider object + * @param value new value + * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately + */ +static inline void lv_slider_set_left_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim) +{ + lv_bar_set_start_value(obj, value, anim); +} + +/** + * Set minimum and the maximum values of a bar + * @param obj pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t * obj, int32_t min, int32_t max) +{ + lv_bar_set_range(obj, min, max); +} + +/** + * Set the mode of slider. + * @param obj pointer to a slider object + * @param mode the mode of the slider. See ::lv_slider_mode_t + */ +static inline void lv_slider_set_mode(lv_obj_t * obj, lv_slider_mode_t mode) +{ + lv_bar_set_mode(obj, (lv_bar_mode_t)mode); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of the main knob of a slider + * @param obj pointer to a slider object + * @return the value of the main knob of the slider + */ +static inline int32_t lv_slider_get_value(const lv_obj_t * obj) +{ + return lv_bar_get_value(obj); +} + +/** + * Get the value of the left knob of a slider + * @param obj pointer to a slider object + * @return the value of the left knob of the slider + */ +static inline int32_t lv_slider_get_left_value(const lv_obj_t * obj) +{ + return lv_bar_get_start_value(obj); +} + +/** + * Get the minimum value of a slider + * @param obj pointer to a slider object + * @return the minimum value of the slider + */ +static inline int32_t lv_slider_get_min_value(const lv_obj_t * obj) +{ + return lv_bar_get_min_value(obj); +} + +/** + * Get the maximum value of a slider + * @param obj pointer to a slider object + * @return the maximum value of the slider + */ +static inline int32_t lv_slider_get_max_value(const lv_obj_t * obj) +{ + return lv_bar_get_max_value(obj); +} + +/** + * Give the slider is being dragged or not + * @param obj pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * obj); + +/** + * Get the mode of the slider. + * @param obj pointer to a bar object + * @return see ::lv_slider_mode_t + */ +static inline lv_slider_mode_t lv_slider_get_mode(lv_obj_t * slider) +{ + lv_bar_mode_t mode = lv_bar_get_mode(slider); + if(mode == LV_BAR_MODE_SYMMETRICAL) return LV_SLIDER_MODE_SYMMETRICAL; + else if(mode == LV_BAR_MODE_RANGE) return LV_SLIDER_MODE_RANGE; + else return LV_SLIDER_MODE_NORMAL; +} + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SLIDER*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/include/liblvgl/widgets/lv_switch.h b/include/liblvgl/widgets/lv_switch.h new file mode 100644 index 0000000..63ec427 --- /dev/null +++ b/include/liblvgl/widgets/lv_switch.h @@ -0,0 +1,61 @@ +/** + * @file lv_switch.h + * + */ + +#ifndef LV_SWITCH_H +#define LV_SWITCH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_SWITCH != 0 + +#include "liblvgl/core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/** Switch knob extra area correction factor */ +#define _LV_SWITCH_KNOB_EXT_AREA_CORRECTION 2 + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_obj_t obj; + int32_t anim_state; +} lv_switch_t; + +extern const lv_obj_class_t lv_switch_class; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch object + * @param parent pointer to an object, it will be the parent of the new switch + * @return pointer to the created switch + */ +lv_obj_t * lv_switch_create(lv_obj_t * parent); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_SWITCH*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_SWITCH_H*/ diff --git a/include/liblvgl/widgets/lv_table.h b/include/liblvgl/widgets/lv_table.h new file mode 100644 index 0000000..311d914 --- /dev/null +++ b/include/liblvgl/widgets/lv_table.h @@ -0,0 +1,210 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_TABLE != 0 + +/*Testing of dependencies*/ +#if LV_USE_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1)" +#endif + +#include "liblvgl/core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TABLE_CELL_NONE 0XFFFF +LV_EXPORT_CONST_INT(LV_TABLE_CELL_NONE); + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_TABLE_CELL_CTRL_MERGE_RIGHT = 1 << 0, + LV_TABLE_CELL_CTRL_TEXT_CROP = 1 << 1, + LV_TABLE_CELL_CTRL_CUSTOM_1 = 1 << 4, + LV_TABLE_CELL_CTRL_CUSTOM_2 = 1 << 5, + LV_TABLE_CELL_CTRL_CUSTOM_3 = 1 << 6, + LV_TABLE_CELL_CTRL_CUSTOM_4 = 1 << 7, +}; + +typedef uint8_t lv_table_cell_ctrl_t; + +/*Data of table*/ +typedef struct { + lv_obj_t obj; + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_coord_t * row_h; + lv_coord_t * col_w; + uint16_t col_act; + uint16_t row_act; +} lv_table_t; + +extern const lv_obj_class_t lv_table_class; + +/** + * `type` field in `lv_obj_draw_part_dsc_t` if `class_p = lv_table_class` + * Used in `LV_EVENT_DRAW_PART_BEGIN` and `LV_EVENT_DRAW_PART_END` + */ +typedef enum { + LV_TABLE_DRAW_PART_CELL, /**< A cell*/ +} lv_table_draw_part_type_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param parent pointer to an object, it will be the parent of the new table + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * parent); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param txt text to display in the cell. It will be copied and saved so this variable is not required after this function call. + * @note New roes/columns are added automatically if required + */ +void lv_table_set_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the value of a cell. Memory will be allocated to store the text by the table. + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param fmt `printf`-like format + * @note New roes/columns are added automatically if required + */ +void lv_table_set_cell_value_fmt(lv_obj_t * obj, uint16_t row, uint16_t col, const char * fmt, ...); + +/** + * Set the number of rows + * @param obj table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * obj, uint16_t row_cnt); + +/** + * Set the number of columns + * @param obj table pointer to a Table object + * @param col_cnt number of columns. + */ +void lv_table_set_col_cnt(lv_obj_t * obj, uint16_t col_cnt); + +/** + * Set the width of a column + * @param obj table pointer to a Table object + * @param col_id id of the column [0 .. LV_TABLE_COL_MAX -1] + * @param w width of the column + */ +void lv_table_set_col_width(lv_obj_t * obj, uint16_t col_id, lv_coord_t w); + +/** + * Add control bits to the cell. + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param ctrl OR-ed values from ::lv_table_cell_ctrl_t + */ +void lv_table_add_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl); + + +/** + * Clear control bits of the cell. + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param ctrl OR-ed values from ::lv_table_cell_ctrl_t + */ +void lv_table_clear_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @return text in the cell + */ +const char * lv_table_get_cell_value(lv_obj_t * obj, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param obj table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * obj); + +/** + * Get the number of columns. + * @param obj table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * obj); + +/** + * Get the width of a column + * @param obj table pointer to a Table object + * @param col id of the column [0 .. LV_TABLE_COL_MAX -1] + * @return width of the column + */ +lv_coord_t lv_table_get_col_width(lv_obj_t * obj, uint16_t col); + +/** + * Get whether a cell has the control bits + * @param obj pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param ctrl OR-ed values from ::lv_table_cell_ctrl_t + * @return true: all control bits are set; false: not all control bits are set + */ +bool lv_table_has_cell_ctrl(lv_obj_t * obj, uint16_t row, uint16_t col, lv_table_cell_ctrl_t ctrl); + +/** + * Get the selected cell (pressed and or focused) + * @param obj pointer to a table object + * @param row pointer to variable to store the selected row (LV_TABLE_CELL_NONE: if no cell selected) + * @param col pointer to variable to store the selected column (LV_TABLE_CELL_NONE: if no cell selected) + */ +void lv_table_get_selected_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_TABLE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/include/liblvgl/widgets/lv_textarea.h b/include/liblvgl/widgets/lv_textarea.h new file mode 100644 index 0000000..cfa47e4 --- /dev/null +++ b/include/liblvgl/widgets/lv_textarea.h @@ -0,0 +1,358 @@ +/** + * @file lv_textarea.h + * + */ + +#ifndef LV_TEXTAREA_H +#define LV_TEXTAREA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "liblvgl/lv_conf_internal.h" + +#if LV_USE_TEXTAREA != 0 + +/*Testing of dependencies*/ +#if LV_USE_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (LV_USE_LABEL 1)" +#endif + +#include "liblvgl/core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TEXTAREA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +LV_EXPORT_CONST_INT(LV_TEXTAREA_CURSOR_LAST); + +/********************** + * TYPEDEFS + **********************/ + +/*Data of text area*/ +typedef struct { + lv_obj_t obj; + lv_obj_t * label; /*Label of the text area*/ + char * placeholder_txt; /*Place holder label. only visible if text is an empty string*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + char * pwd_bullet; /*Replacement characters displayed in password mode*/ + const char * accepted_chars; /*Only these characters will be accepted. NULL: accept all*/ + uint32_t max_length; /*The max. number of characters. 0: no limit*/ + uint16_t pwd_show_time; /*Time to show characters in password mode before change them to '*'*/ + struct { + lv_coord_t valid_x; /*Used when stepping up/down to a shorter line. + *(Used by the library)*/ + uint32_t pos; /*The current cursor position + *(0: before 1st letter; 1: before 2nd letter ...)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint32_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + uint8_t show : 1; /*Cursor is visible now or not (Handled by the library)*/ + uint8_t click_pos : 1; /*1: Enable positioning the cursor by clicking the text area*/ + } cursor; +#if LV_LABEL_TEXT_SELECTION + uint32_t sel_start; /*Temporary values for text selection*/ + uint32_t sel_end; + uint8_t text_sel_in_prog : 1; /*User is in process of selecting*/ + uint8_t text_sel_en : 1; /*Text can be selected on this text area*/ +#endif + uint8_t pwd_mode : 1; /*Replace characters with '*'*/ + uint8_t one_line : 1; /*One line mode (ignore line breaks)*/ +} lv_textarea_t; + +extern const lv_obj_class_t lv_textarea_class; + +enum { + LV_PART_TEXTAREA_PLACEHOLDER = LV_PART_CUSTOM_FIRST, +}; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a text area object + * @param parent pointer to an object, it will be the parent of the new text area + * @return pointer to the created text area + */ +lv_obj_t * lv_textarea_create(lv_obj_t * parent); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Insert a character to the current cursor position. + * To add a wide char, e.g. 'Á' use `_lv_txt_encoded_conv_wc('Á')` + * @param obj pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_textarea_add_char(lv_obj_t * obj, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param obj pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_textarea_add_text(lv_obj_t * obj, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param obj pointer to a text area object + */ +void lv_textarea_del_char(lv_obj_t * obj); + +/** + * Delete the right character from the current cursor position + * @param obj pointer to a text area object + */ +void lv_textarea_del_char_forward(lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param obj pointer to a text area object + * @param txt pointer to the text + */ +void lv_textarea_set_text(lv_obj_t * obj, const char * txt); + +/** + * Set the placeholder text of a text area + * @param obj pointer to a text area object + * @param txt pointer to the text + */ +void lv_textarea_set_placeholder_text(lv_obj_t * obj, const char * txt); + +/** + * Set the cursor position + * @param obj pointer to a text area object + * @param pos the new cursor position in character index + * < 0 : index from the end of the text + * LV_TEXTAREA_CURSOR_LAST: go after the last character + */ +void lv_textarea_set_cursor_pos(lv_obj_t * obj, int32_t pos); + +/** + * Enable/Disable the positioning of the cursor by clicking the text on the text area. + * @param obj pointer to a text area object + * @param en true: enable click positions; false: disable + */ +void lv_textarea_set_cursor_click_pos(lv_obj_t * obj, bool en); + +/** + * Enable/Disable password mode + * @param obj pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_textarea_set_password_mode(lv_obj_t * obj, bool en); + +/** + * Set the replacement characters to show in password mode + * @param obj pointer to a text area object + * @param bullet pointer to the replacement text + */ +void lv_textarea_set_password_bullet(lv_obj_t * obj, const char * bullet); + +/** + * Configure the text area to one line or back to normal + * @param obj pointer to a text area object + * @param en true: one line, false: normal + */ +void lv_textarea_set_one_line(lv_obj_t * obj, bool en); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param obj pointer to a text area object + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_textarea_set_accepted_chars(lv_obj_t * obj, const char * list); + +/** + * Set max length of a Text Area. + * @param obj pointer to a text area object + * @param num the maximal number of characters can be added (`lv_textarea_set_text` ignores it) + */ +void lv_textarea_set_max_length(lv_obj_t * obj, uint32_t num); + +/** + * In `LV_EVENT_INSERT` the text which planned to be inserted can be replaced by an other text. + * It can be used to add automatic formatting to the text area. + * @param obj pointer to a text area object + * @param txt pointer to a new string to insert. If `""` no text will be added. + * The variable must be live after the `event_cb` exists. (Should be `global` or `static`) + */ +void lv_textarea_set_insert_replace(lv_obj_t * obj, const char * txt); + +/** + * Enable/disable selection mode. + * @param obj pointer to a text area object + * @param en true or false to enable/disable selection mode + */ +void lv_textarea_set_text_selection(lv_obj_t * obj, bool en); + +/** + * Set how long show the password before changing it to '*' + * @param obj pointer to a text area object + * @param time show time in milliseconds. 0: hide immediately. + */ +void lv_textarea_set_password_show_time(lv_obj_t * obj, uint16_t time); + +/** + * Deprecated: use the normal text_align style property instead + * Set the label's alignment. + * It sets where the label is aligned (in one line mode it can be smaller than the text area) + * and how the lines of the area align in case of multiline text area + * @param obj pointer to a text area object + * @param align the align mode from ::lv_text_align_t + */ +void lv_textarea_set_align(lv_obj_t * obj, lv_text_align_t align); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param obj pointer to a text area object + * @return pointer to the text + */ +const char * lv_textarea_get_text(const lv_obj_t * obj); + +/** + * Get the placeholder text of a text area + * @param obj pointer to a text area object + * @return pointer to the text + */ +const char * lv_textarea_get_placeholder_text(lv_obj_t * obj); + +/** + * Get the label of a text area + * @param obj pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_textarea_get_label(const lv_obj_t * obj); + +/** + * Get the current cursor position in character index + * @param obj pointer to a text area object + * @return the cursor position + */ +uint32_t lv_textarea_get_cursor_pos(const lv_obj_t * obj); + +/** + * Get whether the cursor click positioning is enabled or not. + * @param obj pointer to a text area object + * @return true: enable click positions; false: disable + */ +bool lv_textarea_get_cursor_click_pos(lv_obj_t * obj); + +/** + * Get the password mode attribute + * @param obj pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_textarea_get_password_mode(const lv_obj_t * obj); + +/** + * Get the replacement characters to show in password mode + * @param obj pointer to a text area object + * @return pointer to the replacement text + */ +const char * lv_textarea_get_password_bullet(lv_obj_t * obj); + +/** + * Get the one line configuration attribute + * @param obj pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_textarea_get_one_line(const lv_obj_t * obj); + +/** + * Get a list of accepted characters. + * @param obj pointer to a text area object + * @return list of accented characters. + */ +const char * lv_textarea_get_accepted_chars(lv_obj_t * obj); + +/** + * Get max length of a Text Area. + * @param obj pointer to a text area object + * @return the maximal number of characters to be add + */ +uint32_t lv_textarea_get_max_length(lv_obj_t * obj); + +/** + * Find whether text is selected or not. + * @param obj pointer to a text area object + * @return whether text is selected or not + */ +bool lv_textarea_text_is_selected(const lv_obj_t * obj); + +/** + * Find whether selection mode is enabled. + * @param obj pointer to a text area object + * @return true: selection mode is enabled, false: disabled + */ +bool lv_textarea_get_text_selection(lv_obj_t * obj); + +/** + * Set how long show the password before changing it to '*' + * @param obj pointer to a text area object + * @return show time in milliseconds. 0: hide immediately. + */ +uint16_t lv_textarea_get_password_show_time(lv_obj_t * obj); + +/*===================== + * Other functions + *====================*/ + +/** + * Clear the selection on the text area. + * @param obj pointer to a text area object + */ +void lv_textarea_clear_selection(lv_obj_t * obj); + +/** + * Move the cursor one character right + * @param obj pointer to a text area object + */ +void lv_textarea_cursor_right(lv_obj_t * obj); + +/** + * Move the cursor one character left + * @param obj pointer to a text area object + */ +void lv_textarea_cursor_left(lv_obj_t * obj); + +/** + * Move the cursor one line down + * @param obj pointer to a text area object + */ +void lv_textarea_cursor_down(lv_obj_t * obj); + +/** + * Move the cursor one line up + * @param obj pointer to a text area object + */ +void lv_textarea_cursor_up(lv_obj_t * obj); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_TEXTAREA_H*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_TEXTAREA_H*/ diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..9407e1e --- /dev/null +++ b/include/main.h @@ -0,0 +1,80 @@ +/** + * \file main.h + * + * Contains common definitions and header files used throughout your PROS + * project. + * + * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef _PROS_MAIN_H_ +#define _PROS_MAIN_H_ + +/** + * If defined, some commonly used enums will have preprocessor macros which give + * a shorter, more convenient naming pattern. If this isn't desired, simply + * comment the following line out. + * + * For instance, E_CONTROLLER_MASTER has a shorter name: CONTROLLER_MASTER. + * E_CONTROLLER_MASTER is pedantically correct within the PROS styleguide, but + * not convienent for most student programmers. + */ +#define PROS_USE_SIMPLE_NAMES + +/** + * If defined, C++ literals will be available for use. All literals are in the + * pros::literals namespace. + * + * For instance, you can do `4_mtr = 50` to set motor 4's target velocity to 50 + */ +#define PROS_USE_LITERALS + +#include "api.h" + +/** + * You should add more #includes here + */ +//#include "okapi/api.hpp" + +/** + * If you find doing pros::Motor() to be tedious and you'd prefer just to do + * Motor, you can use the namespace with the following commented out line. + * + * IMPORTANT: Only the okapi or pros namespace may be used, not both + * concurrently! The okapi namespace will export all symbols inside the pros + * namespace. + */ +// using namespace pros; +// using namespace pros::literals; +// using namespace okapi; + +/** + * Prototypes for the competition control tasks are redefined here to ensure + * that they can be called from user code (i.e. calling autonomous from a + * button press in opcontrol() for testing purposes). + */ +#ifdef __cplusplus +extern "C" { +#endif +void autonomous(void); +void initialize(void); +void disabled(void); +void competition_initialize(void); +void opcontrol(void); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +/** + * You can add C++-only headers here + */ +//#include +#endif + +#endif // _PROS_MAIN_H_ diff --git a/include/okapi/api.hpp b/include/okapi/api.hpp new file mode 100644 index 0000000..2c403e0 --- /dev/null +++ b/include/okapi/api.hpp @@ -0,0 +1,134 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +/** @mainpage OkapiLib Index Page + * + * @section intro_sec Introduction + * + * **OkapiLib** is a PROS library for programming VEX V5 robots. This library is intended to raise + * the floor for teams with all levels of experience. New teams should have an easier time getting + * their robot up and running, and veteran teams should find that OkapiLib doesn't get in the way or + * place any limits on functionality. + * + * For tutorials on how to get the most out of OkapiLib, see the + * [Tutorials](docs/tutorials/index.md) section. For documentation on using the OkapiLib API, see + * the [API](docs/api/index.md) section. + * + * @section getting_started Getting Started + * Not sure where to start? Take a look at the + * [Getting Started](docs/tutorials/walkthrough/gettingStarted.md) tutorial. + * Once you have OkapiLib set up, check out the + * [Clawbot](docs/tutorials/walkthrough/clawbot.md) tutorial. + * + * @section using_docs Using The Documentation + * + * Start with reading the [Tutorials](docs/tutorials/index.md). Use the [API](docs/api/index.md) + * section to explore the class hierarchy. To see a list of all available classes, use the + * [Classes](annotated.html) section. + * + * This documentation has a powerful search feature, which can be brought up with the keyboard + * shortcuts `Tab` or `T`. All exports to the `okapi` namespace such as enums, constants, units, or + * functions can be found [here](@ref okapi). + */ + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/chassis/model/threeEncoderXDriveModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/impl/chassis/controller/chassisControllerBuilder.hpp" + +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/api/control/util/flywheelSimulator.hpp" +#include "okapi/api/control/util/pidTuner.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncPosControllerBuilder.hpp" +#include "okapi/impl/control/async/asyncVelControllerBuilder.hpp" +#include "okapi/impl/control/iterative/iterativeControllerFactory.hpp" +#include "okapi/impl/control/util/controllerRunnerFactory.hpp" +#include "okapi/impl/control/util/pidTunerFactory.hpp" + +#include "okapi/api/odometry/odomMath.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/threeEncoderOdometry.hpp" + +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" +#include "okapi/impl/device/adiUltrasonic.hpp" +#include "okapi/impl/device/button/adiButton.hpp" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controller.hpp" +#include "okapi/impl/device/distanceSensor.hpp" +#include "okapi/impl/device/motor/adiMotor.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/opticalSensor.hpp" +#include "okapi/impl/device/rotarysensor/IMU.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/adiGyro.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/device/rotarysensor/potentiometer.hpp" +#include "okapi/impl/device/rotarysensor/rotationSensor.hpp" + +#include "okapi/api/filter/averageFilter.hpp" +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/filter/demaFilter.hpp" +#include "okapi/api/filter/ekfFilter.hpp" +#include "okapi/api/filter/emaFilter.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/filteredControllerInput.hpp" +#include "okapi/api/filter/medianFilter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularJerk.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QJerk.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/QPressure.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/QTorque.hpp" +#include "okapi/api/units/QVolume.hpp" +#include "okapi/api/units/RQuantityName.hpp" + +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include "okapi/impl/util/configurableTimeUtilFactory.hpp" +#include "okapi/impl/util/rate.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" +#include "okapi/impl/util/timer.hpp" diff --git a/include/okapi/api/chassis/controller/chassisController.hpp b/include/okapi/api/chassis/controller/chassisController.hpp new file mode 100644 index 0000000..9e3dcf9 --- /dev/null +++ b/include/okapi/api/chassis/controller/chassisController.hpp @@ -0,0 +1,142 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include +#include + +namespace okapi { +class ChassisController { + public: + /** + * A ChassisController adds a closed-loop layer on top of a ChassisModel. moveDistance and + * turnAngle both use closed-loop control to move the robot. There are passthrough functions for + * everything defined in ChassisModel. + * + * @param imodel underlying ChassisModel + */ + explicit ChassisController() = default; + + virtual ~ChassisController() = default; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistance(QLength itarget) = 0; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRaw(double itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + virtual void moveDistanceAsync(QLength itarget) = 0; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + virtual void moveRawAsync(double itarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngle(QAngle idegTarget) = 0; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRaw(double idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + virtual void turnAngleAsync(QAngle idegTarget) = 0; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + virtual void turnRawAsync(double idegTarget) = 0; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + virtual void setTurnsMirrored(bool ishouldMirror) = 0; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + virtual bool isSettled() = 0; + + /** + * Delays until the currently executing movement completes. + */ + virtual void waitUntilSettled() = 0; + + /** + * Interrupts the current movement to stop the robot. + */ + virtual void stop() = 0; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Get the ChassisScales. + */ + virtual ChassisScales getChassisScales() const = 0; + + /** + * Get the GearsetRatioPair. + */ + virtual AbstractMotor::GearsetRatioPair getGearsetRatioPair() const = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisModel. + */ + virtual ChassisModel &model() = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp b/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp new file mode 100644 index 0000000..6bee44e --- /dev/null +++ b/include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp @@ -0,0 +1,184 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class ChassisControllerIntegrated : public ChassisController { + public: + /** + * ChassisController using the V5 motor's integrated control. Puts the motors into encoder count + * units. Throws a `std::invalid_argument` exception if the gear ratio is zero. The initial + * model's max velocity will be propagated to the controllers. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param ileftController The controller used for the left side motors. + * @param irightController The controller used for the right side motors. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerIntegrated( + const TimeUtil &itimeUtil, + std::shared_ptr imodel, + std::unique_ptr ileftController, + std::unique_ptr irightController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Get the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Get the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr leftController; + std::unique_ptr rightController; + int lastTarget; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/controller/chassisControllerPid.hpp b/include/okapi/api/chassis/controller/chassisControllerPid.hpp new file mode 100644 index 0000000..91441ec --- /dev/null +++ b/include/okapi/api/chassis/controller/chassisControllerPid.hpp @@ -0,0 +1,275 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class ChassisControllerPID : public ChassisController { + public: + /** + * ChassisController using PID control. Puts the motors into encoder count units. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param imodel The ChassisModel used to read from sensors/write to motors. + * @param idistanceController The PID controller that controls chassis distance for driving + * straight. + * @param iturnController The PID controller that controls chassis angle for turning. + * @param iangleController The PID controller that controls chassis angle for driving straight. + * @param igearset The internal gearset and external ratio used on the drive motors. + * @param iscales The ChassisScales. + * @param ilogger The logger this instance will log to. + */ + ChassisControllerPID( + TimeUtil itimeUtil, + std::shared_ptr imodel, + std::unique_ptr idistanceController, + std::unique_ptr iturnController, + std::unique_ptr iangleController, + const AbstractMotor::GearsetRatioPair &igearset = AbstractMotor::gearset::green, + const ChassisScales &iscales = ChassisScales({1, 1}, imev5GreenTPR), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ChassisControllerPID(const ChassisControllerPID &) = delete; + ChassisControllerPID(ChassisControllerPID &&other) = delete; + ChassisControllerPID &operator=(const ChassisControllerPID &other) = delete; + ChassisControllerPID &operator=(ChassisControllerPID &&other) = delete; + + ~ChassisControllerPID() override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward 6 inches + * chassis->moveDistance(6_in); + * + * // Drive backward 0.2 meters + * chassis->moveDistance(-0.2_m); + * ``` + * + * @param itarget distance to travel + */ + void moveDistance(QLength itarget) override; + + /** + * Drives the robot straight for a distance (using closed-loop control). + * + * ```cpp + * // Drive forward by spinning the motors 400 degrees + * chassis->moveRaw(400); + * ``` + * + * @param itarget distance to travel in motor degrees + */ + void moveRaw(double itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * Sets the target distance for the robot to drive straight (using closed-loop control). + * + * @param itarget distance to travel in motor degrees + */ + void moveRawAsync(double itarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn 90 degrees clockwise + * chassis->turnAngle(90_deg); + * ``` + * + * @param idegTarget angle to turn for + */ + void turnAngle(QAngle idegTarget) override; + + /** + * Turns the robot clockwise in place (using closed-loop control). + * + * ```cpp + * // Turn clockwise by spinning the motors 200 degrees + * chassis->turnRaw(200); + * ``` + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRaw(double idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * Sets the target angle for the robot to turn clockwise in place (using closed-loop control). + * + * @param idegTarget angle to turn for in motor degrees + */ + void turnRawAsync(double idegTarget) override; + + /** + * Sets whether turns should be mirrored. + * + * @param ishouldMirror whether turns should be mirrored + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * Checks whether the internal controllers are currently settled. + * + * @return Whether this ChassisController is settled. + */ + bool isSettled() override; + + /** + * Delays until the currently executing movement completes. + */ + void waitUntilSettled() override; + + /** + * Gets the ChassisScales. + */ + ChassisScales getChassisScales() const override; + + /** + * Gets the GearsetRatioPair. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * Sets the velocity mode flag. When the controller is in velocity mode, the control loop will + * set motor velocities. When the controller is in voltage mode (`ivelocityMode = false`), the + * control loop will set motor voltages. Additionally, when the controller is in voltage mode, + * it will not obey maximum velocity limits. + * + * @param ivelocityMode Whether the controller should be in velocity or voltage mode. + */ + void setVelocityMode(bool ivelocityMode); + + /** + * Sets the gains for all controllers. + * + * @param idistanceGains The distance controller gains. + * @param iturnGains The turn controller gains. + * @param iangleGains The angle controller gains. + */ + void setGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Gets the current controller gains. + * + * @return The current controller gains in the order: distance, turn, angle. + */ + std::tuple + getGains() const; + + /** + * Starts the internal thread. This method is called by the ChassisControllerBuilder when making a + * new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Interrupts the current movement to stop the robot. + */ + void stop() override; + + /** + * Sets a new maximum velocity in RPM [0-600]. In voltage mode, the max velocity is ignored and a + * max voltage should be set on the underlying ChassisModel instead. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The maximum velocity in RPM [0-600]. + */ + double getMaxVelocity() const override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisModel. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + bool normalTurns{true}; + std::shared_ptr chassisModel; + TimeUtil timeUtil; + std::unique_ptr distancePid; + std::unique_ptr turnPid; + std::unique_ptr anglePid; + ChassisScales scales; + AbstractMotor::GearsetRatioPair gearsetRatioPair; + bool velocityMode{true}; + std::atomic_bool doneLooping{true}; + std::atomic_bool doneLoopingSeen{true}; + std::atomic_bool newMovement{false}; + std::atomic_bool dtorCalled{false}; + QTime threadSleepTime{10_ms}; + + static void trampoline(void *context); + void loop(); + + /** + * Wait for the distance setup (distancePid and anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForDistanceSettled(); + + /** + * Wait for the angle setup (anglePid) to settle. + * + * @return true if done settling; false if settling should be tried again + */ + bool waitForAngleSettled(); + + /** + * Stops all the controllers and the ChassisModel. + */ + void stopAfterSettled(); + + typedef enum { distance, angle, none } modeType; + modeType mode{none}; + + CrossplatformThread *task{nullptr}; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/controller/chassisScales.hpp b/include/okapi/api/chassis/controller/chassisScales.hpp new file mode 100644 index 0000000..d4d2909 --- /dev/null +++ b/include/okapi/api/chassis/controller/chassisScales.hpp @@ -0,0 +1,88 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" +#include "okapi/api/util/logging.hpp" +#include +#include +#include + +namespace okapi { +class ChassisScales { + public: + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the wheel diameter, the second element is the wheel track. For three-encoder configurations, + * the length from the center of rotation to the middle wheel and the middle wheel diameter are + * passed as the third and fourth elements. + * + * The wheel track is the center-to-center distance between the wheels (center-to-center + * meaning the width between the centers of both wheels). For example, if you are using four inch + * omni wheels and there are 11.5 inches between the centers of each wheel, you would call the + * constructor like so: + * `ChassisScales scales({4_in, 11.5_in}, imev5GreenTPR); // imev5GreenTPR for a green gearset` + * + * Wheel diameter + * + * +-+ Center of rotation + * | | | + * v v +----------+ Length to middle wheel + * | | from center of rotation + * +---> === | === | + * | + v + | + * | ++---------------++ | + * | | | v + * Wheel track | | | + * | | x |+| <-- Middle wheel + * | | | + * | | | + * | ++---------------++ + * | + + + * +---> === === + * + * + * @param idimensions {wheel diameter, wheel track} or {wheel diameter, wheel track, length to + * middle wheel, middle wheel diameter}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &idimensions, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * The scales a ChassisController needs to do all of its closed-loop control. The first element is + * the straight scale, the second element is the turn scale. Optionally, the length from the + * center of rotation to the middle wheel and the middle scale can be passed as the third and + * fourth elements. The straight scale converts motor degrees to meters, the turn scale converts + * motor degrees to robot turn degrees, and the middle scale converts middle wheel degrees to + * meters. + * + * @param iscales {straight scale, turn scale} or {straight scale, turn scale, length to middle + * wheel in meters, middle scale}. + * @param itpr The ticks per revolution of the encoders. + * @param ilogger The logger this instance will log to. + */ + ChassisScales(const std::initializer_list &iscales, + double itpr, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + QLength wheelDiameter; + QLength wheelTrack; + QLength middleWheelDistance; + QLength middleWheelDiameter; + double straight; + double turn; + double middle; + double tpr; + + protected: + static void validateInputSize(std::size_t inputSize, const std::shared_ptr &logger); +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp b/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp new file mode 100644 index 0000000..f8fe52e --- /dev/null +++ b/include/okapi/api/chassis/controller/defaultOdomChassisController.hpp @@ -0,0 +1,183 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/odomChassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include + +namespace okapi { +class DefaultOdomChassisController : public OdomChassisController { + public: + /** + * Odometry based chassis controller that moves using a separately constructed chassis controller. + * Spins up a task at the default priority plus 1 for odometry when constructed. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle, relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The odometry to read state estimates from. + * @param icontroller The chassis controller to delegate to. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + * @param ilogger The logger this instance will log to. + */ + DefaultOdomChassisController(const TimeUtil &itimeUtil, + std::shared_ptr iodometry, + std::shared_ptr icontroller, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + QLength imoveThreshold = 0_mm, + QAngle iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + DefaultOdomChassisController(const DefaultOdomChassisController &) = delete; + DefaultOdomChassisController(DefaultOdomChassisController &&other) = delete; + DefaultOdomChassisController &operator=(const DefaultOdomChassisController &other) = delete; + DefaultOdomChassisController &operator=(DefaultOdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + void driveToPoint(const Point &ipoint, + bool ibackwards = false, + const QLength &ioffset = 0_mm) override; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + void turnToPoint(const Point &ipoint) override; + + /** + * @return The internal ChassisController. + */ + std::shared_ptr getChassisController(); + + /** + * @return The internal ChassisController. + */ + ChassisController &chassisController(); + + /** + * This delegates to the input ChassisController. + */ + void turnToAngle(const QAngle &iangle) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistance(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRaw(double itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveDistanceAsync(QLength itarget) override; + + /** + * This delegates to the input ChassisController. + */ + void moveRawAsync(double itarget) override; + + /** + * Turns chassis to desired angle (turns in the direction of smallest angle) + * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) + * + * @param idegTarget target angle + */ + void turnAngle(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRaw(double idegTarget) override; + + /** + * Turns chassis to desired angle (turns in the direction of smallest angle) + * (ex. If current angle is 0 and target is 270, the chassis will turn -90 degrees) + * + * @param idegTarget target angle + */ + void turnAngleAsync(QAngle idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void turnRawAsync(double idegTarget) override; + + /** + * This delegates to the input ChassisController. + */ + void setTurnsMirrored(bool ishouldMirror) override; + + /** + * This delegates to the input ChassisController. + */ + bool isSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void waitUntilSettled() override; + + /** + * This delegates to the input ChassisController. + */ + void stop() override; + + /** + * This delegates to the input ChassisController. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * This delegates to the input ChassisController. + */ + double getMaxVelocity() const override; + + /** + * This delegates to the input ChassisController. + */ + ChassisScales getChassisScales() const override; + + /** + * This delegates to the input ChassisController. + */ + AbstractMotor::GearsetRatioPair getGearsetRatioPair() const override; + + /** + * This delegates to the input ChassisController. + */ + std::shared_ptr getModel() override; + + /** + * This delegates to the input ChassisController. + */ + ChassisModel &model() override; + + protected: + std::shared_ptr logger; + std::shared_ptr controller; + + void waitForOdomTask(); +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/controller/odomChassisController.hpp b/include/okapi/api/chassis/controller/odomChassisController.hpp new file mode 100644 index 0000000..e2de53a --- /dev/null +++ b/include/okapi/api/chassis/controller/odomChassisController.hpp @@ -0,0 +1,154 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class OdomChassisController : public ChassisController { + public: + /** + * Odometry based chassis controller. Starts task at the default for odometry when constructed, + * which calls `Odometry::step` every `10ms`. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * Moves the robot around in the odom frame. Instead of telling the robot to drive forward or + * turn some amount, you instead tell it to drive to a specific point on the field or turn to + * a specific angle relative to its starting position. + * + * @param itimeUtil The TimeUtil. + * @param iodometry The Odometry instance to run in a new task. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold minimum length movement (smaller movements will be skipped) + * @param iturnThreshold minimum angle turn (smaller turns will be skipped) + */ + OdomChassisController(TimeUtil itimeUtil, + std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + ~OdomChassisController() override; + + OdomChassisController(const OdomChassisController &) = delete; + OdomChassisController(OdomChassisController &&other) = delete; + OdomChassisController &operator=(const OdomChassisController &other) = delete; + OdomChassisController &operator=(OdomChassisController &&other) = delete; + + /** + * Drives the robot straight to a point in the odom frame. + * + * @param ipoint The target point to navigate to. + * @param ibackwards Whether to drive to the target point backwards. + * @param ioffset An offset from the target point in the direction pointing towards the robot. The + * robot will stop this far away from the target point. + */ + virtual void + driveToPoint(const Point &ipoint, bool ibackwards = false, const QLength &ioffset = 0_mm) = 0; + + /** + * Turns the robot to face a point in the odom frame. + * + * @param ipoint The target point to turn to face. + */ + virtual void turnToPoint(const Point &ipoint) = 0; + + /** + * Turns the robot to face an angle in the odom frame. + * + * @param iangle The angle to turn to. + */ + virtual void turnToAngle(const QAngle &iangle) = 0; + + /** + * @return The current state. + */ + virtual OdomState getState() const; + + /** + * Set a new state to be the current state. The default StateMode is + * `StateMode::FRAME_TRANSFORMATION`. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate); + + /** + * Sets a default StateMode that will be used to interpret target points and query the Odometry + * state. + * + * @param imode The new default StateMode. + */ + void setDefaultStateMode(const StateMode &imode); + + /** + * Set a new move threshold. Any requested movements smaller than this threshold will be skipped. + * + * @param imoveThreshold new move threshold + */ + virtual void setMoveThreshold(const QLength &imoveThreshold); + + /** + * Set a new turn threshold. Any requested turns smaller than this threshold will be skipped. + * + * @param iturnTreshold new turn threshold + */ + virtual void setTurnThreshold(const QAngle &iturnTreshold); + + /** + * @return The current move threshold. + */ + virtual QLength getMoveThreshold() const; + + /** + * @return The current turn threshold. + */ + virtual QAngle getTurnThreshold() const; + + /** + * Starts the internal odometry thread. This should not be called by normal users. + */ + void startOdomThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getOdomThread() const; + + /** + * @return The internal odometry. + */ + std::shared_ptr getOdometry(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + QLength moveThreshold; + QAngle turnThreshold; + std::shared_ptr odom; + CrossplatformThread *odomTask{nullptr}; + std::atomic_bool dtorCalled{false}; + StateMode defaultStateMode{StateMode::FRAME_TRANSFORMATION}; + std::atomic_bool odomTaskRunning{false}; + + static void trampoline(void *context); + void loop(); +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/chassisModel.hpp b/include/okapi/api/chassis/model/chassisModel.hpp new file mode 100644 index 0000000..1968759 --- /dev/null +++ b/include/okapi/api/chassis/model/chassisModel.hpp @@ -0,0 +1,165 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * A version of the ReadOnlyChassisModel that also supports write methods, such as setting motor + * speed. Because this class can write to motors, there can only be one owner and as such copying + * is disabled. + */ +class ChassisModel : public ReadOnlyChassisModel { + public: + explicit ChassisModel() = default; + ChassisModel(const ChassisModel &) = delete; + ChassisModel &operator=(const ChassisModel &) = delete; + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + virtual void forward(double ispeed) = 0; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVector(double iforwardSpeed, double iyaw) = 0; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + virtual void driveVectorVoltage(double iforwardSpeed, double iyaw) = 0; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + virtual void rotate(double ispeed) = 0; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + virtual void stop() = 0; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + virtual void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) = 0; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) = 0; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + virtual void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) = 0; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void left(double ispeed) = 0; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ipower motor power + */ + virtual void right(double ispeed) = 0; + + /** + * Reset the sensors to their zero point. + */ + virtual void resetSensors() = 0; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + virtual void setBrakeMode(AbstractMotor::brakeMode mode) = 0; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + virtual void setEncoderUnits(AbstractMotor::encoderUnits units) = 0; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + virtual void setGearing(AbstractMotor::gearset gearset) = 0; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(double imaxVelocity) = 0; + + /** + * @return The current maximum velocity. + */ + virtual double getMaxVelocity() const = 0; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + virtual void setMaxVoltage(double imaxVoltage) = 0; + + /** + * @return The maximum voltage in mV `[0-12000]`. + */ + virtual double getMaxVoltage() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/hDriveModel.hpp b/include/okapi/api/chassis/model/hDriveModel.hpp new file mode 100644 index 0000000..5afb95f --- /dev/null +++ b/include/okapi/api/chassis/model/hDriveModel.hpp @@ -0,0 +1,247 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class HDriveModel : public ChassisModel { + public: + /** + * Model for an h-drive (wheels parallel with robot's direction of motion, with an additional + * wheel perpendicular to those). When the left and right side motors are powered +100%, the robot + * should move forward in a straight line. When the middle motor is powered +100%, the robot + * should strafe right in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param imiddleMotor The middle (perpendicular) motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + HDriveModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr imiddleMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. Sets the middle motor to zero velocity. + * + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. Sets the middle motor + * to zero velocity. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. Sets the middle motor to zero + * velocity. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. Sets the middle motor to zero velocity. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + hArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Drive the robot with an curvature drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + virtual void + hCurvature(double irightSpeed, double iforwardSpeed, double icurvature, double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Power the middle motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + virtual void middle(double ispeed); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + /** + * @return The middle motor. + */ + std::shared_ptr getMiddleMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr middleMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/readOnlyChassisModel.hpp b/include/okapi/api/chassis/model/readOnlyChassisModel.hpp new file mode 100644 index 0000000..01526f1 --- /dev/null +++ b/include/okapi/api/chassis/model/readOnlyChassisModel.hpp @@ -0,0 +1,28 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/coreProsAPI.hpp" +#include + +namespace okapi { +/** + * A version of the ChassisModel that only supports read methods, such as querying sensor values. + * This class does not let you write to motors, so it supports having multiple owners and as a + * result copying is enabled. + */ +class ReadOnlyChassisModel { + public: + virtual ~ReadOnlyChassisModel() = default; + + /** + * Read the sensors. + * + * @return sensor readings (format is implementation dependent) + */ + virtual std::valarray getSensorVals() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/skidSteerModel.hpp b/include/okapi/api/chassis/model/skidSteerModel.hpp new file mode 100644 index 0000000..7994c14 --- /dev/null +++ b/include/okapi/api/chassis/model/skidSteerModel.hpp @@ -0,0 +1,198 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class SkidSteerModel : public ChassisModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +100%, the robot should move forward in a straight line. + * + * @param ileftSideMotor The left side motor. + * @param irightSideMotor The right side motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + SkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ispeed) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = ySpeed + zRotation + * rightPower = ySpeed - zRotation + * + * @param iySpeed speed on y axis (forward) + * @param izRotation speed around z axis (up) + */ + void driveVector(double iySpeed, double izRotation) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void rotate(double ispeed) override; + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getLeftSideMotor() const; + + /** + * Returns the left side motor. + * + * @return the left side motor + */ + std::shared_ptr getRightSideMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr leftSideMotor; + std::shared_ptr rightSideMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp b/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp new file mode 100644 index 0000000..2acbe3c --- /dev/null +++ b/include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/skidSteerModel.hpp" + +namespace okapi { +class ThreeEncoderSkidSteerModel : public SkidSteerModel { + public: + /** + * Model for a skid steer drive (wheels parallel with robot's direction of motion). When all + * motors are powered +127, the robot should move forward in a straight line. + * + * @param ileftSideMotor left side motor + * @param irightSideMotor right side motor + * @param ileftEnc left side encoder + * @param imiddleEnc middle encoder (mounted perpendicular to the left and right side encoders) + * @param irightEnc right side encoder + */ + ThreeEncoderSkidSteerModel(std::shared_ptr ileftSideMotor, + std::shared_ptr irightSideMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp b/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp new file mode 100644 index 0000000..14e4ee0 --- /dev/null +++ b/include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp @@ -0,0 +1,50 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/xDriveModel.hpp" + +namespace okapi { +class ThreeEncoderXDriveModel : public XDriveModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + * @param imiddleEnc The middle encoder. + */ + ThreeEncoderXDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + std::shared_ptr imiddleEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right, middle} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + protected: + std::shared_ptr middleSensor; +}; +} // namespace okapi diff --git a/include/okapi/api/chassis/model/xDriveModel.hpp b/include/okapi/api/chassis/model/xDriveModel.hpp new file mode 100644 index 0000000..07781be --- /dev/null +++ b/include/okapi/api/chassis/model/xDriveModel.hpp @@ -0,0 +1,273 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/chassisModel.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/api/units/QAngle.hpp" + +namespace okapi { +class XDriveModel : public ChassisModel { + public: + /** + * Model for an x drive (wheels at 45 deg from a skid steer drive). When all motors are powered + * +100%, the robot should move forward in a straight line. + * + * @param itopLeftMotor The top left motor. + * @param itopRightMotor The top right motor. + * @param ibottomRightMotor The bottom right motor. + * @param ibottomLeftMotor The bottom left motor. + * @param ileftEnc The left side encoder. + * @param irightEnc The right side encoder. + */ + XDriveModel(std::shared_ptr itopLeftMotor, + std::shared_ptr itopRightMotor, + std::shared_ptr ibottomRightMotor, + std::shared_ptr ibottomLeftMotor, + std::shared_ptr ileftEnc, + std::shared_ptr irightEnc, + double imaxVelocity, + double imaxVoltage); + + /** + * Drive the robot forwards (using open-loop control). Uses velocity mode. + * + * @param ispeed motor power + */ + void forward(double ipower) override; + + /** + * Drive the robot in an arc (using open-loop control). Uses velocity mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVector(double iforwardSpeed, double iyaw) override; + + /** + * Drive the robot in an arc. Uses voltage mode. + * The algorithm is (approximately): + * leftPower = forwardSpeed + yaw + * rightPower = forwardSpeed - yaw + * + * @param iforwadSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + */ + void driveVectorVoltage(double iforwardSpeed, double iyaw) override; + + /** + * Turn the robot clockwise (using open-loop control). Uses velocity mode. + * + * @param ipower motor power + */ + void rotate(double ipower) override; + + /** + * Drive the robot side-ways (using open-loop control) where positive ipower is + * to the right and negative ipower is to the left. Uses velocity mode. + * + * @param ispeed motor power + */ + void strafe(double ipower); + + /** + * Strafe the robot in an arc (using open-loop control) where positive istrafeSpeed is + * to the right and negative istrafeSpeed is to the left. Uses velocity mode. + * The algorithm is (approximately): + * topLeftPower = -1 * istrafeSpeed + yaw + * topRightPower = istrafeSpeed - yaw + * bottomRightPower = -1 * istrafeSpeed - yaw + * bottomLeftPower = istrafeSpeed + yaw + * + * @param istrafeSpeed speed to the right + * @param iyaw speed around the vertical axis + */ + void strafeVector(double istrafeSpeed, double iyaw); + + /** + * Stop the robot (set all the motors to 0). Uses velocity mode. + */ + void stop() override; + + /** + * Drive the robot with a tank drive layout. Uses voltage mode. + * + * @param ileftSpeed left side speed + * @param irightSpeed right side speed + * @param ithreshold deadband on joystick values + */ + void tank(double ileftSpeed, double irightSpeed, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + void arcade(double iforwardSpeed, double iyaw, double ithreshold = 0) override; + + /** + * Drive the robot with a curvature drive layout. The robot drives in constant radius turns + * where you control the curvature (inverse of radius) you drive in. This is advantageous + * because the forward speed will not affect the rate of turning. The algorithm switches to + * arcade if the forward speed is 0. Uses voltage mode. + * + * @param iforwardSpeed speed forward direction + * @param icurvature curvature (inverse of radius) to drive in + * @param ithreshold deadband on joystick values + */ + void curvature(double iforwardSpeed, double icurvature, double ithreshold = 0) override; + + /** + * Drive the robot with an arcade drive layout. Uses voltage mode. + * + * @param irightSpeed speed to the right + * @param iforwardSpeed speed in the forward direction + * @param iyaw speed around the vertical axis + * @param ithreshold deadband on joystick values + */ + virtual void + xArcade(double irightSpeed, double iforwardSpeed, double iyaw, double ithreshold = 0); + + /** + * Drive the robot with a field-oriented arcade drive layout. Uses voltage mode. + * For example: + * Both `fieldOrientedXArcade(1, 0, 0, 0_deg)` and `fieldOrientedXArcade(1, 0, 0, 90_deg)` + * will drive the chassis in the forward/north direction. In other words, no matter + * the robot's heading, the robot will move forward/north when you tell it + * to move forward/north and will move right/east when you tell it to move right/east. + * + * + * @param ixSpeed forward speed -- (`+1`) forward, (`-1`) backward + * @param iySpeed sideways speed -- (`+1`) right, (`-1`) left + * @param iyaw turn speed -- (`+1`) clockwise, (`-1`) counter-clockwise + * @param iangle current chassis angle (`0_deg` = no correction, winds clockwise) + * @param ithreshold deadband on joystick values + */ + virtual void fieldOrientedXArcade(double ixSpeed, + double iySpeed, + double iyaw, + QAngle iangle, + double ithreshold = 0); + + /** + * Power the left side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void left(double ispeed) override; + + /** + * Power the right side motors. Uses velocity mode. + * + * @param ispeed The motor power. + */ + void right(double ispeed) override; + + /** + * Read the sensors. + * + * @return sensor readings in the format {left, right} + */ + std::valarray getSensorVals() const override; + + /** + * Reset the sensors to their zero point. + */ + void resetSensors() override; + + /** + * Set the brake mode for each motor. + * + * @param mode new brake mode + */ + void setBrakeMode(AbstractMotor::brakeMode mode) override; + + /** + * Set the encoder units for each motor. + * + * @param units new motor encoder units + */ + void setEncoderUnits(AbstractMotor::encoderUnits units) override; + + /** + * Set the gearset for each motor. + * + * @param gearset new motor gearset + */ + void setGearing(AbstractMotor::gearset gearset) override; + + /** + * Sets a new maximum velocity in RPM. The usable maximum depends on the maximum velocity of the + * currently installed gearset. If the configured maximum velocity is greater than the attainable + * maximum velocity from the currently installed gearset, the ChassisModel will still scale to + * that velocity. + * + * @param imaxVelocity The new maximum velocity. + */ + void setMaxVelocity(double imaxVelocity) override; + + /** + * @return The current maximum velocity. + */ + double getMaxVelocity() const override; + + /** + * Sets a new maximum voltage in mV in the range `[0-12000]`. + * + * @param imaxVoltage The new maximum voltage. + */ + void setMaxVoltage(double imaxVoltage) override; + + /** + * @return The maximum voltage in mV in the range `[0-12000]`. + */ + double getMaxVoltage() const override; + + /** + * Returns the top left motor. + * + * @return the top left motor + */ + std::shared_ptr getTopLeftMotor() const; + + /** + * Returns the top right motor. + * + * @return the top right motor + */ + std::shared_ptr getTopRightMotor() const; + + /** + * Returns the bottom right motor. + * + * @return the bottom right motor + */ + std::shared_ptr getBottomRightMotor() const; + + /** + * Returns the bottom left motor. + * + * @return the bottom left motor + */ + std::shared_ptr getBottomLeftMotor() const; + + protected: + double maxVelocity; + double maxVoltage; + std::shared_ptr topLeftMotor; + std::shared_ptr topRightMotor; + std::shared_ptr bottomRightMotor; + std::shared_ptr bottomLeftMotor; + std::shared_ptr leftSensor; + std::shared_ptr rightSensor; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncController.hpp b/include/okapi/api/control/async/asyncController.hpp new file mode 100644 index 0000000..e0da0da --- /dev/null +++ b/include/okapi/api/control/async/asyncController.hpp @@ -0,0 +1,24 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/closedLoopController.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps on its own in another thread and automatically writes to the + * output. + */ +template +class AsyncController : public ClosedLoopController { + public: + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + virtual void waitUntilSettled() = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp b/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp new file mode 100644 index 0000000..8efcc74 --- /dev/null +++ b/include/okapi/api/control/async/asyncLinearMotionProfileController.hpp @@ -0,0 +1,291 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +#include "squiggles.hpp" + +namespace okapi { +class AsyncLinearMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 1D motion profiles. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param ioutput The output to write velocity targets to. + * @param idiameter The effective diameter for whatever the motor spins. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncLinearMotionProfileController( + const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncLinearMotionProfileController(AsyncLinearMotionProfileController &&other) = delete; + + AsyncLinearMotionProfileController & + operator=(AsyncLinearMotionProfileController &&other) = delete; + + ~AsyncLinearMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same `pathId` to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns `true` if the path was + * either deleted or didn't exist in the first place. It returns `false` if the path could not be + * removed because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to generatePath() + * @return `true` if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + */ + void setTarget(std::string ipathId, bool ibackwards); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual std::string getTarget() const; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, const QLength &itarget, bool ibackwards = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iposition The starting position. + * @param itarget The target position. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + */ + void moveTo(const QLength &iposition, + const QLength &itarget, + const PathfinderLimits &ilimits, + bool ibackwards = false); + + /** + * Returns the last error of the controller. Does not update when disabled. Returns zero if there + * is no path currently being followed. + * + * @return the last error + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread(); + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Attempts to remove a path without stopping execution, then if that fails, disables the + * controller and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + std::shared_ptr logger; + std::map> paths{}; + PathfinderLimits limits; + std::shared_ptr> output; + QLength diameter; + AbstractMotor::GearsetRatioPair pair; + double currentProfilePosition{0}; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const std::vector &path, + std::unique_ptr rate); + + /** + * Converts linear "chassis" speed to rotational motor speed. + * + * @param linear "chassis" frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string getPathErrorMessage(const std::vector &points, + const std::string &ipathId, + int length); +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncMotionProfileController.hpp b/include/okapi/api/control/async/asyncMotionProfileController.hpp new file mode 100644 index 0000000..3c8b74a --- /dev/null +++ b/include/okapi/api/control/async/asyncMotionProfileController.hpp @@ -0,0 +1,326 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/util/pathfinderUtil.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +#include "squiggles.hpp" + +namespace okapi { +class AsyncMotionProfileController : public AsyncPositionController { + public: + /** + * An Async Controller which generates and follows 2D motion profiles. Throws a + * `std::invalid_argument` exception if the gear ratio is zero. + * + * @param itimeUtil The TimeUtil. + * @param ilimits The default limits. + * @param imodel The chassis model to control. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @param ilogger The logger this instance will log to. + */ + AsyncMotionProfileController(const TimeUtil &itimeUtil, + const PathfinderLimits &ilimits, + const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + AsyncMotionProfileController(AsyncMotionProfileController &&other) = delete; + + AsyncMotionProfileController &operator=(AsyncMotionProfileController &&other) = delete; + + ~AsyncMotionProfileController() override; + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + */ + void generatePath(std::initializer_list iwaypoints, const std::string &ipathId); + + /** + * Generates a path which intersects the given waypoints and saves it internally with a key of + * pathId. Call `executePath()` with the same pathId to run it. + * + * If the waypoints form a path which is impossible to achieve, an instance of + * `std::runtime_error` is thrown (and an error is logged) which describes the waypoints. If there + * are no waypoints, no path is generated. + * + * NOTE: The waypoints are expected to be in the + * okapi::State::FRAME_TRANSFORMATION format where +x is forward, +y is right, + * and 0 theta is measured from the +x axis to the +y axis. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ipathId A unique identifier to save the path with. + * @param ilimits The limits to use for this path only. + */ + void generatePath(std::initializer_list iwaypoints, + const std::string &ipathId, + const PathfinderLimits &ilimits); + + /** + * Removes a path and frees the memory it used. This function returns true if the path was either + * deleted or didn't exist in the first place. It returns false if the path could not be removed + * because it is running. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()` + * @return True if the path no longer exists + */ + bool removePath(const std::string &ipathId); + + /** + * Gets the identifiers of all paths saved in this `AsyncMotionProfileController`. + * + * @return The identifiers of all paths + */ + std::vector getPaths(); + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + */ + void setTarget(std::string ipathId) override; + + /** + * Executes a path with the given ID. If there is no path matching the ID, the method will + * return. Any targets set while a path is being followed will be ignored. + * + * @param ipathId A unique identifier for the path, previously passed to `generatePath()`. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void setTarget(std::string ipathId, bool ibackwards, bool imirrored = false); + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. This just calls `setTarget()`. + */ + void controllerSet(std::string ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + std::string getTarget() override; + + /** + * This is overridden to return the current path. + * + * @return The most recent value of the process variable. + */ + std::string getProcessValue() const override; + + /** + * Blocks the current task until the controller has settled. This controller is settled when + * it has finished following a path. If no path is being followed, it is settled. + */ + void waitUntilSettled() override; + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + bool ibackwards = false, + bool imirrored = false); + + /** + * Generates a new path from the position (typically the current position) to the target and + * blocks until the controller has settled. Does not save the path which was generated. + * + * @param iwaypoints The waypoints to hit on the path. + * @param ilimits The limits to use for this path only. + * @param ibackwards Whether to follow the profile backwards. + * @param imirrored Whether to follow the profile mirrored. + */ + void moveTo(std::initializer_list iwaypoints, + const PathfinderLimits &ilimits, + bool ibackwards = false, + bool imirrored = false); + + /** + * Returns the last error of the controller. Does not update when disabled. This implementation + * always returns zero since the robot is assumed to perfectly follow the path. Subclasses can + * override this to be more accurate using odometry information. + * + * @return the last error + */ + PathfinderPoint getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller so it can start from 0 again properly. Keeps configuration from + * before. This implementation also stops movement. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * NOT cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * This implementation does nothing because the API always requires the starting position to be + * specified. + */ + void tarePosition() override; + + /** + * This implementation does nothing because the maximum velocity is configured using + * PathfinderLimits elsewhere. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the `AsyncMotionProfileControllerBuilder` when making a new instance of this class. + */ + void startThread(); + + /** + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const; + + /** + * Saves a generated path to a file. Paths are stored as `.csv`. An SD card + * must be inserted into the brain and the directory must exist. `idirectory` can be prefixed with + * `/usd/`, but it this is not required. + * + * @param idirectory The directory to store the path file in + * @param ipathId The path ID of the generated path + */ + void storePath(const std::string &idirectory, const std::string &ipathId); + + /** + * Loads a path from a directory on the SD card containing a path CSV file. `/usd/` is + * automatically prepended to `idirectory` if it is not specified. + * + * @param idirectory The directory that the path files are stored in + * @param ipathId The path ID that the paths are stored under (and will be loaded into) + */ + void loadPath(const std::string &idirectory, const std::string &ipathId); + + /** + * Attempts to remove a path without stopping execution. If that fails, disables the controller + * and removes the path. + * + * @param ipathId The path ID that will be removed + */ + void forceRemovePath(const std::string &ipathId); + + protected: + std::shared_ptr logger; + std::map> paths{}; + PathfinderLimits limits; + std::shared_ptr model; + ChassisScales scales; + AbstractMotor::GearsetRatioPair pair; + TimeUtil timeUtil; + + // This must be locked when accessing the current path + CrossplatformMutex currentPathMutex; + + std::string currentPath{""}; + std::atomic_bool isRunning{false}; + std::atomic_int direction{1}; + std::atomic_bool mirrored{false}; + std::atomic_bool disabled{false}; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context); + void loop(); + + /** + * Follow the supplied path. Must follow the disabled lifecycle. + */ + virtual void executeSinglePath(const std::vector &path, + std::unique_ptr rate); + + /** + * Converts linear chassis speed to rotational motor speed. + * + * @param linear chassis frame speed + * @return motor frame speed + */ + QAngularSpeed convertLinearToRotational(QSpeed linear) const; + + std::string getPathErrorMessage(const std::vector &points, + const std::string &ipathId, + int length); + + /** + * Joins and escapes a directory and file name + * + * @param directory The directory path, separated by forward slashes (/) and with or without a + * trailing slash + * @param filename The file name in the directory + * @return the fully qualified and legal path name + */ + static std::string makeFilePath(const std::string &directory, const std::string &filename); + + void internalStorePath(std::ostream &file, const std::string &ipathId); + void internalLoadPath(std::istream &file, const std::string &ipathId); + void internalLoadPathfinderPath(std::istream &leftFile, + std::istream &rightFile, + const std::string &ipathId); + + static constexpr double DT = 0.01; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncPosIntegratedController.hpp b/include/okapi/api/control/async/asyncPosIntegratedController.hpp new file mode 100644 index 0000000..1b47976 --- /dev/null +++ b/include/okapi/api/control/async/asyncPosIntegratedController.hpp @@ -0,0 +1,145 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncPosIntegratedController : public AsyncPositionController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncPosIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * Sets a new maximum velocity in motor RPM [0-600]. + * + * @param imaxVelocity The new maximum velocity in motor RPM [0-600]. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Stops the motor mid-movement. Does not change the last set target. + */ + virtual void stop(); + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget{0}; + double offset{0}; + bool controllerIsDisabled{false}; + bool hasFirstTarget{false}; + std::unique_ptr settledUtil; + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncPosPidController.hpp b/include/okapi/api/control/async/asyncPosPidController.hpp new file mode 100644 index 0000000..0621a03 --- /dev/null +++ b/include/okapi/api/control/async/asyncPosPidController.hpp @@ -0,0 +1,100 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/offsettableControllerInput.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncPosPIDController : public AsyncWrapper, + public AsyncPositionController { + public: + /** + * An async position PID controller. + * + * @param iinput The controller input. Will be turned into an OffsettableControllerInput. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * An async position PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikI The integral gain. + * @param ikD The derivative gain. + * @param ikBias The controller bias. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncPosPIDController( + const std::shared_ptr &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikI, + double ikD, + double ikBias = 0, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + void tarePosition() override; + + /** + * This implementation does not respect the maximum velocity. + * + * @param imaxVelocity Ignored. + */ + void setMaxVelocity(std::int32_t imaxVelocity) override; + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativePosPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativePosPIDController::Gains getGains() const; + + protected: + std::shared_ptr offsettableInput; + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncPositionController.hpp b/include/okapi/api/control/async/asyncPositionController.hpp new file mode 100644 index 0000000..9ed954f --- /dev/null +++ b/include/okapi/api/control/async/asyncPositionController.hpp @@ -0,0 +1,28 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncPositionController : virtual public AsyncController { + public: + /** + * Sets the "absolute" zero position of the controller to its current position. + */ + virtual void tarePosition() = 0; + + /** + * Sets a new maximum velocity (typically motor RPM [0-600]). The interpretation of the units + * of this velocity and whether it will be respected is implementation-dependent. + * + * @param imaxVelocity The new maximum velocity. + */ + virtual void setMaxVelocity(std::int32_t imaxVelocity) = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncVelIntegratedController.hpp b/include/okapi/api/control/async/asyncVelIntegratedController.hpp new file mode 100644 index 0000000..19d3ae1 --- /dev/null +++ b/include/okapi/api/control/async/asyncVelIntegratedController.hpp @@ -0,0 +1,124 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +/** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are whatever + * units the motor is in. + */ +class AsyncVelIntegratedController : public AsyncVelocityController { + public: + /** + * Closed-loop controller that uses the V5 motor's onboard control to move. Input units are + * whatever units the motor is in. Throws a std::invalid_argument exception if the gear ratio is + * zero. + * + * @param imotor The motor to control. + * @param ipair The gearset. + * @param imaxVelocity The maximum velocity after gearing. + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + AsyncVelIntegratedController(const std::shared_ptr &imotor, + const AbstractMotor::GearsetRatioPair &ipair, + std::int32_t imaxVelocity, + const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr motor; + AbstractMotor::GearsetRatioPair pair; + std::int32_t maxVelocity; + double lastTarget = 0; + bool controllerIsDisabled = false; + bool hasFirstTarget = false; + std::unique_ptr settledUtil; + + virtual void resumeMovement(); +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncVelPidController.hpp b/include/okapi/api/control/async/asyncVelPidController.hpp new file mode 100644 index 0000000..cd19d07 --- /dev/null +++ b/include/okapi/api/control/async/asyncVelPidController.hpp @@ -0,0 +1,64 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/control/async/asyncWrapper.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class AsyncVelPIDController : public AsyncWrapper, + public AsyncVelocityController { + public: + /** + * An async velocity PID controller. + * + * @param iinput The controller input. + * @param ioutput The controller output. + * @param itimeUtil The TimeUtil. + * @param ikP The proportional gain. + * @param ikD The derivative gain. + * @param ikF The feed-forward gain. + * @param ikSF A feed-forward gain to counteract static friction. + * @param ivelMath The VelMath used for calculating velocity. + * @param iratio Any external gear ratio. + * @param iderivativeFilter The derivative filter. + */ + AsyncVelPIDController( + const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + double iratio = 1, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + void setGains(const IterativeVelPIDController::Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + IterativeVelPIDController::Gains getGains() const; + + protected: + std::shared_ptr internalController; +}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncVelocityController.hpp b/include/okapi/api/control/async/asyncVelocityController.hpp new file mode 100644 index 0000000..1088813 --- /dev/null +++ b/include/okapi/api/control/async/asyncVelocityController.hpp @@ -0,0 +1,14 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncController.hpp" +#include + +namespace okapi { +template +class AsyncVelocityController : virtual public AsyncController {}; +} // namespace okapi diff --git a/include/okapi/api/control/async/asyncWrapper.hpp b/include/okapi/api/control/async/asyncWrapper.hpp new file mode 100644 index 0000000..d53ef45 --- /dev/null +++ b/include/okapi/api/control/async/asyncWrapper.hpp @@ -0,0 +1,287 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/api/util/supplier.hpp" +#include +#include + +namespace okapi { +template +class AsyncWrapper : virtual public AsyncController { + public: + /** + * A wrapper class that transforms an `IterativeController` into an `AsyncController` by running + * it in another task. The input controller will act like an `AsyncController`. + * + * @param iinput controller input, passed to the `IterativeController` + * @param ioutput controller output, written to from the `IterativeController` + * @param icontroller the controller to use + * @param irateSupplier used for rates used in the main loop and in `waitUntilSettled` + * @param iratio Any external gear ratio. + * @param ilogger The logger this instance will log to. + */ + AsyncWrapper(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const std::shared_ptr> &icontroller, + const Supplier> &irateSupplier, + const double iratio = 1, + std::shared_ptr ilogger = Logger::getDefaultLogger()) + : logger(std::move(ilogger)), + rateSupplier(irateSupplier), + input(iinput), + output(ioutput), + controller(icontroller), + ratio(iratio) { + } + + AsyncWrapper(AsyncWrapper &&other) = delete; + + AsyncWrapper &operator=(AsyncWrapper &&other) = delete; + + ~AsyncWrapper() override { + dtorCalled.store(true, std::memory_order_release); + delete task; + } + + /** + * Sets the target for the controller. + */ + void setTarget(const Input itarget) override { + LOG_INFO("AsyncWrapper: Set target to " + std::to_string(itarget)); + hasFirstTarget = true; + controller->setTarget(itarget * ratio); + lastTarget = itarget; + } + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. + * + * @param ivalue the controller's output + */ + void controllerSet(const Input ivalue) override { + controller->controllerSet(ivalue); + } + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + Input getTarget() override { + return controller->getTarget(); + } + + /** + * @return The most recent value of the process variable. + */ + Input getProcessValue() const override { + return controller->getProcessValue(); + } + + /** + * Returns the last calculated output of the controller. + */ + Output getOutput() const { + return controller->getOutput(); + } + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + Output getError() const override { + return controller->getError(); + } + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override { + return isDisabled() || controller->isSettled(); + } + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + void setSampleTime(const QTime &isampleTime) { + controller->setSampleTime(isampleTime); + } + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(const Output imax, const Output imin) { + controller->setOutputLimits(imax, imin); + } + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) { + controller->setControllerSetTargetLimits(itargetMax, itargetMin); + } + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + Output getMaxOutput() { + return controller->getMaxOutput(); + } + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + Output getMinOutput() { + return controller->getMinOutput(); + } + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override { + LOG_INFO_S("AsyncWrapper: Reset"); + controller->reset(); + hasFirstTarget = false; + } + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(!controller->isDisabled())); + controller->flipDisable(); + resumeMovement(); + } + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(const bool iisDisabled) override { + LOG_INFO("AsyncWrapper: flipDisable " + std::to_string(iisDisabled)); + controller->flipDisable(iisDisabled); + resumeMovement(); + } + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override { + return controller->isDisabled(); + } + + /** + * Blocks the current task until the controller has settled. Determining what settling means is + * implementation-dependent. + */ + void waitUntilSettled() override { + LOG_INFO_S("AsyncWrapper: Waiting to settle"); + + auto rate = rateSupplier.get(); + while (!isSettled()) { + rate->delayUntil(motorUpdateRate); + } + + LOG_INFO_S("AsyncWrapper: Done waiting to settle"); + } + + /** + * Starts the internal thread. This should not be called by normal users. This method is called + * by the AsyncControllerFactory when making a new instance of this class. + */ + void startThread() { + if (!task) { + task = new CrossplatformThread(trampoline, this, "AsyncWrapper"); + } + } + + /** + * Returns the underlying thread handle. + * + * @return The underlying thread handle. + */ + CrossplatformThread *getThread() const { + return task; + } + + protected: + std::shared_ptr logger; + Supplier> rateSupplier; + std::shared_ptr> input; + std::shared_ptr> output; + std::shared_ptr> controller; + bool hasFirstTarget{false}; + Input lastTarget; + double ratio; + std::atomic_bool dtorCalled{false}; + CrossplatformThread *task{nullptr}; + + static void trampoline(void *context) { + if (context) { + static_cast(context)->loop(); + } + } + + void loop() { + auto rate = rateSupplier.get(); + while (!dtorCalled.load(std::memory_order_acquire) && !task->notifyTake(0)) { + if (!isDisabled()) { + output->controllerSet(controller->step(input->controllerGet())); + } + + rate->delayUntil(controller->getSampleTime()); + } + } + + /** + * Resumes moving after the controller is reset. Should not cause movement if the controller is + * turned off, reset, and turned back on. + */ + virtual void resumeMovement() { + if (isDisabled()) { + // This will grab the output *when disabled* + output->controllerSet(controller->getOutput()); + } else { + if (hasFirstTarget) { + setTarget(lastTarget); + } + } + } +}; +} // namespace okapi diff --git a/include/okapi/api/control/closedLoopController.hpp b/include/okapi/api/control/closedLoopController.hpp new file mode 100644 index 0000000..90ce6c5 --- /dev/null +++ b/include/okapi/api/control/closedLoopController.hpp @@ -0,0 +1,86 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * An abstract closed-loop controller. + * + * @tparam Input The target/input type. + * @tparam Output The error/output type. + */ +template +class ClosedLoopController : public ControllerOutput { + public: + virtual ~ClosedLoopController() = default; + + /** + * Sets the target for the controller. + * + * @param itarget the new target + */ + virtual void setTarget(Input itarget) = 0; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + virtual Input getTarget() = 0; + + /** + * @return The most recent value of the process variable. + */ + virtual Input getProcessValue() const = 0; + + /** + * Returns the last error of the controller. Does not update when disabled. + * + * @return the last error + */ + virtual Output getError() const = 0; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return `true`. + * + * @return whether the controller is settled + */ + virtual bool isSettled() = 0; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + virtual void reset() = 0; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + virtual void flipDisable() = 0; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + virtual void flipDisable(bool iisDisabled) = 0; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + virtual bool isDisabled() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/controllerInput.hpp b/include/okapi/api/control/controllerInput.hpp new file mode 100644 index 0000000..399ed9e --- /dev/null +++ b/include/okapi/api/control/controllerInput.hpp @@ -0,0 +1,19 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +namespace okapi { +template class ControllerInput { + public: + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual T controllerGet() = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/controllerOutput.hpp b/include/okapi/api/control/controllerOutput.hpp new file mode 100644 index 0000000..f016f5e --- /dev/null +++ b/include/okapi/api/control/controllerOutput.hpp @@ -0,0 +1,19 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +namespace okapi { +template class ControllerOutput { + public: + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + virtual void controllerSet(T ivalue) = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativeController.hpp b/include/okapi/api/control/iterative/iterativeController.hpp new file mode 100644 index 0000000..6bf4a07 --- /dev/null +++ b/include/okapi/api/control/iterative/iterativeController.hpp @@ -0,0 +1,79 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/closedLoopController.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +/** + * Closed-loop controller that steps iteratively using the step method below. + * + * `ControllerOutput::controllerSet()` should set the controller's target to the input scaled by + * the output bounds. + */ +template +class IterativeController : public ClosedLoopController { + public: + /** + * Do one iteration of the controller. + * + * @param ireading A new measurement. + * @return The controller output. + */ + virtual Output step(Input ireading) = 0; + + /** + * Returns the last calculated output of the controller. + */ + virtual Output getOutput() const = 0; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + virtual void setOutputLimits(Output imax, Output imin) = 0; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by `controllerSet()` is scaled into the range `[-itargetMin, itargetMax]`. + * + * @param itargetMax The new max target for `controllerSet()`. + * @param itargetMin The new min target for `controllerSet()`. + */ + virtual void setControllerSetTargetLimits(Output itargetMax, Output itargetMin) = 0; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + virtual Output getMaxOutput() = 0; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + virtual Output getMinOutput() = 0; + + /** + * Set time between loops. + * + * @param isampleTime time between loops + */ + virtual void setSampleTime(QTime isampleTime) = 0; + + /** + * Get the last set sample time. + * + * @return sample time + */ + virtual QTime getSampleTime() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp b/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp new file mode 100644 index 0000000..05e83c9 --- /dev/null +++ b/include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp @@ -0,0 +1,150 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include + +namespace okapi { +class IterativeMotorVelocityController : public IterativeVelocityController { + public: + /** + * Velocity controller that automatically writes to the motor. + */ + IterativeMotorVelocityController( + const std::shared_ptr &imotor, + const std::shared_ptr> &icontroller); + + /** + * Do one iteration of the controller. + * + * @param inewReading new measurement + * @return controller output + */ + double step(double ireading) override; + + /** + * Sets the target for the controller. + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops in ms + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + protected: + std::shared_ptr motor; + std::shared_ptr> controller; +}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativePosPidController.hpp b/include/okapi/api/control/iterative/iterativePosPidController.hpp new file mode 100644 index 0000000..eca96fb --- /dev/null +++ b/include/okapi/api/control/iterative/iterativePosPidController.hpp @@ -0,0 +1,276 @@ +/* + * Based on the Arduino PID controller: https://github.com/br3ttb/Arduino-PID-Library + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativePositionController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class IterativePosPIDController : public IterativePositionController { + public: + struct Gains { + double kP{0}; + double kI{0}; + double kD{0}; + double kBias{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Position PID controller. + * + * @param ikP the proportional gain + * @param ikI the integration gain + * @param ikD the derivative gain + * @param ikBias the controller bias + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativePosPIDController( + double ikP, + double ikI, + double ikD, + double ikBias, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Position PID controller. + * + * @param igains the controller gains + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + */ + IterativePosPIDController( + const Gains &igains, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target position + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. Output is in the range [-1, 1] + * unless the bounds have been changed with setOutputLimits(). + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Set integrator bounds. Default bounds are [-1, 1]. + * + * @param imax max integrator value + * @param imin min integrator value + */ + virtual void setIntegralLimits(double imax, double imin); + + /** + * Set the error sum bounds. Default bounds are [0, std::numeric_limits::max()]. Error + * will only be added to the integral term when its absolute value is between these bounds of + * either side of the target. + * + * @param imax max error value that will be summed + * @param imin min error value that will be summed + */ + virtual void setErrorSumLimits(double imax, double imin); + + /** + * Set whether the integrator should be reset when error is 0 or changes sign. + * + * @param iresetOnZero true to reset + */ + virtual void setIntegratorReset(bool iresetOnZero); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + protected: + std::shared_ptr logger; + double kP, kI, kD, kBias; + QTime sampleTime{10_ms}; + double target{0}; + double lastReading{0}; + double error{0}; + double lastError{0}; + std::unique_ptr derivativeFilter; + + // Integral bounds + double integral{0}; + double integralMax{1}; + double integralMin{-1}; + + // Error will only be added to the integral term within these bounds on either side of the target + double errorSumMin{0}; + double errorSumMax{std::numeric_limits::max()}; + + double derivative{0}; + + // Output bounds + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + + // Reset the integrated when the controller crosses 0 or not + bool shouldResetOnCross{true}; + + bool controllerIsDisabled{false}; + + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativePositionController.hpp b/include/okapi/api/control/iterative/iterativePositionController.hpp new file mode 100644 index 0000000..6da33e6 --- /dev/null +++ b/include/okapi/api/control/iterative/iterativePositionController.hpp @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativePositionController : public IterativeController {}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativeVelPidController.hpp b/include/okapi/api/control/iterative/iterativeVelPidController.hpp new file mode 100644 index 0000000..910554f --- /dev/null +++ b/include/okapi/api/control/iterative/iterativeVelPidController.hpp @@ -0,0 +1,255 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativeVelocityController.hpp" +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include "okapi/api/filter/velMath.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class IterativeVelPIDController : public IterativeVelocityController { + public: + struct Gains { + double kP{0}; + double kD{0}; + double kF{0}; + double kSF{0}; + + bool operator==(const Gains &rhs) const; + bool operator!=(const Gains &rhs) const; + }; + + /** + * Velocity PD controller. + * + * @param ikP the proportional gain + * @param ikD the derivative gain + * @param ikF the feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + double ikP, + double ikD, + double ikF, + double ikSF, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param igains The controller gains. + * @param ivelMath The VelMath used for calculating velocity. + * @param itimeUtil see TimeUtil docs + * @param iderivativeFilter a filter for filtering the derivative term + * @param ilogger The logger this instance will log to. + */ + IterativeVelPIDController( + const Gains &igains, + std::unique_ptr ivelMath, + const TimeUtil &itimeUtil, + std::unique_ptr iderivativeFilter = std::make_unique(), + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + /** + * Do one iteration of the controller. Returns the reading in the range [-1, 1] unless the + * bounds have been changed with setOutputLimits(). + * + * @param inewReading new measurement + * @return controller output + */ + double step(double inewReading) override; + + /** + * Sets the target for the controller. + * + * @param itarget new target velocity + */ + void setTarget(double itarget) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() override; + + /** + * Gets the last set target, or the default target if none was set. + * + * @return the last target + */ + double getTarget() const; + + /** + * @return The most recent value of the process variable. + */ + double getProcessValue() const override; + + /** + * Returns the last calculated output of the controller. + */ + double getOutput() const override; + + /** + * Get the upper output bound. + * + * @return the upper output bound + */ + double getMaxOutput() override; + + /** + * Get the lower output bound. + * + * @return the lower output bound + */ + double getMinOutput() override; + + /** + * Returns the last error of the controller. Does not update when disabled. + */ + double getError() const override; + + /** + * Returns whether the controller has settled at the target. Determining what settling means is + * implementation-dependent. + * + * If the controller is disabled, this method must return true. + * + * @return whether the controller is settled + */ + bool isSettled() override; + + /** + * Set time between loops in ms. + * + * @param isampleTime time between loops + */ + void setSampleTime(QTime isampleTime) override; + + /** + * Set controller output bounds. Default bounds are [-1, 1]. + * + * @param imax max output + * @param imin min output + */ + void setOutputLimits(double imax, double imin) override; + + /** + * Sets the (soft) limits for the target range that controllerSet() scales into. The target + * computed by controllerSet() is scaled into the range [-itargetMin, itargetMax]. + * + * @param itargetMax The new max target for controllerSet(). + * @param itargetMin The new min target for controllerSet(). + */ + void setControllerSetTargetLimits(double itargetMax, double itargetMin) override; + + /** + * Resets the controller's internal state so it is similar to when it was first initialized, while + * keeping any user-configured information. + */ + void reset() override; + + /** + * Changes whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + */ + void flipDisable() override; + + /** + * Sets whether the controller is off or on. Turning the controller on after it was off will + * cause the controller to move to its last set target, unless it was reset in that time. + * + * @param iisDisabled whether the controller is disabled + */ + void flipDisable(bool iisDisabled) override; + + /** + * Returns whether the controller is currently disabled. + * + * @return whether the controller is currently disabled + */ + bool isDisabled() const override; + + /** + * Get the last set sample time. + * + * @return sample time + */ + QTime getSampleTime() const override; + + /** + * Do one iteration of velocity calculation. + * + * @param inewReading new measurement + * @return filtered velocity + */ + virtual QAngularSpeed stepVel(double inewReading); + + /** + * Set controller gains. + * + * @param igains The new gains. + */ + virtual void setGains(const Gains &igains); + + /** + * Gets the current gains. + * + * @return The current gains. + */ + Gains getGains() const; + + /** + * Sets the number of encoder ticks per revolution. Default is 1800. + * + * @param tpr number of measured units per revolution + */ + virtual void setTicksPerRev(double tpr); + + /** + * Returns the current velocity. + */ + virtual QAngularSpeed getVel() const; + + protected: + std::shared_ptr logger; + double kP, kD, kF, kSF; + QTime sampleTime{10_ms}; + double error{0}; + double derivative{0}; + double target{0}; + double outputSum{0}; + double output{0}; + double outputMax{1}; + double outputMin{-1}; + double controllerSetTargetMax{1}; + double controllerSetTargetMin{-1}; + bool controllerIsDisabled{false}; + + std::unique_ptr velMath; + std::unique_ptr derivativeFilter; + std::unique_ptr loopDtTimer; + std::unique_ptr settledUtil; +}; +} // namespace okapi diff --git a/include/okapi/api/control/iterative/iterativeVelocityController.hpp b/include/okapi/api/control/iterative/iterativeVelocityController.hpp new file mode 100644 index 0000000..5e78264 --- /dev/null +++ b/include/okapi/api/control/iterative/iterativeVelocityController.hpp @@ -0,0 +1,13 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativeController.hpp" + +namespace okapi { +template +class IterativeVelocityController : public IterativeController {}; +} // namespace okapi diff --git a/include/okapi/api/control/offsettableControllerInput.hpp b/include/okapi/api/control/offsettableControllerInput.hpp new file mode 100644 index 0000000..8f02201 --- /dev/null +++ b/include/okapi/api/control/offsettableControllerInput.hpp @@ -0,0 +1,41 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerInput.hpp" +#include + +namespace okapi { +class OffsetableControllerInput : public ControllerInput { + public: + /** + * A ControllerInput which can be tared to change the zero position. + * + * @param iinput The ControllerInput to reference. + */ + explicit OffsetableControllerInput(const std::shared_ptr> &iinput); + + virtual ~OffsetableControllerInput(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or PROS_ERR on a failure. + */ + double controllerGet() override; + + /** + * Sets the "absolute" zero position of this controller input to its current position. This does + * nothing if the underlying controller input returns PROS_ERR. + */ + virtual void tarePosition(); + + protected: + std::shared_ptr> input; + double offset{0}; +}; +} // namespace okapi diff --git a/include/okapi/api/control/util/controllerRunner.hpp b/include/okapi/api/control/util/controllerRunner.hpp new file mode 100644 index 0000000..29a1ebd --- /dev/null +++ b/include/okapi/api/control/util/controllerRunner.hpp @@ -0,0 +1,131 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncController.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativeController.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +template class ControllerRunner { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param itimeUtil The TimeUtil. + * @param ilogger The logger this instance will log to. + */ + explicit ControllerRunner(const TimeUtil &itimeUtil, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()) + : logger(ilogger), rate(itimeUtil.getRate()) { + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilSettled(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + while (!icontroller.isSettled()) { + ioutput.controllerSet(icontroller.getOutput()); + rate->delayUntil(10_ms); + } + + LOG_INFO("ControllerRunner: runUntilSettled(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + AsyncController &icontroller) { + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(AsyncController): Done waiting to settle"); + return icontroller.getError(); + } + + /** + * Runs the controller until it has reached its target, but not necessarily settled. + * + * @param itarget the new target + * @param icontroller the controller to run + * @param ioutput the output to write to + * @return the error when settled + */ + virtual Output runUntilAtTarget(const Input itarget, + IterativeController &icontroller, + ControllerOutput &ioutput) { + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Set target to " + + std::to_string(itarget)); + icontroller.setTarget(itarget); + + double error = icontroller.getError(); + double lastError = error; + while (error != 0 && std::copysign(1.0, error) == std::copysign(1.0, lastError)) { + ioutput.controllerSet(icontroller.getOutput()); + lastError = error; + rate->delayUntil(10_ms); + error = icontroller.getError(); + } + + LOG_INFO("ControllerRunner: runUntilAtTarget(IterativeController): Done waiting to settle"); + return icontroller.getError(); + } + + protected: + std::shared_ptr logger; + std::unique_ptr rate; +}; +} // namespace okapi diff --git a/include/okapi/api/control/util/flywheelSimulator.hpp b/include/okapi/api/control/util/flywheelSimulator.hpp new file mode 100644 index 0000000..7f82e69 --- /dev/null +++ b/include/okapi/api/control/util/flywheelSimulator.hpp @@ -0,0 +1,156 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include + +namespace okapi { +class FlywheelSimulator { + public: + /** + * A simulator for an inverted pendulum. The center of mass of the system changes as the link + * rotates (by default, you can set a new torque function with setExternalTorqueFunction()). + */ + explicit FlywheelSimulator(double imass = 0.01, + double ilinkLen = 1, + double imuStatic = 0.1, + double imuDynamic = 0.9, + double itimestep = 0.01); + + virtual ~FlywheelSimulator(); + + /** + * Step the simulation by the timestep. + * + * @return the current angle + */ + double step(); + + /** + * Step the simulation by the timestep. + * + * @param itorque new input torque + * @return the current angle + */ + double step(double itorque); + + /** + * Sets the torque function used to calculate the torque due to external forces. This torque gets + * summed with the input torque. + * + * For example, the default torque function has the torque due to gravity vary as the link swings: + * [](double angle, double mass, double linkLength) { + * return (linkLength * std::cos(angle)) * (mass * -1 * gravity); + * } + * + * @param itorqueFunc the torque function. The return value is the torque due to external forces + */ + void setExternalTorqueFunction( + std::function itorqueFunc); + + /** + * Sets the input torque. The input will be bounded by the max torque. + * + * @param itorque new input torque + */ + void setTorque(double itorque); + + /** + * Sets the max torque. The input torque cannot exceed this maximum torque. + * + * @param imaxTorque new maximum torque + */ + void setMaxTorque(double imaxTorque); + + /** + * Sets the current angle. + * + * @param iangle new angle + **/ + void setAngle(double iangle); + + /** + * Sets the mass (kg). + * + * @param imass new mass + */ + void setMass(double imass); + + /** + * Sets the link length (m). + * + * @param ilinkLen new link length + */ + void setLinkLength(double ilinkLen); + + /** + * Sets the static friction (N*m). + * + * @param imuStatic new static friction + */ + void setStaticFriction(double imuStatic); + + /** + * Sets the dynamic friction (N*m). + * + * @param imuDynamic new dynamic friction + */ + void setDynamicFriction(double imuDynamic); + + /** + * Sets the timestep (sec). + * + * @param itimestep new timestep + */ + void setTimestep(double itimestep); + + /** + * Returns the current angle (angle in rad). + * + * @return the current angle + */ + double getAngle() const; + + /** + * Returns the current omgea (angular velocity in rad / sec). + * + * @return the current omega + */ + double getOmega() const; + + /** + * Returns the current acceleration (angular acceleration in rad / sec^2). + * + * @return the current acceleration + */ + double getAcceleration() const; + + /** + * Returns the maximum torque input. + * + * @return the max torque input + */ + double getMaxTorque() const; + + protected: + double inputTorque = 0; // N*m + double maxTorque = 0.5649; // N*m + double angle = 0; // rad + double omega = 0; // rad / sec + double accel = 0; // rad / sec^2 + double mass; // kg + double linkLen; // m + double muStatic; // N*m + double muDynamic; // N*m + double timestep; // sec + double I = 0; // moment of inertia + std::function torqueFunc; + + const double minTimestep = 0.000001; // 1 us + + virtual double stepImpl(); +}; +} // namespace okapi diff --git a/include/okapi/api/control/util/pathfinderUtil.hpp b/include/okapi/api/control/util/pathfinderUtil.hpp new file mode 100644 index 0000000..c356adf --- /dev/null +++ b/include/okapi/api/control/util/pathfinderUtil.hpp @@ -0,0 +1,23 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct PathfinderPoint { + QLength x; // X coordinate relative to the start of the movement + QLength y; // Y coordinate relative to the start of the movement + QAngle theta; // Exit angle relative to the start of the movement +}; + +struct PathfinderLimits { + double maxVel; // Maximum robot velocity in m/s + double maxAccel; // Maximum robot acceleration in m/s/s + double maxJerk; // Maximum robot jerk in m/s/s/s +}; +} // namespace okapi diff --git a/include/okapi/api/control/util/pidTuner.hpp b/include/okapi/api/control/util/pidTuner.hpp new file mode 100644 index 0000000..d70c6a0 --- /dev/null +++ b/include/okapi/api/control/util/pidTuner.hpp @@ -0,0 +1,80 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include + +namespace okapi { +class PIDTuner { + public: + struct Output { + double kP, kI, kD; + }; + + PIDTuner(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + const TimeUtil &itimeUtil, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::size_t inumIterations = 5, + std::size_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~PIDTuner(); + + virtual Output autotune(); + + protected: + static constexpr double inertia = 0.5; // Particle inertia + static constexpr double confSelf = 1.1; // Self confidence + static constexpr double confSwarm = 1.2; // Particle swarm confidence + static constexpr int increment = 5; + static constexpr int divisor = 5; + static constexpr QTime loopDelta = 10_ms; // NOLINT + + struct Particle { + double pos, vel, best; + }; + + struct ParticleSet { + Particle kP, kI, kD; + double bestError; + }; + + std::shared_ptr logger; + TimeUtil timeUtil; + std::shared_ptr> input; + std::shared_ptr> output; + + const QTime timeout; + const std::int32_t goal; + const double kPMin; + const double kPMax; + const double kIMin; + const double kIMax; + const double kDMin; + const double kDMax; + const std::size_t numIterations; + const std::size_t numParticles; + const double kSettle; + const double kITAE; +}; +} // namespace okapi diff --git a/include/okapi/api/control/util/settledUtil.hpp b/include/okapi/api/control/util/settledUtil.hpp new file mode 100644 index 0000000..9b81ba2 --- /dev/null +++ b/include/okapi/api/control/util/settledUtil.hpp @@ -0,0 +1,51 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include + +namespace okapi { +class SettledUtil { + public: + /** + * A utility class to determine if a control loop has settled based on error. A control loop is + * settled if the error is within `iatTargetError` and `iatTargetDerivative` for `iatTargetTime`. + * + * @param iatTargetTimer A timer used to track `iatTargetTime`. + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + */ + explicit SettledUtil(std::unique_ptr iatTargetTimer, + double iatTargetError = 50, + double iatTargetDerivative = 5, + QTime iatTargetTime = 250_ms); + + virtual ~SettledUtil(); + + /** + * Returns whether the controller is settled. + * + * @param ierror The current error. + * @return Whether the controller is settled. + */ + virtual bool isSettled(double ierror); + + /** + * Resets the "at target" timer and clears the previous error. + */ + virtual void reset(); + + protected: + double atTargetError = 50; + double atTargetDerivative = 5; + QTime atTargetTime = 250_ms; + std::unique_ptr atTargetTimer; + double lastError = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/coreProsAPI.hpp b/include/okapi/api/coreProsAPI.hpp new file mode 100644 index 0000000..a565336 --- /dev/null +++ b/include/okapi/api/coreProsAPI.hpp @@ -0,0 +1,132 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef THREADS_STD +#include +#define CROSSPLATFORM_THREAD_T std::thread + +#include +#define CROSSPLATFORM_MUTEX_T std::mutex +#else +#include "api.h" +#include "pros/apix.h" +#define CROSSPLATFORM_THREAD_T pros::task_t +#define CROSSPLATFORM_MUTEX_T pros::Mutex +#endif + +#define NOT_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Initialization (PROS)") != 0) + +#define NOT_COMP_INITIALIZE_TASK \ + (strcmp(pros::c::task_get_name(pros::c::task_get_current()), "User Comp. Init. (PROS)") != 0) + +class CrossplatformThread { + public: +#ifdef THREADS_STD + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const = "OkapiLibCrossplatformTask") +#else + CrossplatformThread(void (*ptr)(void *), + void *params, + const char *const name = "OkapiLibCrossplatformTask") +#endif + : +#ifdef THREADS_STD + thread(ptr, params) +#else + thread( + pros::c::task_create(ptr, params, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name)) +#endif + { + } + + ~CrossplatformThread() { +#ifdef THREADS_STD + thread.join(); +#else + if (pros::c::task_get_state(thread) != pros::E_TASK_STATE_DELETED) { + pros::c::task_delete(thread); + } +#endif + } + +#ifdef THREADS_STD + void notifyWhenDeleting(CrossplatformThread *) { + } +#else + void notifyWhenDeleting(CrossplatformThread *parent) { + pros::c::task_notify_when_deleting(parent->thread, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T *) { + } +#else + void notifyWhenDeletingRaw(CROSSPLATFORM_THREAD_T parent) { + pros::c::task_notify_when_deleting(parent, thread, 1, pros::E_NOTIFY_ACTION_INCR); + } +#endif + +#ifdef THREADS_STD + std::uint32_t notifyTake(const std::uint32_t) { + return 0; + } +#else + std::uint32_t notifyTake(const std::uint32_t itimeout) { + return pros::c::task_notify_take(true, itimeout); + } +#endif + + static std::string getName() { +#ifdef THREADS_STD + std::ostringstream ss; + ss << std::this_thread::get_id(); + return ss.str(); +#else + return std::string(pros::c::task_get_name(NULL)); +#endif + } + + CROSSPLATFORM_THREAD_T thread; +}; + +class CrossplatformMutex { + public: + CrossplatformMutex() = default; + + void lock() { +#ifdef THREADS_STD + mutex.lock(); +#else + while (!mutex.take(1)) { + } +#endif + } + + void unlock() { +#ifdef THREADS_STD + mutex.unlock(); +#else + mutex.give(); +#endif + } + + protected: + CROSSPLATFORM_MUTEX_T mutex; +}; diff --git a/include/okapi/api/device/button/abstractButton.hpp b/include/okapi/api/device/button/abstractButton.hpp new file mode 100644 index 0000000..4e75f2e --- /dev/null +++ b/include/okapi/api/device/button/abstractButton.hpp @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerInput.hpp" + +namespace okapi { +class AbstractButton : public ControllerInput { + public: + virtual ~AbstractButton(); + + /** + * Return whether the button is currently pressed. + **/ + virtual bool isPressed() = 0; + + /** + * Return whether the state of the button changed since the last time this method was + * called. + **/ + virtual bool changed() = 0; + + /** + * Return whether the state of the button changed to being pressed since the last time this method + * was called. + **/ + virtual bool changedToPressed() = 0; + + /** + * Return whether the state of the button to being not pressed changed since the last time this + * method was called. + **/ + virtual bool changedToReleased() = 0; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value. This is the same as the output of the pressed() method. + */ + virtual bool controllerGet() override; +}; +} // namespace okapi diff --git a/include/okapi/api/device/button/buttonBase.hpp b/include/okapi/api/device/button/buttonBase.hpp new file mode 100644 index 0000000..54f1ccd --- /dev/null +++ b/include/okapi/api/device/button/buttonBase.hpp @@ -0,0 +1,52 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/device/button/abstractButton.hpp" + +namespace okapi { +class ButtonBase : public AbstractButton { + public: + /** + * @param iinverted Whether the button is inverted (`true` meaning default pressed and `false` + * meaning default not pressed). + */ + explicit ButtonBase(bool iinverted = false); + + /** + * Return whether the button is currently pressed. + **/ + bool isPressed() override; + + /** + * Return whether the state of the button changed since the last time this method was called. + **/ + bool changed() override; + + /** + * Return whether the state of the button changed to pressed since the last time this method was + *called. + **/ + bool changedToPressed() override; + + /** + * Return whether the state of the button to not pressed since the last time this method was + *called. + **/ + bool changedToReleased() override; + + protected: + bool inverted{false}; + bool wasPressedLast_c{false}; + bool wasPressedLast_ctp{false}; + bool wasPressedLast_ctr{false}; + + virtual bool currentlyPressed() = 0; + + private: + bool changedImpl(bool &prevState); +}; +} // namespace okapi diff --git a/include/okapi/api/device/motor/abstractMotor.hpp b/include/okapi/api/device/motor/abstractMotor.hpp new file mode 100644 index 0000000..ff46fe0 --- /dev/null +++ b/include/okapi/api/device/motor/abstractMotor.hpp @@ -0,0 +1,537 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include + +namespace okapi { +class AbstractMotor : public ControllerOutput { + public: + /** + * Indicates the 'brake mode' of a motor. + */ + enum class brakeMode { + coast = 0, ///< Motor coasts when stopped, traditional behavior + brake = 1, ///< Motor brakes when stopped + hold = 2, ///< Motor actively holds position when stopped + invalid = INT32_MAX + }; + + /** + * Indicates the units used by the motor encoders. + */ + enum class encoderUnits { + degrees = 0, ///< degrees + rotations = 1, ///< rotations + counts = 2, ///< counts + invalid = INT32_MAX ///< invalid + }; + + /** + * Indicates the internal gear ratio of a motor. + */ + enum class gearset { + red = 100, ///< 36:1, 100 RPM, Red gear set + green = 200, ///< 18:1, 200 RPM, Green gear set + blue = 600, ///< 6:1, 600 RPM, Blue gear set + invalid = INT32_MAX + }; + + /** + * A simple structure representing the full ratio between motor and wheel. + */ + struct GearsetRatioPair { + /** + * A simple structure representing the full ratio between motor and wheel. + * + * The ratio is `motor rotation : wheel rotation`, e.x., if one motor rotation + * corresponds to two wheel rotations, the ratio is `1.0/2.0`. + * + * @param igearset The gearset in the motor. + * @param iratio The ratio of motor rotation to wheel rotation. + */ + GearsetRatioPair(const gearset igearset, const double iratio = 1) + : internalGearset(igearset), ratio(iratio) { + } + + ~GearsetRatioPair() = default; + + gearset internalGearset; + double ratio = 1; + }; + + virtual ~AbstractMotor(); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, no matter what the current + * position is. + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveRelative(double iposition, std::int32_t ivelocity) = 0; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVelocity(std::int16_t ivelocity) = 0; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivoltage The new voltage value from -12000 to 12000 + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t moveVoltage(std::int16_t ivoltage) = 0; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) = 0; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTargetPosition() = 0; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double getPosition() = 0; + + /** + * Gets the positional error (target position minus actual position) of the motor in its encoder + * units. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's positional error in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPositionError(); + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t tarePosition() = 0; + + /** + * Gets the velocity commanded to the motor by the user. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t getTargetVelocity() = 0; + + /** + * Gets the actual velocity of the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual double getActualVelocity() = 0; + + /** + * Gets the difference between the target velocity of the motor and the actual velocity of the + * motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's velocity error in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getVelocityError(); + + /** + * Gets the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentDraw() = 0; + + /** + * Gets the direction of movement for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getDirection() = 0; + + /** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getEfficiency() = 0; + + /** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the motor's current limit is being exceeded and 0 if the current limit is not + * exceeded, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t isOverCurrent() = 0; + + /** + * Checks if the motor's temperature is above its limit. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t isOverTemp() = 0; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + virtual std::int32_t isStopped() = 0; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + virtual std::int32_t getZeroPositionFlag() = 0; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + virtual uint32_t getFaults() = 0; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + virtual uint32_t getFlags() = 0; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param timestamp A pointer to a time in milliseconds for which the encoder count will be + * returned. If NULL, the timestamp at which the encoder count was read will not be supplied + * + * @return The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + virtual std::int32_t getRawPosition(std::uint32_t *timestamp) = 0; + + /** + * Gets the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getPower() = 0; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double getTemperature() = 0; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + virtual double getTorque() = 0; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + virtual std::int32_t getVoltage() = 0; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setBrakeMode(brakeMode imode) = 0; + + /** + * Gets the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + virtual brakeMode getBrakeMode() = 0; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setCurrentLimit(std::int32_t ilimit) = 0; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t getCurrentLimit() = 0; + + /** + * Sets one of encoderUnits for the motor encoder. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setEncoderUnits(encoderUnits iunits) = 0; + + /** + * Gets the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + virtual encoderUnits getEncoderUnits() = 0; + + /** + * Sets one of gearset for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setGearing(gearset igearset) = 0; + + /** + * Gets the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + virtual gearset getGearing() = 0; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setReversed(bool ireverse) = 0; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVoltageLimit(std::int32_t ilimit) = 0; + + /** + * Returns the encoder associated with this motor. + * + * @return the encoder for this motor + */ + virtual std::shared_ptr getEncoder() = 0; +}; + +AbstractMotor::GearsetRatioPair operator*(AbstractMotor::gearset gearset, double ratio); + +} // namespace okapi diff --git a/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp b/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp new file mode 100644 index 0000000..4de4cc5 --- /dev/null +++ b/include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp @@ -0,0 +1,20 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class ContinuousRotarySensor : public RotarySensor { + public: + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/device/rotarysensor/rotarySensor.hpp b/include/okapi/api/device/rotarysensor/rotarySensor.hpp new file mode 100644 index 0000000..9b010a4 --- /dev/null +++ b/include/okapi/api/device/rotarysensor/rotarySensor.hpp @@ -0,0 +1,23 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/coreProsAPI.hpp" + +namespace okapi { +class RotarySensor : public ControllerInput { + public: + virtual ~RotarySensor(); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/averageFilter.hpp b/include/okapi/api/filter/averageFilter.hpp new file mode 100644 index 0000000..c2babd0 --- /dev/null +++ b/include/okapi/api/filter/averageFilter.hpp @@ -0,0 +1,59 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" +#include +#include + +namespace okapi { +/** + * A filter which returns the average of a list of values. + * + * @tparam n number of taps in the filter + */ +template class AverageFilter : public Filter { + public: + /** + * Averaging filter. + */ + AverageFilter() = default; + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = 0.0; + for (size_t i = 0; i < n; i++) + output += data[i]; + output /= (double)n; + + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/composableFilter.hpp b/include/okapi/api/filter/composableFilter.hpp new file mode 100644 index 0000000..be494e9 --- /dev/null +++ b/include/okapi/api/filter/composableFilter.hpp @@ -0,0 +1,50 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include +#include + +namespace okapi { +class ComposableFilter : public Filter { + public: + /** + * A composable filter is a filter that consists of other filters. The input signal is passed + * through each filter in sequence. The final output of this filter is the output of the last + * filter. + * + * @param ilist The filters to use in sequence. + */ + ComposableFilter(const std::initializer_list> &ilist); + + /** + * Filters a value. + * + * @param ireading A new measurement. + * @return The filtered result. + */ + double filter(double ireading) override; + + /** + * @return The previous output from filter. + */ + double getOutput() const override; + + /** + * Adds a filter to the end of the sequence. + * + * @param ifilter The filter to add. + */ + virtual void addFilter(std::shared_ptr ifilter); + + protected: + std::vector> filters; + double output = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/demaFilter.hpp b/include/okapi/api/filter/demaFilter.hpp new file mode 100644 index 0000000..c3f4ef3 --- /dev/null +++ b/include/okapi/api/filter/demaFilter.hpp @@ -0,0 +1,52 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +class DemaFilter : public Filter { + public: + /** + * Double exponential moving average filter. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + DemaFilter(double ialpha, double ibeta); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + * @param ibeta beta gain + */ + virtual void setGains(double ialpha, double ibeta); + + protected: + double alpha, beta; + double outputS = 0; + double lastOutputS = 0; + double outputB = 0; + double lastOutputB = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/ekfFilter.hpp b/include/okapi/api/filter/ekfFilter.hpp new file mode 100644 index 0000000..731ad85 --- /dev/null +++ b/include/okapi/api/filter/ekfFilter.hpp @@ -0,0 +1,71 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" +#include "okapi/api/util/mathUtil.hpp" + +namespace okapi { +class EKFFilter : public Filter { + public: + /** + * One dimensional extended Kalman filter. The default arguments should work fine for most signal + * filtering. It won't hurt to graph your signal and the filtered result, and check if the filter + * is doing its job. + * + * Q is the covariance of the process noise and R is the + * covariance of the observation noise. The default values for Q and R should be a modest balance + * between trust in the sensor and FIR filtering. + * + * Think of R as how noisy your sensor is. Its value can be found mathematically by computing the + * standard deviation of your sensor reading vs. "truth" (of course, "truth" is still an estimate; + * try to calibrate your robot in a controlled setting where you can minimize the error in what + * "truth" is). + * + * Think of Q as how noisy your model is. It decides how much "smoothing" the filter does and how + * far it lags behind the true signal. This parameter is most often used as a "tuning" parameter + * to adjust the response of the filter. + * + * @param iQ process noise covariance + * @param iR measurement noise covariance + */ + explicit EKFFilter(double iQ = 0.0001, double iR = ipow(0.2, 2)); + + /** + * Filters a value, like a sensor reading. Assumes the control input is zero. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Filters a reading with a control input. + * + * @param ireading new measurement + * @param icontrol control input + * @return filtered result + */ + virtual double filter(double ireading, double icontrol); + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + const double Q, R; + double xHat = 0; + double xHatPrev = 0; + double xHatMinus = 0; + double P = 0; + double Pprev = 1; + double Pminus = 0; + double K = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/emaFilter.hpp b/include/okapi/api/filter/emaFilter.hpp new file mode 100644 index 0000000..f41611c --- /dev/null +++ b/include/okapi/api/filter/emaFilter.hpp @@ -0,0 +1,47 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class EmaFilter : public Filter { + public: + /** + * Exponential moving average filter. + * + * @param ialpha alpha gain + */ + explicit EmaFilter(double ialpha); + + /** + * Filters a value, like a sensor reading. + * + * @param reading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + /** + * Set filter gains. + * + * @param ialpha alpha gain + */ + virtual void setGains(double ialpha); + + protected: + double alpha; + double output = 0; + double lastOutput = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/filter.hpp b/include/okapi/api/filter/filter.hpp new file mode 100644 index 0000000..24ca2cf --- /dev/null +++ b/include/okapi/api/filter/filter.hpp @@ -0,0 +1,28 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +namespace okapi { +class Filter { + public: + virtual ~Filter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + virtual double filter(double ireading) = 0; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + virtual double getOutput() const = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/filteredControllerInput.hpp b/include/okapi/api/filter/filteredControllerInput.hpp new file mode 100644 index 0000000..9257fe6 --- /dev/null +++ b/include/okapi/api/filter/filteredControllerInput.hpp @@ -0,0 +1,48 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/filter.hpp" +#include + +namespace okapi { +/** + * A ControllerInput with a filter built in. + * + * @tparam InputType the type of the ControllerInput + * @tparam FilterType the type of the Filter + */ +template +class FilteredControllerInput : public ControllerInput { + public: + /** + * A filtered controller input. Applies a filter to the controller input. Useful if you want to + * place a filter between a control input and a control loop. + * + * @param iinput ControllerInput type + * @param ifilter Filter type + */ + FilteredControllerInput(std::unique_ptr> iinput, + std::unique_ptr ifilter) + : input(std::move(iinput)), filter(std::move(ifilter)) { + } + + /** + * Gets the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current filtered sensor value. + */ + double controllerGet() override { + return filter->filter(input->controllerGet()); + } + + protected: + std::unique_ptr> input; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/medianFilter.hpp b/include/okapi/api/filter/medianFilter.hpp new file mode 100644 index 0000000..2879211 --- /dev/null +++ b/include/okapi/api/filter/medianFilter.hpp @@ -0,0 +1,94 @@ +/* + * Uses the median filter algorithm from N. Wirth’s book, implementation by N. Devillard. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" +#include +#include +#include + +namespace okapi { +/** + * A filter which returns the median value of list of values. + * + * @tparam n number of taps in the filter + */ +template class MedianFilter : public Filter { + public: + MedianFilter() : middleIndex((((n)&1) ? ((n) / 2) : (((n) / 2) - 1))) { + } + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(const double ireading) override { + data[index++] = ireading; + if (index >= n) { + index = 0; + } + + output = kth_smallset(); + return output; + } + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override { + return output; + } + + protected: + std::array data{0}; + std::size_t index = 0; + double output = 0; + const size_t middleIndex; + + /** + * Algorithm from N. Wirth’s book, implementation by N. Devillard. + */ + double kth_smallset() { + std::array dataCopy = data; + size_t j, l, m; + l = 0; + m = n - 1; + + while (l < m) { + double x = dataCopy[middleIndex]; + size_t i = l; + j = m; + do { + while (dataCopy[i] < x) { + i++; + } + while (x < dataCopy[j]) { + j--; + } + if (i <= j) { + const double t = dataCopy[i]; + dataCopy[i] = dataCopy[j]; + dataCopy[j] = t; + i++; + j--; + } + } while (i <= j); + if (j < middleIndex) + l = i; + if (middleIndex < i) + m = j; + } + + return dataCopy[middleIndex]; + } +}; +} // namespace okapi diff --git a/include/okapi/api/filter/passthroughFilter.hpp b/include/okapi/api/filter/passthroughFilter.hpp new file mode 100644 index 0000000..543fa31 --- /dev/null +++ b/include/okapi/api/filter/passthroughFilter.hpp @@ -0,0 +1,36 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/filter.hpp" + +namespace okapi { +class PassthroughFilter : public Filter { + public: + /** + * A simple filter that does no filtering and just passes the input through. + */ + PassthroughFilter(); + + /** + * Filters a value, like a sensor reading. + * + * @param ireading new measurement + * @return filtered result + */ + double filter(double ireading) override; + + /** + * Returns the previous output from filter. + * + * @return the previous output from filter + */ + double getOutput() const override; + + protected: + double lastOutput = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/filter/velMath.hpp b/include/okapi/api/filter/velMath.hpp new file mode 100644 index 0000000..a02dd8f --- /dev/null +++ b/include/okapi/api/filter/velMath.hpp @@ -0,0 +1,74 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/composableFilter.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class VelMath { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a `std::invalid_argument` exception + * if `iticksPerRev` is zero. + * + * @param iticksPerRev The number of ticks per revolution (or whatever units you are using). + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between velocity measurements. + * @param ilogger The logger this instance will log to. + */ + VelMath(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime, + std::unique_ptr iloopDtTimer, + std::shared_ptr ilogger = Logger::getDefaultLogger()); + + virtual ~VelMath(); + + /** + * Calculates the current velocity and acceleration. Returns the (filtered) velocity. + * + * @param inewPos The new position measurement. + * @return The new velocity estimate. + */ + virtual QAngularSpeed step(double inewPos); + + /** + * Sets ticks per revolution (or whatever units you are using). Throws a `std::invalid_argument` + * exception if iticksPerRev is zero. + * + * @param iTPR The number of ticks per revolution. + */ + virtual void setTicksPerRev(double iTPR); + + /** + * @return The last calculated velocity. + */ + virtual QAngularSpeed getVelocity() const; + + /** + * @return The last calculated acceleration. + */ + virtual QAngularAcceleration getAccel() const; + + protected: + std::shared_ptr logger; + QAngularSpeed vel{0_rpm}; + QAngularSpeed lastVel{0_rpm}; + QAngularAcceleration accel{0.0}; + double lastPos{0}; + double ticksPerRev; + + QTime sampleTime; + std::unique_ptr loopDtTimer; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/odomMath.hpp b/include/okapi/api/odometry/odomMath.hpp new file mode 100644 index 0000000..f32c2cd --- /dev/null +++ b/include/okapi/api/odometry/odomMath.hpp @@ -0,0 +1,95 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/point.hpp" +#include "okapi/api/util/logging.hpp" +#include + +namespace okapi { +class OdomMath { + public: + /** + * Computes the distance from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance between the Odometry state and the point. + */ + static QLength computeDistanceToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the angle from the given Odometry state to the given point. The point and the + * OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The angle between the Odometry state and the point. + */ + static QAngle computeAngleToPoint(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance and angle from the given Odometry state to the given point. The point and + * the OdomState must be in `StateMode::FRAME_TRANSFORMATION`. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The distance and angle between the Odometry state and the point. + */ + static std::pair computeDistanceAndAngleToPoint(const Point &ipoint, + const OdomState &istate); + + /** + * Constraints the angle to [0,360] degrees. + * + * @param angle The input angle. + * @return The angle normalized to [0,360] degrees. + */ + static QAngle constrainAngle360(const QAngle &angle); + + /** + * Constraints the angle to [-180,180) degrees. + * + * @param angle The input angle. + * @return The angle normalized to [-180,180) degrees. + */ + static QAngle constrainAngle180(const QAngle &angle); + + private: + OdomMath(); + ~OdomMath(); + + /** + * Computes the x and y diffs in meters between the points. + * + * @param ipoint The point. + * @param istate The Odometry state. + * @return The diffs in the order `{xDiff, yDiff}`. + */ + static std::pair computeDiffs(const Point &ipoint, const OdomState &istate); + + /** + * Computes the distance between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @return The cartesian distance in meters. + */ + static double computeDistance(double xDiff, double yDiff); + + /** + * Compites the angle between the points. + * + * @param xDiff The x-axis diff in meters. + * @param yDiff The y-axis diff in meters. + * @param theta The current robot's theta in radians. + * @return The angle in radians. + */ + static double computeAngle(double xDiff, double yDiff, double theta); +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/odomState.hpp b/include/okapi/api/odometry/odomState.hpp new file mode 100644 index 0000000..842707c --- /dev/null +++ b/include/okapi/api/odometry/odomState.hpp @@ -0,0 +1,57 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantityName.hpp" +#include + +namespace okapi { +struct OdomState { + QLength x{0_m}; + QLength y{0_m}; + QAngle theta{0_deg}; + + /** + * Get a string for the current odometry state (optionally with the specified units). + * + * Examples: + * - `OdomState::str(1_m, 1_deg)`: The default (no arguments specified). + * - `OdomState::str(1_tile, 1_radian)`: distance tiles and angle radians. + * + * Throws std::domain_error if the units passed are undefined. + * + * @param idistanceUnit The units you want your distance to be in. This must be an exact, predefined QLength (such as foot, meter, inch, tile etc.). + * @param iangleUnit The units you want your angle to be in. This must be an exact, predefined QAngle (degree or radian). + * @return A string representing the state. + */ + std::string str(QLength idistanceUnit, QAngle iangleUnit) const; + + /** + * Get a string for the current odometry state (optionally with the specified units). + * + * Examples: + * - `OdomState::str(1_m, "_m", 1_deg, "_deg")`: The default (no arguments specified), prints in meters and degrees. + * - `OdomState::str(1_in, "_in", 1_deg, "_deg")` or `OdomState::str(1_in, "\"", 1_deg, "°")`: to print values in inches and degrees with different suffixes. + * - `OdomState::str(6_tile / 100, "%", 360_deg / 100, "%")` to get the distance values in % of the vex field, and angle values in % of a full rotation. + * + * @param idistanceUnit The units you want your distance to be in. The x or y position will be output in multiples of this length. + * @param distUnitName The suffix you as your distance unit. + * @param iangleUnit The units you want your angle to be in. The angle will be output in multiples of this unit. + * @param angleUnitName The suffix you want as your angle unit. + * @return A string representing the state. + */ + std::string str(QLength idistanceUnit = meter, + std::string distUnitName = "_m", + QAngle iangleUnit = degree, + std::string angleUnitName = "_deg") const; + + bool operator==(const OdomState &rhs) const; + + bool operator!=(const OdomState &rhs) const; +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/odometry.hpp b/include/okapi/api/odometry/odometry.hpp new file mode 100644 index 0000000..823cf3c --- /dev/null +++ b/include/okapi/api/odometry/odometry.hpp @@ -0,0 +1,61 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include "okapi/api/chassis/model/readOnlyChassisModel.hpp" +#include "okapi/api/odometry/odomState.hpp" +#include "okapi/api/odometry/stateMode.hpp" + +namespace okapi { +class Odometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + */ + explicit Odometry() = default; + + virtual ~Odometry() = default; + + /** + * Sets the drive and turn scales. + */ + virtual void setScales(const ChassisScales &ichassisScales) = 0; + + /** + * Do one odometry step. + */ + virtual void step() = 0; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + virtual OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const = 0; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + virtual void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) = 0; + + /** + * @return The internal ChassisModel. + */ + virtual std::shared_ptr getModel() = 0; + + /** + * @return The internal ChassisScales. + */ + virtual ChassisScales getScales() = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/point.hpp b/include/okapi/api/odometry/point.hpp new file mode 100644 index 0000000..c55266b --- /dev/null +++ b/include/okapi/api/odometry/point.hpp @@ -0,0 +1,30 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/odometry/stateMode.hpp" +#include "okapi/api/units/QLength.hpp" + +namespace okapi { +struct Point { + QLength x{0_m}; + QLength y{0_m}; + + /** + * Computes the value of this point in `StateMode::FRAME_TRANSFORMATION`. + * + * @param imode The StateMode this Point is currently specified in. + * @return This point specified in `StateMode::FRAME_TRANSFORMATION`. + */ + Point inFT(const StateMode &imode) const { + if (imode == StateMode::FRAME_TRANSFORMATION) { + return *this; + } else { + return {y, x}; + } + } +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/stateMode.hpp b/include/okapi/api/odometry/stateMode.hpp new file mode 100644 index 0000000..da2b6bc --- /dev/null +++ b/include/okapi/api/odometry/stateMode.hpp @@ -0,0 +1,17 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +namespace okapi { +/** + * The mode for the OdomState calculated by Odometry. + */ +enum class StateMode { + FRAME_TRANSFORMATION, ///< +x is forward, +y is right, 0 degrees is along +x + CARTESIAN ///< +x is right, +y is forward, 0 degrees is along +y +}; + +} // namespace okapi diff --git a/include/okapi/api/odometry/threeEncoderOdometry.hpp b/include/okapi/api/odometry/threeEncoderOdometry.hpp new file mode 100644 index 0000000..d4a0401 --- /dev/null +++ b/include/okapi/api/odometry/threeEncoderOdometry.hpp @@ -0,0 +1,43 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp" +#include "okapi/api/odometry/twoEncoderOdometry.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include + +namespace okapi { +class ThreeEncoderOdometry : public TwoEncoderOdometry { + public: + /** + * Odometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales See ChassisScales docs (the middle wheel scale is the third member) + * @param iwheelVelDelta The maximum delta between wheel velocities to consider the robot as + * driving straight. + * @param ilogger The logger this instance will log to. + */ + ThreeEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + protected: + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT) override; +}; +} // namespace okapi diff --git a/include/okapi/api/odometry/twoEncoderOdometry.hpp b/include/okapi/api/odometry/twoEncoderOdometry.hpp new file mode 100644 index 0000000..c733d45 --- /dev/null +++ b/include/okapi/api/odometry/twoEncoderOdometry.hpp @@ -0,0 +1,93 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/odometry/odometry.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include +#include +#include + +namespace okapi { +class TwoEncoderOdometry : public Odometry { + public: + /** + * TwoEncoderOdometry. Tracks the movement of the robot and estimates its position in coordinates + * relative to the start (assumed to be (0, 0, 0)). + * + * @param itimeUtil The TimeUtil. + * @param imodel The chassis model for reading sensors. + * @param ichassisScales The chassis dimensions. + * @param ilogger The logger this instance will log to. + */ + TwoEncoderOdometry(const TimeUtil &itimeUtil, + const std::shared_ptr &imodel, + const ChassisScales &ichassisScales, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + virtual ~TwoEncoderOdometry() = default; + + /** + * Sets the drive and turn scales. + */ + void setScales(const ChassisScales &ichassisScales) override; + + /** + * Do one odometry step. + */ + void step() override; + + /** + * Returns the current state. + * + * @param imode The mode to return the state in. + * @return The current state in the given format. + */ + OdomState getState(const StateMode &imode = StateMode::FRAME_TRANSFORMATION) const override; + + /** + * Sets a new state to be the current state. + * + * @param istate The new state in the given format. + * @param imode The mode to treat the input state as. + */ + void setState(const OdomState &istate, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION) override; + + /** + * @return The internal ChassisModel. + */ + std::shared_ptr getModel() override; + + /** + * @return The internal ChassisScales. + */ + ChassisScales getScales() override; + + protected: + std::shared_ptr logger; + std::unique_ptr rate; + std::unique_ptr timer; + std::shared_ptr model; + ChassisScales chassisScales; + OdomState state; + std::valarray newTicks{0, 0, 0}, tickDiff{0, 0, 0}, lastTicks{0, 0, 0}; + const std::int32_t maximumTickDiff{1000}; + + /** + * Does the math, side-effect free, for one odom step. + * + * @param itickDiff The tick difference from the previous step to this step. + * @param ideltaT The time difference from the previous step to this step. + * @return The newly computed OdomState. + */ + virtual OdomState odomMathStep(const std::valarray &itickDiff, + const QTime &ideltaT); +}; +} // namespace okapi diff --git a/include/okapi/api/units/QAcceleration.hpp b/include/okapi/api/units/QAcceleration.hpp new file mode 100644 index 0000000..50f7193 --- /dev/null +++ b/include/okapi/api/units/QAcceleration.hpp @@ -0,0 +1,36 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -2, 0, QAcceleration) + +constexpr QAcceleration mps2 = meter / (second * second); +constexpr QAcceleration G = 9.80665 * mps2; + +inline namespace literals { +constexpr QAcceleration operator"" _mps2(long double x) { + return QAcceleration(x); +} +constexpr QAcceleration operator"" _mps2(unsigned long long int x) { + return QAcceleration(static_cast(x)); +} +constexpr QAcceleration operator"" _G(long double x) { + return static_cast(x) * G; +} +constexpr QAcceleration operator"" _G(unsigned long long int x) { + return static_cast(x) * G; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QAngle.hpp b/include/okapi/api/units/QAngle.hpp new file mode 100644 index 0000000..2e80b4d --- /dev/null +++ b/include/okapi/api/units/QAngle.hpp @@ -0,0 +1,35 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" +#include + +namespace okapi { +QUANTITY_TYPE(0, 0, 0, 1, QAngle) + +constexpr QAngle radian(1.0); +constexpr QAngle degree = static_cast(2_pi / 360.0) * radian; + +inline namespace literals { +constexpr QAngle operator"" _rad(long double x) { + return QAngle(x); +} +constexpr QAngle operator"" _rad(unsigned long long int x) { + return QAngle(static_cast(x)); +} +constexpr QAngle operator"" _deg(long double x) { + return static_cast(x) * degree; +} +constexpr QAngle operator"" _deg(unsigned long long int x) { + return static_cast(x) * degree; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QAngularAcceleration.hpp b/include/okapi/api/units/QAngularAcceleration.hpp new file mode 100644 index 0000000..487acbf --- /dev/null +++ b/include/okapi/api/units/QAngularAcceleration.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -2, 1, QAngularAcceleration) +} diff --git a/include/okapi/api/units/QAngularJerk.hpp b/include/okapi/api/units/QAngularJerk.hpp new file mode 100644 index 0000000..c3fd6c7 --- /dev/null +++ b/include/okapi/api/units/QAngularJerk.hpp @@ -0,0 +1,16 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -3, 1, QAngularJerk) +} diff --git a/include/okapi/api/units/QAngularSpeed.hpp b/include/okapi/api/units/QAngularSpeed.hpp new file mode 100644 index 0000000..30b8052 --- /dev/null +++ b/include/okapi/api/units/QAngularSpeed.hpp @@ -0,0 +1,39 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 1, QAngularSpeed) + +constexpr QAngularSpeed radps = radian / second; +constexpr QAngularSpeed rpm = (360 * degree) / minute; +constexpr QAngularSpeed cps = (0.01 * degree) / second; // centidegree per second + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static QAngularSpeed convertHertzToRadPerSec(QFrequency in) { + return (in.convert(Hz) / 2_pi) * radps; +} +#pragma GCC diagnostic pop + +inline namespace literals { +constexpr QAngularSpeed operator"" _rpm(long double x) { + return x * rpm; +} +constexpr QAngularSpeed operator"" _rpm(unsigned long long int x) { + return static_cast(x) * rpm; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QArea.hpp b/include/okapi/api/units/QArea.hpp new file mode 100644 index 0000000..ed48722 --- /dev/null +++ b/include/okapi/api/units/QArea.hpp @@ -0,0 +1,26 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 2, 0, 0, QArea) + +constexpr QArea kilometer2 = kilometer * kilometer; +constexpr QArea meter2 = meter * meter; +constexpr QArea decimeter2 = decimeter * decimeter; +constexpr QArea centimeter2 = centimeter * centimeter; +constexpr QArea millimeter2 = millimeter * millimeter; +constexpr QArea inch2 = inch * inch; +constexpr QArea foot2 = foot * foot; +constexpr QArea mile2 = mile * mile; +} // namespace okapi diff --git a/include/okapi/api/units/QForce.hpp b/include/okapi/api/units/QForce.hpp new file mode 100644 index 0000000..8439fb7 --- /dev/null +++ b/include/okapi/api/units/QForce.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 1, -2, 0, QForce) + +constexpr QForce newton = (kg * meter) / (second * second); +constexpr QForce poundforce = pound * G; +constexpr QForce kilopond = kg * G; + +inline namespace literals { +constexpr QForce operator"" _n(long double x) { + return QForce(x); +} +constexpr QForce operator"" _n(unsigned long long int x) { + return QForce(static_cast(x)); +} +constexpr QForce operator"" _lbf(long double x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _lbf(unsigned long long int x) { + return static_cast(x) * poundforce; +} +constexpr QForce operator"" _kp(long double x) { + return static_cast(x) * kilopond; +} +constexpr QForce operator"" _kp(unsigned long long int x) { + return static_cast(x) * kilopond; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QFrequency.hpp b/include/okapi/api/units/QFrequency.hpp new file mode 100644 index 0000000..9cd2991 --- /dev/null +++ b/include/okapi/api/units/QFrequency.hpp @@ -0,0 +1,27 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, -1, 0, QFrequency) + +constexpr QFrequency Hz(1.0); + +inline namespace literals { +constexpr QFrequency operator"" _Hz(long double x) { + return QFrequency(x); +} +constexpr QFrequency operator"" _Hz(unsigned long long int x) { + return QFrequency(static_cast(x)); +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QJerk.hpp b/include/okapi/api/units/QJerk.hpp new file mode 100644 index 0000000..709df1e --- /dev/null +++ b/include/okapi/api/units/QJerk.hpp @@ -0,0 +1,18 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -3, 0, QJerk) +} diff --git a/include/okapi/api/units/QLength.hpp b/include/okapi/api/units/QLength.hpp new file mode 100644 index 0000000..c102fcb --- /dev/null +++ b/include/okapi/api/units/QLength.hpp @@ -0,0 +1,84 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, 0, 0, QLength) + +constexpr QLength meter(1.0); // SI base unit +constexpr QLength decimeter = meter / 10; +constexpr QLength centimeter = meter / 100; +constexpr QLength millimeter = meter / 1000; +constexpr QLength kilometer = 1000 * meter; +constexpr QLength inch = 2.54 * centimeter; +constexpr QLength foot = 12 * inch; +constexpr QLength yard = 3 * foot; +constexpr QLength mile = 5280 * foot; +constexpr QLength tile = 24 * inch; + +inline namespace literals { +constexpr QLength operator"" _mm(long double x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(long double x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(long double x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(long double x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(long double x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(long double x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(long double x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(long double x) { + return static_cast(x) * inch; +} +constexpr QLength operator"" _tile(long double x) { + return static_cast(x) * tile; +} +constexpr QLength operator"" _mm(unsigned long long int x) { + return static_cast(x) * millimeter; +} +constexpr QLength operator"" _cm(unsigned long long int x) { + return static_cast(x) * centimeter; +} +constexpr QLength operator"" _m(unsigned long long int x) { + return static_cast(x) * meter; +} +constexpr QLength operator"" _km(unsigned long long int x) { + return static_cast(x) * kilometer; +} +constexpr QLength operator"" _mi(unsigned long long int x) { + return static_cast(x) * mile; +} +constexpr QLength operator"" _yd(unsigned long long int x) { + return static_cast(x) * yard; +} +constexpr QLength operator"" _ft(unsigned long long int x) { + return static_cast(x) * foot; +} +constexpr QLength operator"" _in(unsigned long long int x) { + return static_cast(x) * inch; +} +constexpr QLength operator"" _tile(unsigned long long int x) { + return static_cast(x) * tile; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QMass.hpp b/include/okapi/api/units/QMass.hpp new file mode 100644 index 0000000..0501cbd --- /dev/null +++ b/include/okapi/api/units/QMass.hpp @@ -0,0 +1,62 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 0, 0, 0, QMass) + +constexpr QMass kg(1.0); // SI base unit +constexpr QMass gramme = 0.001 * kg; +constexpr QMass tonne = 1000 * kg; +constexpr QMass ounce = 0.028349523125 * kg; +constexpr QMass pound = 16 * ounce; +constexpr QMass stone = 14 * pound; + +inline namespace literals { +constexpr QMass operator"" _kg(long double x) { + return QMass(x); +} +constexpr QMass operator"" _g(long double x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(long double x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(long double x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(long double x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(long double x) { + return static_cast(x) * stone; +} +constexpr QMass operator"" _kg(unsigned long long int x) { + return QMass(static_cast(x)); +} +constexpr QMass operator"" _g(unsigned long long int x) { + return static_cast(x) * gramme; +} +constexpr QMass operator"" _t(unsigned long long int x) { + return static_cast(x) * tonne; +} +constexpr QMass operator"" _oz(unsigned long long int x) { + return static_cast(x) * ounce; +} +constexpr QMass operator"" _lb(unsigned long long int x) { + return static_cast(x) * pound; +} +constexpr QMass operator"" _st(unsigned long long int x) { + return static_cast(x) * stone; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QPressure.hpp b/include/okapi/api/units/QPressure.hpp new file mode 100644 index 0000000..23fa384 --- /dev/null +++ b/include/okapi/api/units/QPressure.hpp @@ -0,0 +1,44 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QMass.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, -1, -2, 0, QPressure) + +constexpr QPressure pascal(1.0); +constexpr QPressure bar = 100000 * pascal; +constexpr QPressure psi = pound * G / inch2; + +inline namespace literals { +constexpr QPressure operator"" _Pa(long double x) { + return QPressure(x); +} +constexpr QPressure operator"" _Pa(unsigned long long int x) { + return QPressure(static_cast(x)); +} +constexpr QPressure operator"" _bar(long double x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _bar(unsigned long long int x) { + return static_cast(x) * bar; +} +constexpr QPressure operator"" _psi(long double x) { + return static_cast(x) * psi; +} +constexpr QPressure operator"" _psi(unsigned long long int x) { + return static_cast(x) * psi; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QSpeed.hpp b/include/okapi/api/units/QSpeed.hpp new file mode 100644 index 0000000..d8a1976 --- /dev/null +++ b/include/okapi/api/units/QSpeed.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 1, -1, 0, QSpeed) + +constexpr QSpeed mps = meter / second; +constexpr QSpeed miph = mile / hour; +constexpr QSpeed kmph = kilometer / hour; + +inline namespace literals { +constexpr QSpeed operator"" _mps(long double x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(long double x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(long double x) { + return static_cast(x) * kilometer / hour; +} +constexpr QSpeed operator"" _mps(unsigned long long int x) { + return static_cast(x) * mps; +} +constexpr QSpeed operator"" _miph(unsigned long long int x) { + return static_cast(x) * mile / hour; +} +constexpr QSpeed operator"" _kmph(unsigned long long int x) { + return static_cast(x) * kilometer / hour; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QTime.hpp b/include/okapi/api/units/QTime.hpp new file mode 100644 index 0000000..be9d824 --- /dev/null +++ b/include/okapi/api/units/QTime.hpp @@ -0,0 +1,55 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 0, 1, 0, QTime) + +constexpr QTime second(1.0); // SI base unit +constexpr QTime millisecond = second / 1000; +constexpr QTime minute = 60 * second; +constexpr QTime hour = 60 * minute; +constexpr QTime day = 24 * hour; + +inline namespace literals { +constexpr QTime operator"" _s(long double x) { + return QTime(x); +} +constexpr QTime operator"" _ms(long double x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(long double x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(long double x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(long double x) { + return static_cast(x) * day; +} +constexpr QTime operator"" _s(unsigned long long int x) { + return QTime(static_cast(x)); +} +constexpr QTime operator"" _ms(unsigned long long int x) { + return static_cast(x) * millisecond; +} +constexpr QTime operator"" _min(unsigned long long int x) { + return static_cast(x) * minute; +} +constexpr QTime operator"" _h(unsigned long long int x) { + return static_cast(x) * hour; +} +constexpr QTime operator"" _day(unsigned long long int x) { + return static_cast(x) * day; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QTorque.hpp b/include/okapi/api/units/QTorque.hpp new file mode 100644 index 0000000..b7b6c71 --- /dev/null +++ b/include/okapi/api/units/QTorque.hpp @@ -0,0 +1,43 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QForce.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(1, 2, -2, 0, QTorque) + +constexpr QTorque newtonMeter = newton * meter; +constexpr QTorque footPound = 1.355817948 * newtonMeter; +constexpr QTorque inchPound = 0.083333333 * footPound; + +inline namespace literals { +constexpr QTorque operator"" _nM(long double x) { + return QTorque(x); +} +constexpr QTorque operator"" _nM(unsigned long long int x) { + return QTorque(static_cast(x)); +} +constexpr QTorque operator"" _inLb(long double x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _inLb(unsigned long long int x) { + return static_cast(x) * inchPound; +} +constexpr QTorque operator"" _ftLb(long double x) { + return static_cast(x) * footPound; +} +constexpr QTorque operator"" _ftLb(unsigned long long int x) { + return static_cast(x) * footPound; +} +} // namespace literals +} // namespace okapi diff --git a/include/okapi/api/units/QVolume.hpp b/include/okapi/api/units/QVolume.hpp new file mode 100644 index 0000000..1c76b9c --- /dev/null +++ b/include/okapi/api/units/QVolume.hpp @@ -0,0 +1,28 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/RQuantity.hpp" + +namespace okapi { +QUANTITY_TYPE(0, 3, 0, 0, QVolume) + +constexpr QVolume kilometer3 = kilometer2 * kilometer; +constexpr QVolume meter3 = meter2 * meter; +constexpr QVolume decimeter3 = decimeter2 * decimeter; +constexpr QVolume centimeter3 = centimeter2 * centimeter; +constexpr QVolume millimeter3 = millimeter2 * millimeter; +constexpr QVolume inch3 = inch2 * inch; +constexpr QVolume foot3 = foot2 * foot; +constexpr QVolume mile3 = mile2 * mile; +constexpr QVolume litre = decimeter3; +} // namespace okapi diff --git a/include/okapi/api/units/RQuantity.hpp b/include/okapi/api/units/RQuantity.hpp new file mode 100644 index 0000000..2232ebc --- /dev/null +++ b/include/okapi/api/units/RQuantity.hpp @@ -0,0 +1,419 @@ +/* + * This code is a modified version of Benjamin Jurke's work in 2015. You can read his blog post + * here: + * https://benjaminjurke.com/content/articles/2015/compile-time-numerical-unit-dimension-checking/ + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include + +namespace okapi { +template +class RQuantity { + public: + explicit constexpr RQuantity() : value(0.0) { + } + + explicit constexpr RQuantity(double val) : value(val) { + } + + explicit constexpr RQuantity(long double val) : value(static_cast(val)) { + } + + // The intrinsic operations for a quantity with a unit is addition and subtraction + constexpr RQuantity const &operator+=(const RQuantity &rhs) { + value += rhs.value; + return *this; + } + + constexpr RQuantity const &operator-=(const RQuantity &rhs) { + value -= rhs.value; + return *this; + } + + constexpr RQuantity operator-() { + return RQuantity(value * -1); + } + + constexpr RQuantity const &operator*=(const double rhs) { + value *= rhs; + return *this; + } + + constexpr RQuantity const &operator/=(const double rhs) { + value /= rhs; + return *this; + } + + // Returns the value of the quantity in multiples of the specified unit + constexpr double convert(const RQuantity &rhs) const { + return value / rhs.value; + } + + // returns the raw value of the quantity (should not be used) + constexpr double getValue() const { + return value; + } + + constexpr RQuantity abs() const { + return RQuantity(std::fabs(value)); + } + + constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> + sqrt() const { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(value)); + } + + private: + double value; +}; + +// Predefined (physical unit) quantity types: +// ------------------------------------------ +#define QUANTITY_TYPE(_Mdim, _Ldim, _Tdim, _Adim, name) \ + typedef RQuantity, std::ratio<_Ldim>, std::ratio<_Tdim>, std::ratio<_Adim>> \ + name; + +// Unitless +QUANTITY_TYPE(0, 0, 0, 0, Number) +constexpr Number number(1.0); + +// Standard arithmetic operators: +// ------------------------------ +template +constexpr RQuantity operator+(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() + rhs.getValue()); +} +template +constexpr RQuantity operator-(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(lhs.getValue() - rhs.getValue()); +} +template +constexpr RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add> +operator*(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_add, + std::ratio_add, + std::ratio_add>(lhs.getValue() * rhs.getValue()); +} +template +constexpr RQuantity operator*(const double &lhs, const RQuantity &rhs) { + return RQuantity(lhs * rhs.getValue()); +} +template +constexpr RQuantity operator*(const RQuantity &lhs, const double &rhs) { + return RQuantity(lhs.getValue() * rhs); +} +template +constexpr RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract> +operator/(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, + std::ratio_subtract, + std::ratio_subtract, + std::ratio_subtract>(lhs.getValue() / rhs.getValue()); +} +template +constexpr RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>> +operator/(const double &x, const RQuantity &rhs) { + return RQuantity, M>, + std::ratio_subtract, L>, + std::ratio_subtract, T>, + std::ratio_subtract, A>>(x / rhs.getValue()); +} +template +constexpr RQuantity operator/(const RQuantity &rhs, const double &x) { + return RQuantity(rhs.getValue() / x); +} + +// Comparison operators for quantities: +// ------------------------------------ +template +constexpr bool operator==(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() == rhs.getValue()); +} +template +constexpr bool operator!=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() != rhs.getValue()); +} +template +constexpr bool operator<=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() <= rhs.getValue()); +} +template +constexpr bool operator>=(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() >= rhs.getValue()); +} +template +constexpr bool operator<(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() < rhs.getValue()); +} +template +constexpr bool operator>(const RQuantity &lhs, const RQuantity &rhs) { + return (lhs.getValue() > rhs.getValue()); +} + +// Common math functions: +// ------------------------------ + +template +constexpr RQuantity abs(const RQuantity &rhs) { + return RQuantity(std::abs(rhs.getValue())); +} + +template +constexpr RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply> +pow(const RQuantity &lhs) { + return RQuantity, + std::ratio_multiply, + std::ratio_multiply, + std::ratio_multiply>(std::pow(lhs.getValue(), double(R::num) / R::den)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +pow(const RQuantity &lhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(lhs.getValue(), R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +root(const RQuantity &lhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::pow(lhs.getValue(), 1.0 / R)); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +sqrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::sqrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>> +cbrt(const RQuantity &rhs) { + return RQuantity>, + std::ratio_divide>, + std::ratio_divide>, + std::ratio_divide>>(std::cbrt(rhs.getValue())); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +square(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 2)); +} + +template +constexpr RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>> +cube(const RQuantity &rhs) { + return RQuantity>, + std::ratio_multiply>, + std::ratio_multiply>, + std::ratio_multiply>>(std::pow(rhs.getValue(), 3)); +} + +template +constexpr RQuantity hypot(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::hypot(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity mod(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::fmod(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity copysign(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::copysign(lhs.getValue(), rhs.getValue())); +} + +template +constexpr RQuantity ceil(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::ceil(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity floor(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::floor(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity trunc(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::trunc(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +template +constexpr RQuantity round(const RQuantity &lhs, + const RQuantity &rhs) { + return RQuantity(std::round(lhs.getValue() / rhs.getValue()) * rhs.getValue()); +} + +// Common trig functions: +// ------------------------------ + +constexpr Number +sin(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sin(rhs.getValue())); +} + +constexpr Number +cos(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cos(rhs.getValue())); +} + +constexpr Number +tan(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tan(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asin(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asin(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acos(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acos(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan(rhs.getValue())); +} + +constexpr Number +sinh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::sinh(rhs.getValue())); +} + +constexpr Number +cosh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::cosh(rhs.getValue())); +} + +constexpr Number +tanh(const RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> &rhs) { + return Number(std::tanh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +asinh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::asinh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +acosh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::acosh(rhs.getValue())); +} + +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atanh(const Number &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atanh(rhs.getValue())); +} + +template +constexpr RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>> +atan2(const RQuantity &lhs, const RQuantity &rhs) { + return RQuantity, std::ratio<0>, std::ratio<0>, std::ratio<1>>( + std::atan2(lhs.getValue(), rhs.getValue())); +} + +inline namespace literals { +constexpr long double operator"" _pi(long double x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +constexpr long double operator"" _pi(unsigned long long int x) { + return static_cast(x) * 3.1415926535897932384626433832795; +} +} // namespace literals +} // namespace okapi + +// Conversion macro, which utilizes the string literals +#define ConvertTo(_x, _y) (_x).convert(1.0_##_y) diff --git a/include/okapi/api/units/RQuantityName.hpp b/include/okapi/api/units/RQuantityName.hpp new file mode 100644 index 0000000..28e6298 --- /dev/null +++ b/include/okapi/api/units/RQuantityName.hpp @@ -0,0 +1,46 @@ +#include "okapi/api/units/QAngle.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include +#include +#include + +#pragma once + +namespace okapi { + +/** +* Returns a short name for a unit. +* For example: `str(1_ft)` will return "ft", so will `1 * foot` or `0.3048_m`. +* Throws std::domain_error when `q` is a unit not defined in this function. +* +* @param q Your unit. Currently only QLength and QAngle are supported. +* @return The short string suffix for that unit. +*/ +template std::string getShortUnitName(QType q) { + const std::unordered_map> shortNameMap = + {{typeid(meter), + { + {meter.getValue(), "m"}, + {decimeter.getValue(), "dm"}, + {centimeter.getValue(), "cm"}, + {millimeter.getValue(), "mm"}, + {kilometer.getValue(), "km"}, + {inch.getValue(), "in"}, + {foot.getValue(), "ft"}, + {yard.getValue(), "yd"}, + {mile.getValue(), "mi"}, + {tile.getValue(), "tile"}, + }}, + {typeid(degree), {{degree.getValue(), "deg"}, {radian.getValue(), "rad"}}}}; + + try { + return shortNameMap.at(typeid(q)).at(q.getValue()); + } catch (const std::out_of_range &e) { + throw std::domain_error( + "You have requested the shortname of an unknown unit somewhere (likely odometry strings). " + "Shortname for provided unit is unspecified. You can override this function to add more " + "names or manually specify the name instead."); + } +} +} // namespace okapi diff --git a/include/okapi/api/util/abstractRate.hpp b/include/okapi/api/util/abstractRate.hpp new file mode 100644 index 0000000..987b314 --- /dev/null +++ b/include/okapi/api/util/abstractRate.hpp @@ -0,0 +1,41 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractRate { + public: + virtual ~AbstractRate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + virtual void delay(QFrequency ihz) = 0; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + virtual void delayUntil(QTime itime) = 0; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + virtual void delayUntil(uint32_t ims) = 0; +}; +} // namespace okapi diff --git a/include/okapi/api/util/abstractTimer.hpp b/include/okapi/api/util/abstractTimer.hpp new file mode 100644 index 0000000..db9a488 --- /dev/null +++ b/include/okapi/api/util/abstractTimer.hpp @@ -0,0 +1,125 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/units/QFrequency.hpp" +#include "okapi/api/units/QTime.hpp" + +namespace okapi { +class AbstractTimer { + public: + /** + * A Timer base class which implements its methods in terms of millis(). + * + * @param ifirstCalled the current time + */ + explicit AbstractTimer(QTime ifirstCalled); + + virtual ~AbstractTimer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + virtual QTime millis() const = 0; + + /** + * Returns the time passed in ms since the previous call of this function. + * + * @return The time passed in ms since the previous call of this function + */ + virtual QTime getDt(); + + /** + * Returns the time passed in ms since the previous call of getDt(). Does not change the time + * recorded by getDt(). + * + * @return The time passed in ms since the previous call of getDt() + */ + virtual QTime readDt() const; + + /** + * Returns the time the timer was first constructed. + * + * @return The time the timer was first constructed + */ + virtual QTime getStartingTime() const; + + /** + * Returns the time since the timer was first constructed. + * + * @return The time since the timer was first constructed + */ + virtual QTime getDtFromStart() const; + + /** + * Place a time marker. Placing another marker will overwrite the previous one. + */ + virtual void placeMark(); + + /** + * Clears the marker. + * + * @return The old marker + */ + virtual QTime clearMark(); + + /** + * Place a hard time marker. Placing another hard marker will not overwrite the previous one; + * instead, call clearHardMark() and then place another. + */ + virtual void placeHardMark(); + + /** + * Clears the hard marker. + * + * @return The old hard marker + */ + virtual QTime clearHardMark(); + + /** + * Returns the time since the time marker. Returns 0_ms if there is no marker. + * + * @return The time since the time marker + */ + virtual QTime getDtFromMark() const; + + /** + * Returns the time since the hard time marker. Returns 0_ms if there is no hard marker set. + * + * @return The time since the hard time marker + */ + virtual QTime getDtFromHardMark() const; + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param time time period + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QTime time); + + /** + * Returns true when the input time period has passed, then resets. Meant to be used in loops + * to run an action every time period without blocking. + * + * @param frequency the repeat frequency + * @return true when the input time period has passed, false after reading true until the + * period has passed again + */ + virtual bool repeat(QFrequency frequency); + + protected: + QTime firstCalled; + QTime lastCalled; + QTime mark; + QTime hardMark; + QTime repeatMark; +}; +} // namespace okapi diff --git a/include/okapi/api/util/logging.hpp b/include/okapi/api/util/logging.hpp new file mode 100644 index 0000000..b3a6c30 --- /dev/null +++ b/include/okapi/api/util/logging.hpp @@ -0,0 +1,192 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/coreProsAPI.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include +#include + +#if defined(THREADS_STD) +#else +#include "okapi/impl/util/timer.hpp" +#endif + +#define LOG_DEBUG(msg) logger->debug([=]() { return msg; }) +#define LOG_INFO(msg) logger->info([=]() { return msg; }) +#define LOG_WARN(msg) logger->warn([=]() { return msg; }) +#define LOG_ERROR(msg) logger->error([=]() { return msg; }) + +#define LOG_DEBUG_S(msg) LOG_DEBUG(std::string(msg)) +#define LOG_INFO_S(msg) LOG_INFO(std::string(msg)) +#define LOG_WARN_S(msg) LOG_WARN(std::string(msg)) +#define LOG_ERROR_S(msg) LOG_ERROR(std::string(msg)) + +namespace okapi { +class Logger { + public: + enum class LogLevel { + debug = 4, ///< debug + info = 3, ///< info + warn = 2, ///< warn + error = 1, ///< error + off = 0 ///< off + }; + + /** + * A logger that does nothing. + */ + Logger() noexcept; + + /** + * A logger that opens the input file by name. If the file contains `/ser/`, the file will be + * opened in write mode. Otherwise, the file will be opened in append mode. The file will be + * closed when the logger is destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifileName The name of the log file to open. + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, + std::string_view ifileName, + const LogLevel &ilevel) noexcept; + + /** + * A logger that uses an existing file handle. The file will be closed when the logger is + * destructed. + * + * @param itimer A timer used to get the current time for log statements. + * @param ifile The log file to open. Will be closed by the logger! + * @param ilevel The log level. Log statements more verbose than this level will be disabled. + */ + Logger(std::unique_ptr itimer, FILE *ifile, const LogLevel &ilevel) noexcept; + + ~Logger(); + + constexpr bool isDebugLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::debug); + } + + template void debug(T ilazyMessage) noexcept { + if (isDebugLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) DEBUG: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isInfoLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::info); + } + + template void info(T ilazyMessage) noexcept { + if (isInfoLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) INFO: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isWarnLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::warn); + } + + template void warn(T ilazyMessage) noexcept { + if (isWarnLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) WARN: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + constexpr bool isErrorLevelEnabled() const noexcept { + return toUnderlyingType(logLevel) >= toUnderlyingType(LogLevel::error); + } + + template void error(T ilazyMessage) noexcept { + if (isErrorLevelEnabled() && logfile && timer) { + std::scoped_lock lock(logfileMutex); + fprintf(logfile, + "%ld (%s) ERROR: %s\n", + static_cast(timer->millis().convert(millisecond)), + CrossplatformThread::getName().c_str(), + ilazyMessage().c_str()); + } + } + + /** + * Closes the connection to the log file. + */ + constexpr void close() noexcept { + if (logfile) { + fclose(logfile); + logfile = nullptr; + } + } + + /** + * @return The default logger. + */ + static std::shared_ptr getDefaultLogger(); + + /** + * Sets a new default logger. OkapiLib classes use the default logger unless given another logger + * in their constructor. + * + * @param ilogger The new logger instance. + */ + static void setDefaultLogger(std::shared_ptr ilogger); + + private: + const std::unique_ptr timer; + const LogLevel logLevel; + FILE *logfile; + CrossplatformMutex logfileMutex; + + static bool isSerialStream(std::string_view filename); +}; + +extern std::shared_ptr defaultLogger; + +struct DefaultLoggerInitializer { + DefaultLoggerInitializer() { + if (count++ == 0) { + init(); + } + } + ~DefaultLoggerInitializer() { + if (--count == 0) { + cleanup(); + } + } + + static int count; + + static void init() { +#if defined(THREADS_STD) + defaultLogger = std::make_shared(); +#else + defaultLogger = + std::make_shared(std::make_unique(), "/ser/sout", Logger::LogLevel::warn); +#endif + } + + static void cleanup() { + } +}; + +static DefaultLoggerInitializer defaultLoggerInitializer; // NOLINT(cert-err58-cpp) +} // namespace okapi diff --git a/include/okapi/api/util/mathUtil.hpp b/include/okapi/api/util/mathUtil.hpp new file mode 100644 index 0000000..424a862 --- /dev/null +++ b/include/okapi/api/util/mathUtil.hpp @@ -0,0 +1,255 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include +#include +#include +#include + +namespace okapi { +/** + * Converts inches to millimeters. + */ +static constexpr double inchToMM = 25.4; + +/** + * Converts millimeters to inches. + */ +static constexpr double mmToInch = 0.0393700787; + +/** + * Converts degrees to radians. + */ +static constexpr double degreeToRadian = 0.01745329252; + +/** + * Converts radians to degrees. + */ +static constexpr double radianToDegree = 57.2957795; + +/** + * The ticks per rotation of the 393 IME with torque gearing. + */ +static constexpr double imeTorqueTPR = 627.2; + +/** + * The ticks per rotation of the 393 IME with speed gearing. + */ +static constexpr std::int32_t imeSpeedTPR = 392; + +/** + * The ticks per rotation of the 393 IME with turbo gearing. + */ +static constexpr double imeTurboTPR = 261.333; + +/** + * The ticks per rotation of the 269 IME. + */ +static constexpr double ime269TPR = 240.448; + +/** + * The ticks per rotation of the V5 motor with a red gearset. + */ +static constexpr std::int32_t imev5RedTPR = 1800; + +/** + * The ticks per rotation of the V5 motor with a green gearset. + */ +static constexpr std::int32_t imev5GreenTPR = 900; + +/** + * The ticks per rotation of the V5 motor with a blue gearset. + */ +static constexpr std::int32_t imev5BlueTPR = 300; + +/** + * The ticks per rotation of the red quadrature encoders. + */ +static constexpr std::int32_t quadEncoderTPR = 360; + +/** + * The value of pi. + */ +static constexpr double pi = 3.1415926535897932; + +/** + * The value of pi divided by 2. + */ +static constexpr double pi2 = 1.5707963267948966; + +/** + * The conventional value of gravity of Earth. + */ +static constexpr double gravity = 9.80665; + +/** + * Same as PROS_ERR. + */ +static constexpr auto OKAPI_PROS_ERR = INT32_MAX; + +/** + * Same as PROS_ERR_F. + */ +static constexpr auto OKAPI_PROS_ERR_F = INFINITY; + +/** + * The maximum voltage that can be sent to V5 motors. + */ +static constexpr double v5MotorMaxVoltage = 12000; + +/** + * The polling frequency of V5 motors in milliseconds. + */ +static constexpr std::int8_t motorUpdateRate = 10; + +/** + * The polling frequency of the ADI ports in milliseconds. + */ +static constexpr std::int8_t adiUpdateRate = 10; + +/** + * Integer power function. Computes `base^expo`. + * + * @param base The base. + * @param expo The exponent. + * @return `base^expo`. + */ +constexpr double ipow(const double base, const int expo) { + return (expo == 0) ? 1 + : expo == 1 ? base + : expo > 1 ? ((expo & 1) ? base * ipow(base, expo - 1) + : ipow(base, expo / 2) * ipow(base, expo / 2)) + : 1 / ipow(base, -expo); +} + +/** + * Cuts out a range from the number. The new range of the input number will be + * `(-inf, min]U[max, +inf)`. If value sits equally between `min` and `max`, `max` will be returned. + * + * @param value The number to bound. + * @param min The lower bound of range. + * @param max The upper bound of range. + * @return The remapped value. + */ +constexpr double cutRange(const double value, const double min, const double max) { + const double middle = max - ((max - min) / 2); + + if (value > min && value < middle) { + return min; + } else if (value <= max && value >= middle) { + return max; + } + + return value; +} + +/** + * Deadbands a range of the number. Returns the input value, or `0` if it is in the range `[min, + * max]`. + * + * @param value The number to deadband. + * @param min The lower bound of deadband. + * @param max The upper bound of deadband. + * @return The input value or `0` if it is in the range `[min, max]`. + */ +constexpr double deadband(const double value, const double min, const double max) { + return std::clamp(value, min, max) == value ? 0 : value; +} + +/** + * Remap a value in the range `[oldMin, oldMax]` to the range `[newMin, newMax]`. + * + * @param value The value in the old range. + * @param oldMin The old range lower bound. + * @param oldMax The old range upper bound. + * @param newMin The new range lower bound. + * @param newMax The new range upper bound. + * @return The input value in the new range `[newMin, newMax]`. + */ +constexpr double remapRange(const double value, + const double oldMin, + const double oldMax, + const double newMin, + const double newMax) { + return (value - oldMin) * ((newMax - newMin) / (oldMax - oldMin)) + newMin; +} + +/** + * Converts an enum to its value type. + * + * @param e The enum value. + * @return The corresponding value. + */ +template constexpr auto toUnderlyingType(const E e) noexcept { + return static_cast>(e); +} + +/** + * Converts a bool to a sign. + * + * @param b The bool. + * @return True corresponds to `1` and false corresponds to `-1`. + */ +constexpr auto boolToSign(const bool b) noexcept { + return b ? 1 : -1; +} + +/** + * Computes `lhs mod rhs` using Euclidean division. C's `%` symbol computes the remainder, not + * modulus. + * + * @param lhs The left-hand side. + * @param rhs The right-hand side. + * @return `lhs` mod `rhs`. + */ +constexpr long modulus(const long lhs, const long rhs) noexcept { + return ((lhs % rhs) + rhs) % rhs; +} + +/** + * Converts a gearset to its TPR. + * + * @param igearset The gearset. + * @return The corresponding TPR. + */ +constexpr std::int32_t gearsetToTPR(const AbstractMotor::gearset igearset) noexcept { + switch (igearset) { + case AbstractMotor::gearset::red: + return imev5RedTPR; + case AbstractMotor::gearset::green: + return imev5GreenTPR; + case AbstractMotor::gearset::blue: + case AbstractMotor::gearset::invalid: + default: + return imev5BlueTPR; + } +} + +/** + * Maps ADI port numbers/chars to numbers: + * ``` + * when (port) { + * in ['a', 'h'] -> [1, 8] + * in ['A', 'H'] -> [1, 8] + * else -> [1, 8] + * } + * ``` + * + * @param port The ADI port number or char. + * @return An equivalent ADI port number. + */ +constexpr std::int8_t transformADIPort(const std::int8_t port) { + if (port >= 'a' && port <= 'h') { + return port - ('a' - 1); + } else if (port >= 'A' && port <= 'H') { + return port - ('A' - 1); + } else { + return port; + } +} +} // namespace okapi diff --git a/include/okapi/api/util/supplier.hpp b/include/okapi/api/util/supplier.hpp new file mode 100644 index 0000000..9c92ed0 --- /dev/null +++ b/include/okapi/api/util/supplier.hpp @@ -0,0 +1,34 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include + +namespace okapi { +/** + * A supplier of instances of T. + * + * @tparam T the type to supply + */ +template class Supplier { + public: + explicit Supplier(std::function ifunc) : func(ifunc) { + } + + virtual ~Supplier() = default; + + /** + * Get an instance of type T. This is usually a new instance, but it does not have to be. + * @return an instance of T + */ + T get() const { + return func(); + } + + protected: + std::function func; +}; +} // namespace okapi diff --git a/include/okapi/api/util/timeUtil.hpp b/include/okapi/api/util/timeUtil.hpp new file mode 100644 index 0000000..a79a7f2 --- /dev/null +++ b/include/okapi/api/util/timeUtil.hpp @@ -0,0 +1,41 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/util/settledUtil.hpp" +#include "okapi/api/util/abstractRate.hpp" +#include "okapi/api/util/abstractTimer.hpp" +#include "okapi/api/util/supplier.hpp" + +namespace okapi { +/** + * Utility class for holding an AbstractTimer, AbstractRate, and SettledUtil together in one + * class since they are commonly used together. + */ +class TimeUtil { + public: + TimeUtil(const Supplier> &itimerSupplier, + const Supplier> &irateSupplier, + const Supplier> &isettledUtilSupplier); + + std::unique_ptr getTimer() const; + + std::unique_ptr getRate() const; + + std::unique_ptr getSettledUtil() const; + + Supplier> getTimerSupplier() const; + + Supplier> getRateSupplier() const; + + Supplier> getSettledUtilSupplier() const; + + protected: + Supplier> timerSupplier; + Supplier> rateSupplier; + Supplier> settledUtilSupplier; +}; +} // namespace okapi diff --git a/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp b/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp new file mode 100644 index 0000000..7d11896 --- /dev/null +++ b/include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp @@ -0,0 +1,506 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisControllerIntegrated.hpp" +#include "okapi/api/chassis/controller/chassisControllerPid.hpp" +#include "okapi/api/chassis/controller/defaultOdomChassisController.hpp" +#include "okapi/api/chassis/model/hDriveModel.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/chassis/model/xDriveModel.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/device/rotarysensor/rotationSensor.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class ChassisControllerBuilder { + public: + /** + * A builder that creates ChassisControllers. Use this to create your ChassisController. + * + * @param ilogger The logger this instance will log to. + */ + explicit ChassisControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &ileft, const Motor &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &ileft, const MotorGroup &iright); + + /** + * Sets the motors using a skid-steer layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const Motor &itopLeft, + const Motor &itopRight, + const Motor &ibottomRight, + const Motor &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const MotorGroup &itopLeft, + const MotorGroup &itopRight, + const MotorGroup &ibottomRight, + const MotorGroup &ibottomLeft); + + /** + * Sets the motors using an x-drive layout. + * + * @param itopLeft The top left motor. + * @param itopRight The top right motor. + * @param ibottomRight The bottom right motor. + * @param ibottomLeft The bottom left motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &itopLeft, + const std::shared_ptr &itopRight, + const std::shared_ptr &ibottomRight, + const std::shared_ptr &ibottomLeft); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const Motor &ileft, const Motor &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const MotorGroup &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withMotors(const MotorGroup &ileft, const MotorGroup &iright, const Motor &imiddle); + + /** + * Sets the motors using an h-drive layout. + * + * @param ileft The left motor. + * @param iright The right motor. + * @param imiddle The middle motor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMotors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const ADIEncoder &ileft, const ADIEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withSensors(const ADIEncoder &ileft, const ADIEncoder &iright, const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const RotationSensor &ileft, const RotationSensor &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const RotationSensor &ileft, + const RotationSensor &iright, + const RotationSensor &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const IntegratedEncoder &ileft, + const IntegratedEncoder &iright, + const ADIEncoder &imiddle); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright); + + /** + * Sets the sensors. The default sensors are the motor's integrated encoders. + * + * @param ileft The left side sensor. + * @param iright The right side sensor. + * @param imiddle The middle sensor. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withSensors(const std::shared_ptr &ileft, + const std::shared_ptr &iright, + const std::shared_ptr &imiddle); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. Uses the + * turn controller's gains for the angle controller's gains. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains); + + /** + * Sets the PID controller gains, causing the builder to generate a ChassisControllerPID. + * + * @param idistanceGains The distance controller's gains. + * @param iturnGains The turn controller's gains. + * @param iangleGains The angle controller's gains. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withGains(const IterativePosPIDController::Gains &idistanceGains, + const IterativePosPIDController::Gains &iturnGains, + const IterativePosPIDController::Gains &iangleGains); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodomScales The ChassisScales used just for odometry (if they are different than those + * for the drive). + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(const ChassisScales &iodomScales, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the odometry information, causing the builder to generate an Odometry variant. + * + * @param iodometry The odometry object. + * @param imode The new default StateMode used to interpret target points and query the Odometry + * state. + * @param imoveThreshold The minimum length movement. + * @param iturnThreshold The minimum angle turn. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometry(std::shared_ptr iodometry, + const StateMode &imode = StateMode::FRAME_TRANSFORMATION, + const QLength &imoveThreshold = 0_mm, + const QAngle &iturnThreshold = 0_deg); + + /** + * Sets the derivative filters. Uses a PassthroughFilter by default. + * + * @param idistanceFilter The distance controller's filter. + * @param iturnFilter The turn controller's filter. + * @param iangleFilter The angle controller's filter. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDerivativeFilters( + std::unique_ptr idistanceFilter, + std::unique_ptr iturnFilter = std::make_unique(), + std::unique_ptr iangleFilter = std::make_unique()); + + /** + * Sets the chassis dimensions. + * + * @param igearset The gearset in the drive motors. + * @param iscales The ChassisScales for the base. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withDimensions(const AbstractMotor::GearsetRatioPair &igearset, + const ChassisScales &iscales); + + /** + * Sets the max velocity. Overrides the max velocity of the gearset. + * + * @param imaxVelocity The max velocity. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the max voltage. The default is `12000`. + * + * @param imaxVoltage The max voltage. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withMaxVoltage(double imaxVoltage); + + /** + * Sets the TimeUtilFactory used when building a ChassisController. This instance will be given + * to the ChassisController (not to controllers it uses). The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withChassisControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the TimeUtilFactory used when building a ClosedLoopController. This instance will be given + * to any ClosedLoopController instances. The default is the static TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder & + withClosedLoopControllerTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Creates a new ConfigurableTimeUtilFactory with the given parameters. Given to any + * ClosedLoopController instances. + * + * @param iatTargetError The minimum error to be considered settled. + * @param iatTargetDerivative The minimum error derivative to be considered settled. + * @param iatTargetTime The minimum time within atTargetError to be considered settled. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withClosedLoopControllerTimeUtil(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Sets the TimeUtilFactory used when building an Odometry. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withOdometryTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger used for the ChassisController and ClosedLoopControllers. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + ChassisControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + ChassisControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the ChassisController. Throws a std::runtime_exception if no motors were set or if no + * dimensions were set. + * + * @return A fully built ChassisController. + */ + std::shared_ptr build(); + + /** + * Builds the OdomChassisController. Throws a std::runtime_exception if no motors were set, if no + * dimensions were set, or if no odometry information was passed. + * + * @return A fully built OdomChassisController. + */ + std::shared_ptr buildOdometry(); + + private: + std::shared_ptr logger; + + struct SkidSteerMotors { + std::shared_ptr left; + std::shared_ptr right; + }; + + struct XDriveMotors { + std::shared_ptr topLeft; + std::shared_ptr topRight; + std::shared_ptr bottomRight; + std::shared_ptr bottomLeft; + }; + + struct HDriveMotors { + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr middle; + }; + + enum class DriveMode { SkidSteer, XDrive, HDrive }; + + bool hasMotors{false}; // Used to verify motors were passed + DriveMode driveMode{DriveMode::SkidSteer}; + SkidSteerMotors skidSteerMotors; + XDriveMotors xDriveMotors; + HDriveMotors hDriveMotors; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr leftSensor{nullptr}; + std::shared_ptr rightSensor{nullptr}; + std::shared_ptr middleSensor{nullptr}; + + bool hasGains{false}; // Whether gains were passed, no gains means CCI + IterativePosPIDController::Gains distanceGains; + std::unique_ptr distanceFilter = std::make_unique(); + IterativePosPIDController::Gains angleGains; + std::unique_ptr angleFilter = std::make_unique(); + IterativePosPIDController::Gains turnGains; + std::unique_ptr turnFilter = std::make_unique(); + TimeUtilFactory chassisControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory closedLoopControllerTimeUtilFactory = TimeUtilFactory(); + TimeUtilFactory odometryTimeUtilFactory = TimeUtilFactory(); + + AbstractMotor::GearsetRatioPair gearset{AbstractMotor::gearset::invalid, 1.0}; + ChassisScales driveScales{{1, 1}, imev5GreenTPR}; + bool differentOdomScales{false}; + ChassisScales odomScales{{1, 1}, imev5GreenTPR}; + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool hasOdom{false}; // Whether odometry was passed + std::shared_ptr odometry; + StateMode stateMode; + QLength moveThreshold; + QAngle turnThreshold; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + double maxVoltage{12000}; + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildCCPID(); + std::shared_ptr buildCCI(); + std::shared_ptr + buildDOCC(std::shared_ptr chassisController); + + std::shared_ptr makeChassisModel(); + std::shared_ptr makeSkidSteerModel(); + std::shared_ptr makeXDriveModel(); + std::shared_ptr makeHDriveModel(); +}; +} // namespace okapi diff --git a/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp b/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp new file mode 100644 index 0000000..7faf827 --- /dev/null +++ b/include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp @@ -0,0 +1,177 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/control/async/asyncLinearMotionProfileController.hpp" +#include "okapi/api/control/async/asyncMotionProfileController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncMotionProfileControllerBuilder { + public: + /** + * A builder that creates async motion profile controllers. Use this to build an + * AsyncMotionProfileController or an AsyncLinearMotionProfileController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncMotionProfileControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const Motor &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const MotorGroup &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildLinearMotionProfileController(). + * + * @param ioutput The output. + * @param idiameter The diameter of the mechanical part the motor spins. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr> &ioutput, + const QLength &idiameter, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(ChassisController &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param icontroller The chassis controller to use. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder & + withOutput(const std::shared_ptr &icontroller); + + /** + * Sets the output. This must be used with buildMotionProfileController(). + * + * @param imodel The chassis model to use. + * @param iscales The chassis dimensions. + * @param ipair The gearset. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withOutput(const std::shared_ptr &imodel, + const ChassisScales &iscales, + const AbstractMotor::GearsetRatioPair &ipair); + + /** + * Sets the limits. + * + * @param ilimits The limits. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLimits(const PathfinderLimits &ilimits); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncMotionProfileControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncLinearMotionProfileController. + * + * @return A fully built AsyncLinearMotionProfileController. + */ + std::shared_ptr buildLinearMotionProfileController(); + + /** + * Builds the AsyncMotionProfileController. + * + * @return A fully built AsyncMotionProfileController. + */ + std::shared_ptr buildMotionProfileController(); + + private: + std::shared_ptr logger; + + bool hasLimits{false}; + PathfinderLimits limits; + + bool hasOutput{false}; + std::shared_ptr> output; + QLength diameter; + + bool hasModel{false}; + std::shared_ptr model; + ChassisScales scales{{1, 1}, imev5GreenTPR}; + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; +}; +} // namespace okapi diff --git a/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp b/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp new file mode 100644 index 0000000..124558b --- /dev/null +++ b/include/okapi/impl/control/async/asyncPosControllerBuilder.hpp @@ -0,0 +1,190 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncPosIntegratedController.hpp" +#include "okapi/api/control/async/asyncPosPidController.hpp" +#include "okapi/api/control/async/asyncPositionController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncPosControllerBuilder { + public: + /** + * A builder that creates async position controllers. Use this to create an + * AsyncPosIntegratedController or an AsyncPosPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncPosControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncPosPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGains(const IterativePosPIDController::Gains &igains); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncPosPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncPosControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncPositionController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncPositionController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativePosPIDController::Gains gains; + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAPIC(); + std::shared_ptr buildAPPC(); +}; +} // namespace okapi diff --git a/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp b/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp new file mode 100644 index 0000000..8643e89 --- /dev/null +++ b/include/okapi/impl/control/async/asyncVelControllerBuilder.hpp @@ -0,0 +1,203 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/async/asyncVelIntegratedController.hpp" +#include "okapi/api/control/async/asyncVelPidController.hpp" +#include "okapi/api/control/async/asyncVelocityController.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/device/rotarysensor/adiEncoder.hpp" +#include "okapi/impl/device/rotarysensor/integratedEncoder.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +class AsyncVelControllerBuilder { + public: + /** + * A builder that creates async velocity controllers. Use this to create an + * AsyncVelIntegratedController or an AsyncVelPIDController. + * + * @param ilogger The logger this instance will log to. + */ + explicit AsyncVelControllerBuilder( + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const Motor &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const MotorGroup &imotor); + + /** + * Sets the motor. + * + * @param imotor The motor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMotor(const std::shared_ptr &imotor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const ADIEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const IntegratedEncoder &isensor); + + /** + * Sets the sensor. The default sensor is the motor's integrated encoder. + * + * @param isensor The sensor. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withSensor(const std::shared_ptr &isensor); + + /** + * Sets the controller gains, causing the builder to generate an AsyncVelPIDController. This does + * not set the integrated control's gains. + * + * @param igains The gains. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGains(const IterativeVelPIDController::Gains &igains); + + /** + * Sets the VelMath which calculates and filters velocity. This is ignored when using integrated + * controller. If using a PID controller (by setting the gains), this is required. + * + * @param ivelMath The VelMath. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withVelMath(std::unique_ptr ivelMath); + + /** + * Sets the derivative filter which filters the derivative term before it is scaled by kD. The + * filter is ignored when using integrated control. The default derivative filter is a + * PassthroughFilter. + * + * @param iderivativeFilter The derivative filter. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withDerivativeFilter(std::unique_ptr iderivativeFilter); + + /** + * Sets the gearset. The default gearset is derived from the motor's. + * + * @param igearset The gearset. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withGearset(const AbstractMotor::GearsetRatioPair &igearset); + + /** + * Sets the maximum velocity. The default maximum velocity is derived from the motor's gearset. + * This parameter is ignored when using an AsyncVelPIDController. + * + * @param imaxVelocity The maximum velocity. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withMaxVelocity(double imaxVelocity); + + /** + * Sets the TimeUtilFactory used when building the controller. The default is the static + * TimeUtilFactory. + * + * @param itimeUtilFactory The TimeUtilFactory. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withTimeUtilFactory(const TimeUtilFactory &itimeUtilFactory); + + /** + * Sets the logger. + * + * @param ilogger The logger. + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &withLogger(const std::shared_ptr &ilogger); + + /** + * Parents the internal tasks started by this builder to the current task, meaning they will be + * deleted once the current task is deleted. The `initialize` and `competition_initialize` tasks + * are never parented to. This is the default behavior. + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder &parentedToCurrentTask(); + + /** + * Prevents parenting the internal tasks started by this builder to the current task, meaning they + * will not be deleted once the current task is deleted. This can cause runaway tasks, but is + * sometimes the desired behavior (e.x., if you want to use this builder once in `autonomous` and + * then again in `opcontrol`). + * + * Read more about this in the [builders and tasks tutorial] + * (docs/tutorials/concepts/builders-and-tasks.md). + * + * @return An ongoing builder. + */ + AsyncVelControllerBuilder ¬ParentedToCurrentTask(); + + /** + * Builds the AsyncVelocityController. Throws a std::runtime_exception is no motors were set. + * + * @return A fully built AsyncVelocityController. + */ + std::shared_ptr> build(); + + private: + std::shared_ptr logger; + + bool hasMotors{false}; // Used to verify motors were passed + std::shared_ptr motor; + + bool sensorsSetByUser{false}; // Used so motors don't overwrite sensors set manually + std::shared_ptr sensor; + + bool hasGains{false}; // Whether gains were passed, no gains means integrated control + IterativeVelPIDController::Gains gains; + + bool hasVelMath{false}; // Used to verify velMath was passed + std::unique_ptr velMath; + + std::unique_ptr derivativeFilter = std::make_unique(); + + bool gearsetSetByUser{false}; // Used so motor's don't overwrite a gearset set manually + AbstractMotor::GearsetRatioPair pair{AbstractMotor::gearset::invalid}; + + bool maxVelSetByUser{false}; // Used so motors don't overwrite maxVelocity + double maxVelocity{600}; + + TimeUtilFactory timeUtilFactory = TimeUtilFactory(); + std::shared_ptr controllerLogger = Logger::getDefaultLogger(); + + bool isParentedToCurrentTask{true}; + + std::shared_ptr buildAVIC(); + std::shared_ptr buildAVPC(); +}; +} // namespace okapi diff --git a/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp b/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp new file mode 100644 index 0000000..85b05a5 --- /dev/null +++ b/include/okapi/impl/control/iterative/iterativeControllerFactory.hpp @@ -0,0 +1,120 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/iterative/iterativeMotorVelocityController.hpp" +#include "okapi/api/control/iterative/iterativePosPidController.hpp" +#include "okapi/api/control/iterative/iterativeVelPidController.hpp" +#include "okapi/api/util/mathUtil.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include "okapi/impl/device/motor/motorGroup.hpp" +#include "okapi/impl/filter/velMathFactory.hpp" + +namespace okapi { +class IterativeControllerFactory { + public: + /** + * Position PID controller. + * + * @param ikP proportional gain + * @param ikI integral gain + * @param ikD derivative gain + * @param ikBias controller bias (constant offset added to the output) + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativePosPIDController + posPID(double ikP, + double ikI, + double ikD, + double ikBias = 0, + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller. + * + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeVelPIDController + velPID(double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param ikP proportional gain + * @param ikD derivative gain + * @param ikF feed-forward gain + * @param ikSF a feed-forward gain to counteract static friction + * @param ivelMath The VelMath. + * @param iderivativeFilter A filter for filtering the derivative term. + * @param ilogger The logger this instance will log to. + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + double ikP, + double ikD, + double ikF = 0, + double ikSF = 0, + std::unique_ptr ivelMath = VelMathFactory::createPtr(imev5GreenTPR), + std::unique_ptr iderivativeFilter = std::make_unique(), + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(Motor imotor, + std::shared_ptr> icontroller); + + /** + * Velocity PD controller that automatically writes to the motor. + * + * @param imotor output motor + * @param icontroller controller to use + */ + static IterativeMotorVelocityController + motorVelocity(MotorGroup imotor, + std::shared_ptr> icontroller); +}; +} // namespace okapi diff --git a/include/okapi/impl/control/util/controllerRunnerFactory.hpp b/include/okapi/impl/control/util/controllerRunnerFactory.hpp new file mode 100644 index 0000000..16ab592 --- /dev/null +++ b/include/okapi/impl/control/util/controllerRunnerFactory.hpp @@ -0,0 +1,25 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/util/controllerRunner.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +template class ControllerRunnerFactory { + public: + /** + * A utility class that runs a closed-loop controller. + * + * @param ilogger The logger this instance will log to. + * @return + */ + static ControllerRunner + create(const std::shared_ptr &ilogger = Logger::getDefaultLogger()) { + return ControllerRunner(TimeUtilFactory::createDefault(), ilogger); + } +}; +} // namespace okapi diff --git a/include/okapi/impl/control/util/pidTunerFactory.hpp b/include/okapi/impl/control/util/pidTunerFactory.hpp new file mode 100644 index 0000000..332b55f --- /dev/null +++ b/include/okapi/impl/control/util/pidTunerFactory.hpp @@ -0,0 +1,47 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/control/util/pidTuner.hpp" +#include + +namespace okapi { +class PIDTunerFactory { + public: + static PIDTuner create(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + static std::unique_ptr + createPtr(const std::shared_ptr> &iinput, + const std::shared_ptr> &ioutput, + QTime itimeout, + std::int32_t igoal, + double ikPMin, + double ikPMax, + double ikIMin, + double ikIMax, + double ikDMin, + double ikDMax, + std::int32_t inumIterations = 5, + std::int32_t inumParticles = 16, + double ikSettle = 1, + double ikITAE = 2, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/include/okapi/impl/device/adiUltrasonic.hpp b/include/okapi/impl/device/adiUltrasonic.hpp new file mode 100644 index 0000000..6a525f4 --- /dev/null +++ b/include/okapi/impl/device/adiUltrasonic.hpp @@ -0,0 +1,71 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +class ADIUltrasonic : public ControllerInput { + public: + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic('A', 'B'); + * auto filteredUltra = ADIUltrasonic('A', 'B', std::make_unique>()); + * ``` + * + * @param iportPing The port connected to the orange OUTPUT cable. This must be in port ``1``, + * ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportEcho The port connected to the yellow INPUT cable. This must be in the next highest + * port following iportPing. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::uint8_t iportPing, + std::uint8_t iportEcho, + std::unique_ptr ifilter = std::make_unique()); + + /** + * An ultrasonic sensor in the ADI (3-wire) ports. + * + * ```cpp + * auto ultra = ADIUltrasonic({1, 'A', 'B'}); + * auto filteredUltra = ADIUltrasonic({1, 'A', 'B'}, std::make_unique>()); + * ``` + * + * @param iports The ports the ultrasonic is plugged in to in the order ``{smart port, ping port, + * echo port}``. The smart port is the smart port number (``[1, 21]``). The ping port is the port + * connected to the orange OUTPUT cable. This must be in port ``1``, ``3``, ``5``, or ``7`` + * (``A``, ``C``, ``E``, or ``G``). The echo port is the port connected to the yellow INPUT cable. + * This must be in the next highest port following the ping port. + * @param ifilter The filter to use for filtering the distance measurements. + */ + ADIUltrasonic(std::tuple iports, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~ADIUltrasonic(); + + /** + * Returns the current filtered sensor value. + * + * @return current value + */ + virtual double get(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. Calls get(). + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_ultrasonic_t ultra; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/button/adiButton.hpp b/include/okapi/impl/device/button/adiButton.hpp new file mode 100644 index 0000000..32e59a8 --- /dev/null +++ b/include/okapi/impl/device/button/adiButton.hpp @@ -0,0 +1,50 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" + +namespace okapi { +class ADIButton : public ButtonBase { + public: + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton('A', false); + * auto invertedBtn = ADIButton('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::uint8_t iport, bool iinverted = false); + + /** + * A button in an ADI port. + * + * ```cpp + * auto btn = ADIButton({1, 'A'}, false); + * auto invertedBtn = ADIButton({1, 'A'}, true); + * ``` + * + * @param iports The ports the button is plugged in to in the order ``{smart port, button port}``. + * The smart port is the smart port number (``[1, 21]``). The button port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param iinverted Whether the button is inverted (``true`` meaning default pressed and ``false`` + * meaning default not pressed). + */ + ADIButton(std::pair iports, bool iinverted = false); + + protected: + std::uint8_t smartPort; + std::uint8_t port; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/button/controllerButton.hpp b/include/okapi/impl/device/button/controllerButton.hpp new file mode 100644 index 0000000..3d7e5e5 --- /dev/null +++ b/include/okapi/impl/device/button/controllerButton.hpp @@ -0,0 +1,38 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/button/buttonBase.hpp" +#include "okapi/impl/device/controllerUtil.hpp" + +namespace okapi { +class ControllerButton : public ButtonBase { + public: + /** + * A button on a Controller. + * + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerDigital ibtn, bool iinverted = false); + + /** + * A button on a Controller. + * + * @param icontroller The Controller the button is on. + * @param ibtn The button id. + * @param iinverted Whether the button is inverted (default pressed instead of default released). + */ + ControllerButton(ControllerId icontroller, ControllerDigital ibtn, bool iinverted = false); + + protected: + pros::controller_id_e_t id; + pros::controller_digital_e_t btn; + + virtual bool currentlyPressed() override; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/controller.hpp b/include/okapi/impl/device/controller.hpp new file mode 100644 index 0000000..81f9229 --- /dev/null +++ b/include/okapi/impl/device/controller.hpp @@ -0,0 +1,118 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/impl/device/button/controllerButton.hpp" +#include "okapi/impl/device/controllerUtil.hpp" +#include + +namespace okapi { +class Controller { + public: + Controller(ControllerId iid = ControllerId::master); + + virtual ~Controller(); + + /** + * Returns whether the controller is connected. + * + * @return true if the controller is connected + */ + virtual bool isConnected(); + + /** + * Returns the current analog reading for the channel in the range [-1, 1]. Returns 0 if the + * controller is not connected. + * + * @param ichannel the channel to read + * @return the value of that channel in the range [-1, 1] + */ + virtual float getAnalog(ControllerAnalog ichannel); + + /** + * Returns whether the digital button is currently pressed. Returns false if the controller is + * not connected. + * + * @param ibutton the button to check + * @return true if the button is pressed, false if the controller is not connected + */ + virtual bool getDigital(ControllerDigital ibutton); + + /** + * Returns a ControllerButton for the given button on this controller. + * + * @param ibtn the button + * @return a ControllerButton on this controller + */ + virtual ControllerButton &operator[](ControllerDigital ibtn); + + /** + * Sets text to the controller LCD screen. + * + * @param iline the line number in the range [0-2] at which the text will be displayed + * @param icol the column number in the range [0-14] at which the text will be displayed + * @param itext the string to display + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t setText(std::uint8_t iline, std::uint8_t icol, std::string itext); + + /** + * Clears all of the lines of the controller screen. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clear(); + + /** + * Clears an individual line of the controller screen. + * + * @param iline the line number to clear in the range [0, 2]. + * @return 1 if the operation was successful, PROS_ERR otherwise + */ + virtual std::int32_t clearLine(std::uint8_t iline); + + /** + * Rumble the controller. + * + * Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * @param irumblePattern A string consisting of the characters '.', '-', and ' ', where dots are + * short rumbles, dashes are long rumbles, and spaces are pauses. Maximum supported length is 8 + * characters. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t rumble(std::string irumblePattern); + + /** + * Gets the battery capacity of the given controller. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the controller port. + * + * @return the controller's battery capacity + */ + virtual std::int32_t getBatteryCapacity(); + + /** + * Gets the battery level of the given controller. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the controller port. + * + * @return the controller's battery level + */ + virtual std::int32_t getBatteryLevel(); + + protected: + ControllerId okapiId; + pros::controller_id_e_t prosId; + std::array buttonArray{}; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/controllerUtil.hpp b/include/okapi/impl/device/controllerUtil.hpp new file mode 100644 index 0000000..d62df3a --- /dev/null +++ b/include/okapi/impl/device/controllerUtil.hpp @@ -0,0 +1,64 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" + +namespace okapi { +/** + * Which controller role this has. + */ +enum class ControllerId { + master = 0, ///< master + partner = 1 ///< partner +}; + +/** + * The analog sticks. + */ +enum class ControllerAnalog { + leftX = 0, ///< leftX + leftY = 1, ///< leftY + rightX = 2, ///< rightX + rightY = 3 ///< rightY +}; + +/** + * Various buttons. + */ +enum class ControllerDigital { + L1 = 6, ///< L1 + L2 = 7, ///< L2 + R1 = 8, ///< R1 + R2 = 9, ///< R2 + up = 10, ///< up + down = 11, ///< down + left = 12, ///< left + right = 13, ///< right + X = 14, ///< X + B = 15, ///< B + Y = 16, ///< Y + A = 17 ///< A +}; + +class ControllerUtil { + public: + /** + * Maps an `id` to the PROS enum equivalent. + */ + static pros::controller_id_e_t idToProsEnum(ControllerId in); + + /** + * Maps an `analog` to the PROS enum equivalent. + */ + static pros::controller_analog_e_t analogToProsEnum(ControllerAnalog in); + + /** + * Maps a `digital` to the PROS enum equivalent. + */ + static pros::controller_digital_e_t digitalToProsEnum(ControllerDigital in); +}; +} // namespace okapi diff --git a/include/okapi/impl/device/distanceSensor.hpp b/include/okapi/impl/device/distanceSensor.hpp new file mode 100644 index 0000000..af2816a --- /dev/null +++ b/include/okapi/impl/device/distanceSensor.hpp @@ -0,0 +1,76 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +class DistanceSensor : public ControllerInput { + public: + /** + * A distance sensor on a V5 port. + * + * ```cpp + * auto ds = DistanceSensor(1); + * auto filteredDistSensor = DistanceSensor(1, std::make_unique>()); + * ``` + * + * @param iport The V5 port the device uses. + * @param ifilter The filter to use for filtering the distance measurements. + */ + DistanceSensor(std::uint8_t iport, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~DistanceSensor() = default; + + /** + * Get the current filtered sensor value in mm. + * + * @return The current filtered sensor value in mm. + */ + double get(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::DistanceSensor::get). + */ + double controllerGet() override; + + /** + * Get the confidence in the distance reading. This value has a range of ``[0, 63]``. ``63`` means + * high confidence, lower values imply less confidence. Confidence is only available when distance + * is greater than ``200`` mm. + * + * @return The confidence value in the range ``[0, 63]``. + */ + std::int32_t getConfidence() const; + + /** + * Get the current guess at relative object size. This value has a range of ``[0, 400]``. A 18" x + * 30" grey card will return a value of approximately ``75`` in typical room lighting. + * + * @return The size value in the range ``[0, 400]`` or ``PROS_ERR`` if the operation failed, + * setting errno. + */ + std::int32_t getObjectSize() const; + + /** + * Get the object velocity in m/s. + * + * @return The object velocity in m/s. + */ + double getObjectVelocity() const; + + protected: + std::uint8_t port; + std::unique_ptr filter; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/motor/adiMotor.hpp b/include/okapi/impl/device/motor/adiMotor.hpp new file mode 100644 index 0000000..f39bd41 --- /dev/null +++ b/include/okapi/impl/device/motor/adiMotor.hpp @@ -0,0 +1,69 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerOutput.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class ADIMotor : public ControllerOutput { + public: + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor('A'); + * auto reversedMtr = ADIMotor('A', true); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::uint8_t iport, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * A motor in an ADI port. + * + * ```cpp + * auto mtr = ADIMotor({1, 'A'}, false); + * auto reversedMtr = ADIMotor({1, 'A'}, true); + * ``` + * + * @param iports The ports the motor is plugged in to in the order ``{smart port, motor port}``. + * The smart port is the smart port number (``[1, 21]``). The motor port is the ADI port number + * (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param ireverse Whether the motor is reversed. + * @param logger The logger that initialization warnings will be logged to. + */ + ADIMotor(std::pair iports, + bool ireverse = false, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /** + * Set the voltage to the motor. + * + * @param ivoltage voltage in the range [-127, 127]. + */ + virtual void moveVoltage(std::int8_t ivoltage) const; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be [-1, 1]. + * + * @param ivalue the controller's output in the range [-1, 1] + */ + void controllerSet(double ivalue) override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; + std::int8_t reversed; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/motor/motor.hpp b/include/okapi/impl/device/motor/motor.hpp new file mode 100644 index 0000000..dd9cf0a --- /dev/null +++ b/include/okapi/impl/device/motor/motor.hpp @@ -0,0 +1,390 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" + +namespace okapi { +class Motor : public AbstractMotor { + public: + /** + * A V5 motor. + * + * @param iport The port number in the range ``[1, 21]``. A negative port number is shorthand for + * reversing the motor. + */ + Motor(std::int8_t iport); + + /** + * A V5 motor. + * + * @param iport The port number in the range [1, 21]. + * @param ireverse Whether the motor is reversed (this setting is not written to the motor, it is + * maintained by okapi::Motor instead). + * @param igearset The internal gearset to set in the motor. + * @param iencoderUnits The encoder units to set in the motor. + * @param logger The logger that initialization warnings will be logged to. + */ + Motor(std::uint8_t iport, + bool ireverse, + AbstractMotor::gearset igearset, + AbstractMotor::encoderUnits iencoderUnits, + const std::shared_ptr &logger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, no matter what the current + * position is. + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from -12000 to 12000. + * + * @param ivoltage The new voltage value from -12000 to 12000. + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or PROS_ERR_F if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR if the operation + * failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or PROS_ERR_F if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * @return The motor's efficiency in percent or PROS_ERR_F if the operation failed, setting errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @return 1 if the motor's current limit is being exceeded and 0 if the current limit is not + * exceeded, or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns PROS_ERR with errno set to ENOSYS. + * + * @return 1 if the motor is at zero absolute position, 0 if the motor has moved from its absolute + * zero, or PROS_ERR if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. 0b00000100 = Current Limit + * Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @param timestamp A pointer to a time in milliseconds for which the encoder count will be + * returned. If NULL, the timestamp at which the encoder count was read will not be supplied + * + * @return The raw encoder count at the given timestamp or PROS_ERR if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or PROS_ERR_F if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or PROS_ERR_F if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or PROS_ERR_F if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or PROS_ERR_F if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * @param imode The new motor brake mode to set for the motor + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * @param ilimit The new current limit in mA + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is 2500 mA. + * + * @return The motor's current limit in mA or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or gearset::invalid if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Get the encoder associated with this motor. + * + * @return The encoder for this motor. + */ + std::shared_ptr getEncoder() override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue The controller's output in the range `[-1, 1]`. + */ + void controllerSet(double ivalue) override; + + /** + * @return The port number. + */ + std::uint8_t getPort() const; + + /** + * @return Whether this motor is reversed. + */ + bool isReversed() const; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/motor/motorGroup.hpp b/include/okapi/impl/device/motor/motorGroup.hpp new file mode 100644 index 0000000..6187c4c --- /dev/null +++ b/include/okapi/impl/device/motor/motorGroup.hpp @@ -0,0 +1,400 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/util/logging.hpp" +#include "okapi/impl/device/motor/motor.hpp" +#include +#include + +namespace okapi { +class MotorGroup : public AbstractMotor { + public: + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * A group of V5 motors which act as one motor (i.e. they are mechanically linked). A MotorGroup + * requires at least one motor. If no motors are supplied, a `std::invalid_argument` exception is + * thrown. + * + * @param imotors The motors in this group. + * @param ilogger The logger this instance will log initialization warnings to. + */ + MotorGroup(const std::initializer_list> &imotors, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /******************************************************************************/ + /** Motor movement functions **/ + /** **/ + /** These functions allow programmers to make motors move **/ + /******************************************************************************/ + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with setZeroPosition(). + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The absolute position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveAbsolute(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor. Providing 10.0 as the position + * parameter would result in the motor moving clockwise 10 units, no matter what the current + * position is. + * + * @note This function simply sets the target for the motor, it does not block program execution + * until the movement finishes. + * + * @param iposition The relative position to move to in the motor's encoder units + * @param ivelocity The maximum allowable velocity for the movement in RPM + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveRelative(double iposition, std::int32_t ivelocity) override; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for pros::c::red, + * +-200 for green, and +-600 for blue. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the motor's + * voltage. + * + * @param ivelocity The new motor velocity from -+-100, +-200, or +-600 depending on the motor's + * gearset + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVelocity(std::int16_t ivelocity) override; + + /** + * Sets the voltage for the motor from `-12000` to `12000`. + * + * @param ivoltage The new voltage value from `-12000` to `12000`. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t moveVoltage(std::int16_t ivoltage) override; + + /** + * Changes the output velocity for a profiled movement (moveAbsolute or moveRelative). This will + * have no effect if the motor is not following a profiled movement. + * + * @param ivelocity The new motor velocity from `+-100`, `+-200`, or `+-600` depending on the + * motor's gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t modifyProfiledVelocity(std::int32_t ivelocity) override; + + /******************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** These functions allow programmers to collect telemetry from motors **/ + /******************************************************************************/ + + /** + * Gets the target position set for the motor by the user. + * + * @return The target position in its encoder units or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTargetPosition() override; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * @return The motor's absolute position in its encoder units or `PROS_ERR_F` if the operation + * failed, setting errno. + */ + double getPosition() override; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t tarePosition() override; + + /** + * Gets the velocity commanded to the motor by the user. + * + * @return The commanded motor velocity from +-100, +-200, or +-600, or `PROS_ERR` if the + * operation failed, setting errno. + */ + std::int32_t getTargetVelocity() override; + + /** + * Gets the actual velocity of the motor. + * + * @return The motor's actual velocity in RPM or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getActualVelocity() override; + + /** + * Gets the current drawn by the motor in mA. + * + * @return The motor's current in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentDraw() override; + + /** + * Gets the direction of movement for the motor. + * + * @return 1 for moving in the positive direction, -1 for moving in the negative direction, and + * `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getDirection() override; + + /** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * @return The motor's efficiency in percent or `PROS_ERR_F` if the operation failed, setting + * errno. + */ + double getEfficiency() override; + + /** + * Checks if the motor is drawing over its current limit. + * + * @return 1 if the motor's current limit is being exceeded and 0 if the current limit is not + * exceeded, or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t isOverCurrent() override; + + /** + * Checks if the motor's temperature is above its limit. + * + * @return 1 if the temperature limit is exceeded and 0 if the the temperature is below the limit, + * or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t isOverTemp() override; + + /** + * Checks if the motor is stopped. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is not moving, 0 if the motor is moving, or `PROS_ERR` if the operation + * failed, setting errno + */ + std::int32_t isStopped() override; + + /** + * Checks if the motor is at its zero position. + * + * Although this function forwards data from the motor, the motor presently does not provide any + * value. This function returns `PROS_ERR` with errno set to `ENOSYS`. + * + * @return 1 if the motor is at zero absolute position, `0` if the motor has moved from its + * absolute zero, or `PROS_ERR` if the operation failed, setting errno + */ + std::int32_t getZeroPositionFlag() override; + + /** + * Gets the faults experienced by the motor. Compare this bitfield to the bitmasks in + * pros::motor_fault_e_t. + * + * @return A currently unknown bitfield containing the motor's faults. `0b00000100` = Current + * Limit Hit + */ + uint32_t getFaults() override; + + /** + * Gets the flags set by the motor's operation. Compare this bitfield to the bitmasks in + * pros::motor_flag_e_t. + * + * @return A currently unknown bitfield containing the motor's flags. These seem to be unrelated + * to the individual get_specific_flag functions + */ + uint32_t getFlags() override; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * @param timestamp A pointer to a time in milliseconds for which the encoder count will be + * returned. If `NULL`, the timestamp at which the encoder count was read will not be supplied. + * @return The raw encoder count at the given timestamp or `PROS_ERR` if the operation failed. + */ + std::int32_t getRawPosition(std::uint32_t *timestamp) override; + + /** + * Gets the power drawn by the motor in Watts. + * + * @return The motor's power draw in Watts or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getPower() override; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * @return The motor's temperature in degrees Celsius or `PROS_ERR_F` if the operation failed, + * setting errno. + */ + double getTemperature() override; + + /** + * Gets the torque generated by the motor in Newton Metres (Nm). + * + * @return The motor's torque in NM or `PROS_ERR_F` if the operation failed, setting errno. + */ + double getTorque() override; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * @return The motor's voltage in V or `PROS_ERR_F` if the operation failed, setting errno. + */ + std::int32_t getVoltage() override; + + /******************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /******************************************************************************/ + + /** + * Sets one of AbstractMotor::brakeMode to the motor. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param imode The new motor brake mode to set for the motor. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setBrakeMode(AbstractMotor::brakeMode imode) override; + + /** + * Gets the brake mode that was set for the motor. + * + * @return One of brakeMode, according to what was set for the motor, or brakeMode::invalid if the + * operation failed, setting errno. + */ + brakeMode getBrakeMode() override; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the port. + * + * @param ilimit The new current limit in mA. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setCurrentLimit(std::int32_t ilimit) override; + + /** + * Gets the current limit for the motor in mA. The default value is `2500` mA. + * + * @return The motor's current limit in mA or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t getCurrentLimit() override; + + /** + * Sets one of AbstractMotor::encoderUnits for the motor encoder. + * + * @param iunits The new motor encoder units. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setEncoderUnits(AbstractMotor::encoderUnits iunits) override; + + /** + * Gets the encoder units that were set for the motor. + * + * @return One of encoderUnits according to what is set for the motor or encoderUnits::invalid if + * the operation failed. + */ + encoderUnits getEncoderUnits() override; + + /** + * Sets one of AbstractMotor::gearset for the motor. + * + * @param igearset The new motor gearset. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setGearing(AbstractMotor::gearset igearset) override; + + /** + * Gets the gearset that was set for the motor. + * + * @return One of gearset according to what is set for the motor, or `gearset::invalid` if the + * operation failed. + */ + gearset getGearing() override; + + /** + * Sets the reverse flag for the motor. This will invert its movements and the values returned for + * its position. + * + * @param ireverse True reverses the motor, false is default. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setReversed(bool ireverse) override; + + /** + * Sets the voltage limit for the motor in Volts. + * + * @param ilimit The new voltage limit in Volts. + * @return 1 if the operation was successful or `PROS_ERR` if the operation failed, setting errno. + */ + std::int32_t setVoltageLimit(std::int32_t ilimit) override; + + /** + * Writes the value of the controller output. This method might be automatically called in another + * thread by the controller. The range of input values is expected to be `[-1, 1]`. + * + * @param ivalue the controller's output in the range `[-1, 1]` + */ + void controllerSet(double ivalue) override; + + /** + * Gets the number of motors in the motor group. + * + * @return size_t + */ + size_t getSize(); + + /** + * Get the encoder associated with the first motor in this group. + * + * @return The encoder for the motor at index `0`. + */ + std::shared_ptr getEncoder() override; + + /** + * Get the encoder associated with this motor. + * + * @param index The index in `motors` to get the encoder from. + * @return The encoder for the motor at `index`. + */ + virtual std::shared_ptr getEncoder(std::size_t index); + + protected: + std::vector> motors; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/opticalSensor.hpp b/include/okapi/impl/device/opticalSensor.hpp new file mode 100644 index 0000000..6b8b0be --- /dev/null +++ b/include/okapi/impl/device/opticalSensor.hpp @@ -0,0 +1,140 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/filter/passthroughFilter.hpp" +#include + +namespace okapi { +enum class OpticalSensorOutput { + hue, ///< The color. + saturation, ///< The color's intensity relative to its brightness. + brightness ///< The amount of light. +}; + +class OpticalSensor : public ControllerInput { + public: + /** + * An optical sensor on a V5 port. + * + * ```cpp + * auto osHue = OpticalSensor(1); + * auto osSat = OpticalSensor(1, OpticalSensorOutput::saturation); + * ``` + * + * @param iport The V5 port the device uses. + * @param ioutput Which sensor output to return from (@ref okapi::OpticalSensor::get). + * @param idisableGestures Whether to automatically disable the gesture sensor. Typically, the + * gesture sensor should be disabled unless you are going to use gestures because the optical + * sensor does not update color information while detecting a gesture. + * @param ifilter The filter to use to filter the sensor output. Only the selected output (via + * ``ioutput``) is filtered; the other outputs are untouched. + */ + OpticalSensor(std::uint8_t iport, + OpticalSensorOutput ioutput = OpticalSensorOutput::hue, + bool idisableGestures = true, + std::unique_ptr ifilter = std::make_unique()); + + virtual ~OpticalSensor() = default; + + /** + * Get the current filtered value of the selected output (configured by the constructor). + * + * @return The current filtered value of the selected output (configured by the constructor). + */ + double get(); + + /** + * Get the current hue value in the range ``[0, 360)``. + * + * @return The current hue value in the range ``[0, 360)``. + */ + double getHue() const; + + /** + * Get the current brightness value in the range ``[0, 1]``. + * + * @return The current brightness value in the range ``[0, 1]``. + */ + double getBrightness() const; + + /** + * Get the current saturation value in the range ``[0, 1]``. + * + * @return The current saturation value in the range ``[0, 1]``. + */ + double getSaturation() const; + + /** + * Get the PWM value of the white LED in the range ``[0, 100]``. + * + * @return The PWM value of the white LED in the range ``[0, 100]`` or ``PROS_ERR`` if the + * operation failed, setting ``errno``. + */ + int32_t getLedPWM() const; + + /** + * Set the PWM value of the white LED in the range ``[0, 100]``. + * + * @param value The PWM value in the range ``[0, 100]``. + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t setLedPWM(std::uint8_t ivalue) const; + + /** + * Get the current proximity value in the range ``[0, 255]``. This is not available if gestures + * are being detected. + * + * @return The current proximity value in the range ``[0, 255]``. + */ + int32_t getProximity() const; + + /** + * Get the processed RGBC data from the sensor. + * + * @return The RGBC value if the operation was successful. If the operation failed, all field are + * set to ``PROS_ERR`` and ``errno`` is set. + */ + pros::c::optical_rgb_s_t getRGB() const; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::OpticalSensor::get). + */ + double controllerGet() override; + + /** + * Enable gestures. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t enableGestures() const; + + /** + * Disable gestures. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + int32_t disableGestures() const; + + protected: + std::uint8_t port; + OpticalSensorOutput output; + std::unique_ptr filter; + + /** + * Gets the output directly from the sensor using the selected output. + */ + double getSelectedOutput(); +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/IMU.hpp b/include/okapi/impl/device/rotarysensor/IMU.hpp new file mode 100644 index 0000000..98b97dc --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/IMU.hpp @@ -0,0 +1,109 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +enum class IMUAxes { + z, ///< Yaw Axis + y, ///< Pitch Axis + x ///< Roll Axis +}; + +class IMU : public ContinuousRotarySensor { + public: + /** + * An inertial sensor on the given port. The IMU returns an angle about the selected axis in + * degrees. + * + * ```cpp + * auto imuZ = IMU(1); + * auto imuX = IMU(1, IMUAxes::x); + * ``` + * + * @param iport The port number in the range ``[1, 21]``. + * @param iaxis The axis of the inertial sensor to measure, default `IMUAxes::z`. + */ + IMU(std::uint8_t iport, IMUAxes iaxis = IMUAxes::z); + + /** + * Get the current rotation about the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound The upper bound of the range. + * @param ilowerBound The lower bound of the range. + * @return The remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Get the current acceleration along the configured axis. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double getAcceleration() const; + + /** + * Reset the rotation value to zero. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t reset() override; + + /** + * Resets rotation value to desired value + * For example, ``reset(0)`` will reset the sensor to zero. + * But ``reset(90)`` will reset the sensor to 90 degrees. + * + * @param inewAngle desired reset value + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t reset(double inewAngle); + + /** + * Calibrate the IMU. Resets the rotation value to zero. Calibration is expected to take two + * seconds, but is bounded to five seconds. + * + * @return ``1`` or ``PROS_ERR``. + */ + std::int32_t calibrate(); + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double controllerGet() override; + + /** + * @return Whether the IMU is calibrating. + */ + bool isCalibrating() const; + + protected: + std::uint8_t port; + IMUAxes axis; + double offset = 0; + + /** + * Get the current rotation about the configured axis. The internal offset is not accounted for + * or modified. This just reads from the sensor. + * + * @return The current sensor value or ``PROS_ERR``. + */ + double readAngle() const; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/adiEncoder.hpp b/include/okapi/impl/device/rotarysensor/adiEncoder.hpp new file mode 100644 index 0000000..da2eb3b --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/adiEncoder.hpp @@ -0,0 +1,73 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIEncoder : public ContinuousRotarySensor { + public: + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder('A', 'B', false); + * auto reversedEnc = ADIEncoder('A', 'B', true); + * ``` + * + * @param iportTop The "top" wire from the encoder with the removable cover side up. This must be + * in port ``1``, ``3``, ``5``, or ``7`` (``A``, ``C``, ``E``, or ``G``). + * @param iportBottom The "bottom" wire from the encoder. This must be in port ``2``, ``4``, + * ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::uint8_t iportTop, std::uint8_t iportBottom, bool ireversed = false); + + /** + * An encoder in an ADI port. + * + * ```cpp + * auto enc = ADIEncoder({1, 'A', 'B'}, false); + * auto reversedEnc = ADIEncoder({1, 'A', 'B'}, true); + * ``` + * + * @param iports The ports the encoder is plugged in to in the order ``{smart port, top port, + * bottom port}``. The smart port is the smart port number (``[1, 21]``). The top port is the + * "top" wire from the encoder with the removable cover side up. This must be in port ``1``, + * ``3``, ``5``, or + * ``7`` (``A``, ``C``, ``E``, or ``G``). The bottom port is the "bottom" wire from the encoder. + * This must be in port ``2``, ``4``, ``6``, or ``8`` (``B``, ``D``, ``F``, or ``H``). + * @param ireversed Whether the encoder is reversed. + */ + ADIEncoder(std::tuple iports, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or `PROS_ERR` on a failure. + */ + virtual double controllerGet() override; + + protected: + pros::c::ext_adi_encoder_t enc; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/adiGyro.hpp b/include/okapi/impl/device/rotarysensor/adiGyro.hpp new file mode 100644 index 0000000..f8a34a7 --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/adiGyro.hpp @@ -0,0 +1,82 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/control/controllerInput.hpp" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class ADIGyro : public ContinuousRotarySensor { + public: + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are ``3600`` measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::uint8_t iport, double imultiplier = 1); + + /** + * A gyroscope on the given ADI port. If the port has not previously been configured as a gyro, + * then the constructor will block for 1 second for calibration. The gyro measures in tenths of a + * degree, so there are 3600 measurement points per revolution. + * + * ```cpp + * auto gyro = ADIGyro({1, 'A'}, 1); + * ``` + * + * Note to developers: Keep the default value on imultiplier so that users get an error if they do + * ADIGyro({1, 'A'}). Without it, this calls the non-ext-adi constructor. + * + * @param iports The ports the gyro is plugged in to in the order ``{smart port, gyro port}``. The + * smart port is the smart port number (``[1, 21]``). The gyro port is the ADI port number (``[1, + * 8]``, ``[a, h]``, ``[A, H]``). + * @param imultiplier A value multiplied by the gyro heading value. + */ + ADIGyro(std::pair iports, double imultiplier = 1); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double get() const override; + + /** + * Get the current sensor value remapped into the target range (``[-1800, 1800]`` by default). + * + * @param iupperBound the upper bound of the range. + * @param ilowerBound the lower bound of the range. + * @return the remapped sensor value. + */ + double getRemapped(double iupperBound = 1800, double ilowerBound = -1800) const; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + double controllerGet() override; + + protected: + pros::c::ext_adi_gyro_t gyro; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp b/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp new file mode 100644 index 0000000..8b3473b --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/integratedEncoder.hpp @@ -0,0 +1,56 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" +#include "okapi/impl/device/motor/motor.hpp" + +namespace okapi { +class IntegratedEncoder : public ContinuousRotarySensor { + public: + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param imotor The motor to use the encoder from. + */ + IntegratedEncoder(const okapi::Motor &imotor); + + /** + * Integrated motor encoder. Uses the encoder inside the V5 motor. + * + * @param iport The motor's port number in the range [1, 21]. + * @param ireversed Whether the encoder is reversed. + */ + IntegratedEncoder(std::int8_t iport, bool ireversed = false); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Reset the sensor to zero. + * + * @return `1` on success, `PROS_ERR` on fail + */ + virtual std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/potentiometer.hpp b/include/okapi/impl/device/rotarysensor/potentiometer.hpp new file mode 100644 index 0000000..7842c3f --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/potentiometer.hpp @@ -0,0 +1,57 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/rotarysensor/rotarySensor.hpp" + +namespace okapi { +class Potentiometer : public RotarySensor { + public: + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer('A'); + * ``` + * + * @param iport The ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::uint8_t iport); + + /** + * A potentiometer in an ADI port. + * + * ```cpp + * auto pot = Potentiometer({1, 'A'}); + * ``` + * + * @param iports The ports the potentiometer is plugged in to in the order ``{smart port, + * potentiometer port}``. The smart port is the smart port number (``[1, 21]``). The potentiometer + * port is the ADI port number (``[1, 8]``, ``[a, h]``, ``[A, H]``). + */ + Potentiometer(std::pair iports); + + /** + * Get the current sensor value. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double get() const override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return the current sensor value, or ``PROS_ERR`` on a failure. + */ + virtual double controllerGet() override; + + protected: + std::uint8_t smartPort; + std::uint8_t port; +}; +} // namespace okapi diff --git a/include/okapi/impl/device/rotarysensor/rotationSensor.hpp b/include/okapi/impl/device/rotarysensor/rotationSensor.hpp new file mode 100644 index 0000000..9e64541 --- /dev/null +++ b/include/okapi/impl/device/rotarysensor/rotationSensor.hpp @@ -0,0 +1,64 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "api.h" +#include "okapi/api/device/rotarysensor/continuousRotarySensor.hpp" + +namespace okapi { +class RotationSensor : public ContinuousRotarySensor { + public: + /** + * A rotation sensor in a V5 port. + * + * ```cpp + * auto r = RotationSensor(1); + * auto reversedR = RotationSensor(1, true); + * ``` + * + * @param iport The V5 port the device uses. + * @param ireversed Whether the sensor is reversed. This will set the reversed state in the + * kernel. + */ + RotationSensor(std::uint8_t iport, bool ireversed = false); + + /** + * Get the current rotation in degrees. + * + * @return The current rotation in degrees or ``PROS_ERR_F`` if the operation failed, setting + * ``errno``. + */ + double get() const override; + + /** + * Reset the sensor to zero. + * + * @return ``1`` if the operation was successful or ``PROS_ERR`` if the operation failed, setting + * ``errno``. + */ + std::int32_t reset() override; + + /** + * Get the sensor value for use in a control loop. This method might be automatically called in + * another thread by the controller. + * + * @return The same as [get](@ref okapi::RotationSensor::get). + */ + double controllerGet() override; + + /** + * Get the current rotational velocity estimate in degrees per second. + * + * @return The current rotational velocity estimate in degrees per second or ``PROS_ERR_F`` if the + * operation failed, setting ``errno``. + */ + double getVelocity() const; + + protected: + std::uint8_t port; + std::int8_t reversed{1}; +}; +} // namespace okapi diff --git a/include/okapi/impl/filter/velMathFactory.hpp b/include/okapi/impl/filter/velMathFactory.hpp new file mode 100644 index 0000000..af223d4 --- /dev/null +++ b/include/okapi/impl/filter/velMathFactory.hpp @@ -0,0 +1,68 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/filter/velMath.hpp" +#include + +namespace okapi { +class VelMathFactory { + public: + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. Averages the last two readings. + * + * @param iticksPerRev The number of ticks per revolution. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static VelMath create(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); + + /** + * Velocity math helper. Calculates filtered velocity. Throws a std::invalid_argument exception + * if iticksPerRev is zero. + * + * @param iticksPerRev The number of ticks per revolution. + * @param ifilter The filter used for filtering the calculated velocity. + * @param isampleTime The minimum time between samples. + * @param ilogger The logger this instance will log to. + */ + static std::unique_ptr + createPtr(double iticksPerRev, + std::unique_ptr ifilter, + QTime isampleTime = 0_ms, + const std::shared_ptr &ilogger = Logger::getDefaultLogger()); +}; +} // namespace okapi diff --git a/include/okapi/impl/util/configurableTimeUtilFactory.hpp b/include/okapi/impl/util/configurableTimeUtilFactory.hpp new file mode 100644 index 0000000..3775460 --- /dev/null +++ b/include/okapi/impl/util/configurableTimeUtilFactory.hpp @@ -0,0 +1,34 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/impl/util/timeUtilFactory.hpp" + +namespace okapi { +/** + * A TimeUtilFactory that supplies the SettledUtil parameters passed in the constructor to every + * new TimeUtil instance. + */ +class ConfigurableTimeUtilFactory : public TimeUtilFactory { + public: + ConfigurableTimeUtilFactory(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); + + /** + * Creates a TimeUtil with the SettledUtil parameters specified in the constructor by + * delegating to TimeUtilFactory::withSettledUtilParams. + * + * @return A TimeUtil with the SettledUtil parameters specified in the constructor. + */ + TimeUtil create() override; + + private: + double atTargetError; + double atTargetDerivative; + QTime atTargetTime; +}; +} // namespace okapi diff --git a/include/okapi/impl/util/rate.hpp b/include/okapi/impl/util/rate.hpp new file mode 100644 index 0000000..b76be72 --- /dev/null +++ b/include/okapi/impl/util/rate.hpp @@ -0,0 +1,42 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/util/abstractRate.hpp" + +namespace okapi { +class Rate : public AbstractRate { + public: + Rate(); + + /** + * Delay the current task such that it runs at the given frequency. The first delay will run for + * 1000/(ihz). Subsequent delays will adjust according to the previous runtime of the task. + * + * @param ihz the frequency + */ + void delay(QFrequency ihz) override; + + /** + * Delay the current task until itime has passed. This method can be used by periodic tasks to + * ensure a consistent execution frequency. + * + * @param itime the time period + */ + void delayUntil(QTime itime) override; + + /** + * Delay the current task until ims milliseconds have passed. This method can be used by + * periodic tasks to ensure a consistent execution frequency. + * + * @param ims the time period + */ + void delayUntil(uint32_t ims) override; + + protected: + std::uint32_t lastTime{0}; +}; +} // namespace okapi diff --git a/include/okapi/impl/util/timeUtilFactory.hpp b/include/okapi/impl/util/timeUtilFactory.hpp new file mode 100644 index 0000000..5d4f116 --- /dev/null +++ b/include/okapi/impl/util/timeUtilFactory.hpp @@ -0,0 +1,32 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/util/timeUtil.hpp" + +namespace okapi { +class TimeUtilFactory { + public: + virtual ~TimeUtilFactory() = default; + + /** + * Creates a default TimeUtil. + */ + virtual TimeUtil create(); + + /** + * Creates a default TimeUtil. + */ + static TimeUtil createDefault(); + + /** + * Creates a TimeUtil with custom SettledUtil params. See SettledUtil docs. + */ + static TimeUtil withSettledUtilParams(double iatTargetError = 50, + double iatTargetDerivative = 5, + const QTime &iatTargetTime = 250_ms); +}; +} // namespace okapi diff --git a/include/okapi/impl/util/timer.hpp b/include/okapi/impl/util/timer.hpp new file mode 100644 index 0000000..13d77c9 --- /dev/null +++ b/include/okapi/impl/util/timer.hpp @@ -0,0 +1,22 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "okapi/api/util/abstractTimer.hpp" + +namespace okapi { +class Timer : public AbstractTimer { + public: + Timer(); + + /** + * Returns the current time in units of QTime. + * + * @return the current time + */ + QTime millis() const override; +}; +} // namespace okapi diff --git a/include/okapi/squiggles/constraints.hpp b/include/okapi/squiggles/constraints.hpp new file mode 100644 index 0000000..f59089b --- /dev/null +++ b/include/okapi/squiggles/constraints.hpp @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_CONSTRAINTS_HPP_ +#define _SQUIGGLES_CONSTRAINTS_HPP_ + +#include +#include + +namespace squiggles { +struct Constraints { + /** + * Defines the motion constraints for a path. + * + * @param imax_vel The maximum allowable velocity for the robot in meters per + * second. + * @param imax_accel The maximum allowable acceleration for the robot in + * meters per second per second. + * @param imax_jerk The maximum allowable jerk for the robot in meters per + * second per second per second (m/s^3). + * @param imax_curvature The maximum allowable change in heading in radians + * per second. This is not set to the numeric limits by + * default as that will allow for wild paths. + * @param imin_accel The minimum allowable acceleration for the robot in + * meters per second per second. + */ + Constraints(double imax_vel, + double imax_accel = std::numeric_limits::max(), + double imax_jerk = std::numeric_limits::max(), + double imax_curvature = 1000, + double imin_accel = std::nan("")) + : max_vel(imax_vel), + max_accel(imax_accel), + max_jerk(imax_jerk), + max_curvature(imax_curvature) { + if (imax_accel == std::numeric_limits::max()) { + min_accel = std::numeric_limits::lowest(); + } else { + min_accel = std::isnan(imin_accel) ? -imax_accel : imin_accel; + } + } + + /** + * Serializes the Constraints data for debugging. + * + * @return The Constraints data. + */ + std::string to_string() const { + return "Constraints: {max_vel: " + std::to_string(max_vel) + + ", max_accel: " + std::to_string(max_accel) + + ", max_jerk: " + std::to_string(max_jerk) + + ", min_accel: " + std::to_string(min_accel) + "}"; + } + + double max_vel; + double max_accel; + double max_jerk; + double min_accel; + double max_curvature; +}; +} // namespace squiggles +#endif diff --git a/include/okapi/squiggles/geometry/controlvector.hpp b/include/okapi/squiggles/geometry/controlvector.hpp new file mode 100644 index 0000000..c279bd4 --- /dev/null +++ b/include/okapi/squiggles/geometry/controlvector.hpp @@ -0,0 +1,62 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_CONTROL_VECTOR_HPP_ +#define _GEOMETRY_CONTROL_VECTOR_HPP_ + +#include +#include + +#include "pose.hpp" + +namespace squiggles { +class ControlVector { + public: + /** + * A vector used to specify a state along a hermite spline. + * + * @param ipose The 2D position and heading. + * @param ivel The velocity component of the vector. + * @param iaccel The acceleration component of the vector. + * @param ijerk The jerk component of the vector. + */ + ControlVector(Pose ipose, + double ivel = std::nan(""), + double iaccel = 0.0, + double ijerk = 0.0) + : pose(ipose), vel(ivel), accel(iaccel), jerk(ijerk) {} + + ControlVector() = default; + + /** + * Serializes the Control Vector data for debugging. + * + * @return The Control Vector data. + */ + std::string to_string() const { + return "ControlVector: {" + pose.to_string() + + ", v: " + std::to_string(vel) + ", a: " + std::to_string(accel) + + ", j: " + std::to_string(jerk) + "}"; + } + + std::string to_csv() const { + return pose.to_csv() + "," + std::to_string(vel) + "," + + std::to_string(accel) + "," + std::to_string(jerk); + } + + bool operator==(const ControlVector& other) const { + return pose == other.pose && nearly_equal(vel, other.vel) && + nearly_equal(accel, other.accel) && nearly_equal(jerk, other.jerk); + } + + Pose pose; + double vel; + double accel; + double jerk; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/geometry/pose.hpp b/include/okapi/squiggles/geometry/pose.hpp new file mode 100644 index 0000000..b3b7690 --- /dev/null +++ b/include/okapi/squiggles/geometry/pose.hpp @@ -0,0 +1,67 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_POSE_HPP_ +#define _GEOMETRY_POSE_HPP_ + +#include +#include + +#include "math/utils.hpp" + +namespace squiggles { +class Pose { + public: + /** + * Specifies a point and heading in 2D space. + * + * @param ix The x position of the point in meters. + * @param iy The y position of the point in meters. + * @param iyaw The heading at the point in radians. + */ + Pose(double ix, double iy, double iyaw) : x(ix), y(iy), yaw(iyaw) {} + + Pose() = default; + + /** + * Calculates the Euclidean distance between this pose and another. + * + * @param other The point from which the distance will be calculated. + * + * @return The distance between this pose and Other. + */ + double dist(const Pose& other) const { + return std::sqrt((x - other.x) * (x - other.x) + + (y - other.y) * (y - other.y)); + } + + /** + * Serializes the Pose data for debugging. + * + * @return The Pose data. + */ + std::string to_string() const { + return "Pose: {x: " + std::to_string(x) + ", y: " + std::to_string(y) + + ", yaw: " + std::to_string(yaw) + "}"; + } + + std::string to_csv() const { + return std::to_string(x) + "," + std::to_string(y) + "," + + std::to_string(yaw); + } + + bool operator==(const Pose& other) const { + return nearly_equal(x, other.x) && nearly_equal(y, other.y) && + nearly_equal(yaw, other.yaw); + } + + double x; + double y; + double yaw; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/geometry/profilepoint.hpp b/include/okapi/squiggles/geometry/profilepoint.hpp new file mode 100644 index 0000000..e6eed09 --- /dev/null +++ b/include/okapi/squiggles/geometry/profilepoint.hpp @@ -0,0 +1,100 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _GEOMETRY_PROFILE_POINT_HPP_ +#define _GEOMETRY_PROFILE_POINT_HPP_ + +#include +#include +#include + +#include "controlvector.hpp" +#include "math/utils.hpp" + +namespace squiggles { +struct ProfilePoint { + /** + * Defines a state along a motion profiled path. + * + * @param ivector The pose and associated dynamics at this state in the path. + * @param iwheel_velocities The component of the robot's velocity provided by + * each wheel in meters per second. + * @param icurvature The degree to which the curve deviates from a straight + * line at this point in 1 / meters. + * @param itime The timestamp for this state relative to the start of the + * path in seconds. + */ + ProfilePoint(ControlVector ivector, + std::vector iwheel_velocities, + double icurvature, + double itime) + : vector(ivector), + wheel_velocities(iwheel_velocities), + curvature(icurvature), + time(itime) {} + + ProfilePoint() = default; + + /** + * Serializes the Profile Point data for debugging. + * + * @return The Profile Point data. + */ + std::string to_string() const { + std::string wheels = "{"; + for (auto& w : wheel_velocities) { + wheels += std::to_string(w); + wheels += ", "; + } + wheels += "}"; + return "ProfilePoint: {" + vector.to_string() + ", wheels: " + wheels + + ", k: " + std::to_string(curvature) + + ", t: " + std::to_string(time) + "}"; + } + + std::string to_csv() const { + std::string wheels = ""; + for (auto& w : wheel_velocities) { + wheels += ","; + wheels += std::to_string(w); + } + return vector.to_csv() + "," + std::to_string(curvature) + "," + + std::to_string(time) + wheels; + } + + bool operator==(const ProfilePoint& other) const { + for (std::size_t i = 0; i < wheel_velocities.size(); ++i) { + if (!nearly_equal(wheel_velocities[i], other.wheel_velocities[i])) { + return false; + } + } + return vector == other.vector && nearly_equal(curvature, other.curvature) && + nearly_equal(time, other.time); + } + + friend std::ostream& operator<<(std::ostream& os, const ProfilePoint& p) { + return os << "ProfilePoint(ControlVector(Pose(" + + std::to_string(p.vector.pose.x) + "," + + std::to_string(p.vector.pose.y) + "," + + std::to_string(p.vector.pose.yaw) + ")," + + std::to_string(p.vector.vel) + "," + + std::to_string(p.vector.accel) + "," + + std::to_string(p.vector.jerk) + "),{" + + std::to_string(p.wheel_velocities[0]) + "," + + std::to_string(p.wheel_velocities[1]) + "}," + + std::to_string(p.curvature) + "," + std::to_string(p.time) + + "),"; + // return os << p.to_string(); + } + + ControlVector vector; + std::vector wheel_velocities; + double curvature; + double time; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/io.hpp b/include/okapi/squiggles/io.hpp new file mode 100644 index 0000000..c22ed97 --- /dev/null +++ b/include/okapi/squiggles/io.hpp @@ -0,0 +1,56 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_IO_HPP_ +#define _SQUIGGLES_IO_HPP_ + +#include +#include + +#include "geometry/profilepoint.hpp" + +namespace squiggles { +/** + * Writes the path data to a CSV file. + * + * @param out The output stream to write the CSV data to. This is usually a + * file. + * @param path The path to serialized + * + * @return 0 if the path was serialized succesfully or -1 if an error occurred. + */ +int serialize_path(std::ostream& out, std::vector path); + +/** + * Converts CSV data into a path. + * + * @param in The input stream containing the CSV data. This is usually a file. + * + * @return The path specified by the CSV data or std::nullopt if de-serializing + * the path was unsuccessful. + */ +std::optional> deserialize_path(std::istream& in); + +/** + * Converts CSV data from the Pathfinder library's format to a Squiggles path. + * + * NOTE: this code translates data from Jaci Brunning's Pathfinder library. + * The source for that library can be found at: + * https://github.com/JaciBrunning/Pathfinder/ + * + * @param left The input stream containing the left wheels' CSV data. This is + * usually a file. + * @param right The input stream containing the right wheels' CSV data. This is + * usually a file. + * + * @return The path specified by the CSV data or std::nullopt if de-serializing + * the path was unsuccessful. + */ +std::optional> +deserialize_pathfinder_path(std::istream& left, std::istream& right); +} // namespace squiggles + +#endif diff --git a/include/okapi/squiggles/math/quinticpolynomial.hpp b/include/okapi/squiggles/math/quinticpolynomial.hpp new file mode 100644 index 0000000..f12580f --- /dev/null +++ b/include/okapi/squiggles/math/quinticpolynomial.hpp @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _MATH_QUINTIC_POLYNOMIAL_HPP_ +#define _MATH_QUINTIC_POLYNOMIAL_HPP_ + +#include + +namespace squiggles { +class QuinticPolynomial { + public: + /** + * Defines the polynomial function for a spline in one dimension. + * + * @param s_p The starting position of the curve in meters. + * @param s_v The starting velocity of the curve in meters per second. + * @param s_a The starting acceleration of the curve in meters per second per + * second. + * @param g_p The goal or ending position of the curve in meters. + * @param g_v The goal or ending velocity of the curve in meters per second. + * @param g_a The goal or ending acceleration of the curve in meters per + * second per second. + * @param t The desired duration for the curve in seconds. + */ + QuinticPolynomial(double s_p, + double s_v, + double s_a, + double g_p, + double g_v, + double g_a, + double t); + + /** + * Calculates the values of the polynomial and its derivatives at the given + * time stamp. + */ + double calc_point(double t); + double calc_first_derivative(double t); + double calc_second_derivative(double t); + double calc_third_derivative(double t); + + /** + * Serializes the Quintic Polynomial data for debugging. + * + * @return The Quintic Polynomial data. + */ + std::string to_string() const { + return "QuinticPolynomial: {0: " + std::to_string(a0) + + " 1: " + std::to_string(a1) + " 2: " + std::to_string(a2) + + " 3: " + std::to_string(a3) + " 4: " + std::to_string(a4) + + " 5: " + std::to_string(a5) + "}"; + } + + protected: + /** + * The coefficients for each term of the polynomial. + */ + double a0, a1, a2, a3, a4, a5; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/math/utils.hpp b/include/okapi/squiggles/math/utils.hpp new file mode 100644 index 0000000..cca3da0 --- /dev/null +++ b/include/okapi/squiggles/math/utils.hpp @@ -0,0 +1,61 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _MATH_UTILS_HPP_ +#define _MATH_UTILS_HPP_ + +#include +#include + +namespace squiggles { +/** + * Returns the sign value of the given value. + * + * @return 1 if the value is positive, -1 if the value is negative, and 0 if + * the value is 0. + */ +template inline int sgn(T v) { + return (v > T(0)) - (v < T(0)); +} + +inline bool +nearly_equal(const double& a, const double& b, double epsilon = 1e-5) { + return std::fabs(a - b) < epsilon; +} +} // namespace squiggles + +namespace std { +// Copied from https://github.com/emsr/cxx_linear +template +constexpr std::enable_if_t< + std::is_floating_point_v<_Float> && + __cplusplus <= 201703L, // Only defines this function if C++ standard < 20 + _Float> +lerp(_Float __a, _Float __b, _Float __t) { + if (std::isnan(__a) || std::isnan(__b) || std::isnan(__t)) + return std::numeric_limits<_Float>::quiet_NaN(); + else if ((__a <= _Float{0} && __b >= _Float{0}) || + (__a >= _Float{0} && __b <= _Float{0})) + // ab <= 0 but product could overflow. +#ifndef FMA + return __t * __b + (_Float{1} - __t) * __a; +#else + return std::fma(__t, __b, (_Float{1} - __t) * __a); +#endif + else if (__t == _Float{1}) + return __b; + else { // monotonic near t == 1. +#ifndef FMA + const auto __x = __a + __t * (__b - __a); +#else + const auto __x = std::fma(__t, __b - __a, __a); +#endif + return (__t > _Float{1}) == (__b > __a) ? std::max(__b, __x) + : std::min(__b, __x); + } +} +} // namespace std +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/physicalmodel/passthroughmodel.hpp b/include/okapi/squiggles/physicalmodel/passthroughmodel.hpp new file mode 100644 index 0000000..1db2a17 --- /dev/null +++ b/include/okapi/squiggles/physicalmodel/passthroughmodel.hpp @@ -0,0 +1,38 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ +#define _PHYSICAL_MODEL_PASSTHROUGH_MODEL_HPP_ + +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class PassthroughModel : public PhysicalModel { + public: + /** + * Defines a Physical Model that imposes no constraints of its own. + */ + PassthroughModel() = default; + + Constraints constraints([[maybe_unused]] const Pose pose, + [[maybe_unused]] double curvature, + double vel) override { + return Constraints(vel); + }; + + std::vector + linear_to_wheel_vels([[maybe_unused]] double lin_vel, + [[maybe_unused]] double curvature) override { + return std::vector{}; + } + + std::string to_string() const override { + return "PassthroughModel {}"; + } +}; +} // namespace squiggles + +#endif diff --git a/include/okapi/squiggles/physicalmodel/physicalmodel.hpp b/include/okapi/squiggles/physicalmodel/physicalmodel.hpp new file mode 100644 index 0000000..5c22a4c --- /dev/null +++ b/include/okapi/squiggles/physicalmodel/physicalmodel.hpp @@ -0,0 +1,43 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ +#define _PHYSICAL_MODEL_PHYSICAL_MODEL_HPP_ + +#include "constraints.hpp" +#include "geometry/pose.hpp" + +namespace squiggles { +class PhysicalModel { + public: + /** + * Calculate a set of stricter constraints for the path at the given state + * than the general constraints based on the robot's kinematics. + * + * @param pose The 2D pose for this state in the path. + * @param curvature The change in heading at this state in the path in 1 / + * meters. + * @param vel The linear velocity at this state in the path in meters per + * second. + */ + virtual Constraints + constraints(const Pose pose, double curvature, double vel) = 0; + + /** + * Converts a linear velocity and desired curvature into the component for + * each wheel of the robot. + * + * @param linear The linear velocity for the robot in meters per second. + * @param curvature The change in heading for the robot in 1 / meters. + */ + virtual std::vector linear_to_wheel_vels(double linear, + double curvature) = 0; + + virtual std::string to_string() const = 0; +}; +} // namespace squiggles + +#endif diff --git a/include/okapi/squiggles/physicalmodel/tankmodel.hpp b/include/okapi/squiggles/physicalmodel/tankmodel.hpp new file mode 100644 index 0000000..9f0709b --- /dev/null +++ b/include/okapi/squiggles/physicalmodel/tankmodel.hpp @@ -0,0 +1,45 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _PHYSICAL_MODEL_TANK_MODEL_HPP_ +#define _PHYSICAL_MODEL_TANK_MODEL_HPP_ + +#include +#include + +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class TankModel : public PhysicalModel { + public: + /** + * Defines a model of a tank drive or differential drive robot. + * + * @param itrack_width The distance between the the wheels on each side of the + * robot in meters. + * @param ilinear_constraints The maximum values for the robot's movement. + */ + TankModel(double itrack_width, Constraints ilinear_constraints); + + Constraints + constraints(const Pose pose, double curvature, double vel) override; + + std::vector linear_to_wheel_vels(double lin_vel, + double curvature) override; + + std::string to_string() const override; + + private: + double vel_constraint(const Pose pose, double curvature, double vel); + std::tuple + accel_constraint(const Pose pose, double curvature, double vel) const; + + double track_width; + Constraints linear_constraints; +}; +} // namespace squiggles + +#endif \ No newline at end of file diff --git a/include/okapi/squiggles/spline.hpp b/include/okapi/squiggles/spline.hpp new file mode 100644 index 0000000..4ee5991 --- /dev/null +++ b/include/okapi/squiggles/spline.hpp @@ -0,0 +1,310 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _SQUIGGLES_SPLINE_HPP_ +#define _SQUIGGLES_SPLINE_HPP_ + +#include +#include +#include + +#include "constraints.hpp" +#include "geometry/controlvector.hpp" +#include "geometry/profilepoint.hpp" +#include "math/quinticpolynomial.hpp" +#include "physicalmodel/passthroughmodel.hpp" +#include "physicalmodel/physicalmodel.hpp" + +namespace squiggles { +class SplineGenerator { + public: + /** + * Generates curves that match the given motion constraints. + * + * @param iconstraints The maximum allowable values for the robot's motion. + * @param imodel The robot's physical characteristics and constraints + * @param idt The difference in time in seconds between each state for the + * generated paths. + */ + SplineGenerator(Constraints iconstraints, + std::shared_ptr imodel = + std::make_shared(), + double idt = 0.1); + + /** + * Creates a motion profiled path between the given waypoints. + * + * @param iwaypoints The list of poses that the robot should reach along the + * path. + * @param fast If true, the path optimization process will stop as soon as the + * constraints are met. If false, the optimizer will find the + * smoothest possible path between the points. + * + * @return A series of robot states defining a path between the poses. + */ + std::vector generate(std::vector iwaypoints, + bool fast = false); + std::vector generate(std::initializer_list iwaypoints, + bool fast = false); + + /** + * Creates a motion profiled path between the given waypoints. + * + * @param iwaypoints The list of vectors that the robot should reach along the + * path. + * + * @return A series of robot states defining a path between the vectors. + */ + std::vector generate(std::vector iwaypoints); + std::vector + generate(std::initializer_list iwaypoints); + + protected: + /** + * The maximum allowable values for the robot's motion. + */ + Constraints constraints; + + /** + * Defines the physical structure of the robot and translates the linear + * kinematics to wheel velocities. + */ + std::shared_ptr model; + + /** + * The time difference between each value in the generated path. + */ + double dt; + + /** + * The minimum and maximum durations for a path to take. A larger range allows + * for longer possible paths at the expense of a longer path generation time. + */ + const int T_MIN = 2; + const int T_MAX = 15; + const int MAX_GRAD_DESCENT_ITERATIONS = 10; + + /** + * This is factor is used to create a "dummy velocity" in the initial path + * generation step one or both of the preferred start or end velocities is + * zero. The velocity will be replaced with the preferred start/end velocity + * in parameterization but a nonzero velocity is needed for the spline + * calculation. + * + * This was 1.2 in the WPILib example but that large of a value seems to + * create wild paths, 0.12 worked better in testing with VEX-sized paths. + */ + public: + const double K_DEFAULT_VEL = 1.0; + + /** + * The output of the initial, "naive" generation step. We discard the + * derivative values to replace them with values from a motion profile. + */ + + struct GeneratedPoint { + GeneratedPoint(Pose ipose, double icurvature = 0.0) + : pose(ipose), curvature(icurvature) {} + + std::string to_string() const { + return "GeneratedPoint: {" + pose.to_string() + + ", curvature: " + std::to_string(curvature) + "}"; + } + + Pose pose; + double curvature; + }; + + /** + * An intermediate value used in the "naive" generation step. Contains the + * final GeneratedPoint value that will be returned as well as the spline's + * derivative values to perform the initial check against the constraints. + */ + struct GeneratedVector { + GeneratedVector(GeneratedPoint ipoint, + double ivel, + double iaccel, + double ijerk) + : point(ipoint), vel(ivel), accel(iaccel), jerk(ijerk) {} + + GeneratedPoint point; + double vel; + double accel; + double jerk; + + std::string to_string() const { + return "GeneratedVector: {" + point.to_string() + + ", vel: " + std::to_string(vel) + + ", accel: " + std::to_string(accel) + + ", jerk: " + std::to_string(jerk) + "}"; + } + }; + + std::vector gen_single_raw_path(ControlVector start, + ControlVector end, + int duration, + double start_vel, + double end_vel); + /** + * Runs a Gradient Descent algorithm to minimize the linear acceleration, + * linear jerk, and curvature for the generated path. + * + * This is used when there is not a start/end velocity specified for a given + * path. + */ + std::vector + gradient_descent(ControlVector& start, ControlVector& end, bool fast); + + /** + * An intermediate value used in the parameterization step. Adds the + * constrained values from the motion profile to the output from the "naive" + * generation step. + */ + struct ConstrainedState { + ConstrainedState(Pose ipose, + double icurvature, + double idistance, + double imax_vel, + double imin_accel, + double imax_accel) + : pose(ipose), + curvature(icurvature), + distance(idistance), + max_vel(imax_vel), + min_accel(imin_accel), + max_accel(imax_accel) {} + + ConstrainedState() = default; + + Pose pose = Pose(); + double curvature = 0; + double distance = 0; + double max_vel = 0; + double min_accel = 0; + double max_accel = 0; + + std::string to_string() const { + return "ConstrainedState: {x: " + std::to_string(pose.x) + + ", y: " + std::to_string(pose.y) + + ", yaw: " + std::to_string(pose.yaw) + + ", k: " + std::to_string(curvature) + + ", dist: " + std::to_string(distance) + + ", v: " + std::to_string(max_vel) + + ", min_a: " + std::to_string(min_accel) + + ", max_a: " + std::to_string(max_accel) + "}"; + } + }; + + /** + * The actual function called by the "generate" functions. + * + * @param start An iterator pointing to the first ControlVector in the path + * @param end An iterator pointting to the last ControlVector in the path + * + * @return The points from each path concatenated together + */ + template + std::vector _generate(Iter start, Iter end, bool fast); + + public: + /** + * Performs the "naive" generation step. + * + * This step calculates the spline polynomials that fit within the + * SplineGenerator's acceleration and jerk constraints and returns the points + * that form the curve. + */ + std::vector + gen_raw_path(ControlVector& start, ControlVector& end, bool fast); + + /** + * Imposes a linear motion profile on the raw path. + * + * This step creates the velocity and acceleration values to command the robot + * at each point along the curve. + */ + std::vector + parameterize(const ControlVector start, + const ControlVector end, + const std::vector& raw_path, + const double preferred_start_vel, + const double preferred_end_vel, + const double start_time); + + /** + * Finds the new timestamps for each point along the curve based on the motion + * profile. + */ + std::vector + integrate_constrained_states(std::vector constrainedStates); + + /** + * Finds the ProfilePoint on the profiled curve for the given timestamp. + * + * This with interpolate between points on the curve if a point with an exact + * matching timestamp is not found. + */ + ProfilePoint get_point_at_time(const ControlVector start, + const ControlVector end, + std::vector points, + double t); + + /** + * Linearly interpolates between points along the profiled curve. + */ + ProfilePoint lerp_point(QuinticPolynomial x_qp, + QuinticPolynomial y_qp, + ProfilePoint start, + ProfilePoint end, + double i); + + /** + * Returns the spline curve for the given control vectors and path duration. + */ + QuinticPolynomial get_x_spline(const ControlVector start, + const ControlVector end, + const double duration); + QuinticPolynomial get_y_spline(const ControlVector start, + const ControlVector end, + const double duration); + + /** + * Applies the general constraints and model constraints to the given state. + */ + void enforce_accel_lims(ConstrainedState* state); + + /** + * Imposes the motion profile constraints on a segment of the path from the + * perspective of iterating forwards through the path. + */ + void forward_pass(ConstrainedState* predecessor, ConstrainedState* successor); + + /** + * Imposes the motion profile constraints on a segment of the path from the + * perspective of iterating backwards through the path. + */ + void backward_pass(ConstrainedState* predecessor, + ConstrainedState* successor); + + /** + * Calculates the final velocity for a path segment. + */ + double vf(double vi, double a, double ds); + + /** + * Calculates the initial acceleration needed to match the segments' + * velocities. + */ + double ai(double vf, double vi, double s); + + /** + * Values that are closer to each other than this value are considered equal. + */ + static constexpr double K_EPSILON = 1e-5; +}; +} // namespace squiggles + +#endif diff --git a/include/okapi/squiggles/squiggles.hpp b/include/okapi/squiggles/squiggles.hpp new file mode 100644 index 0000000..86c1bfa --- /dev/null +++ b/include/okapi/squiggles/squiggles.hpp @@ -0,0 +1,22 @@ +/** + * Copyright 2020 Jonathan Bayless + * + * Use of this source code is governed by an MIT-style license that can be found + * in the LICENSE file or at https://opensource.org/licenses/MIT. + */ +#ifndef _ROBOT_SQUIGGLES_H_ +#define _ROBOT_SQUIGGLES_H_ + +#include "geometry/controlvector.hpp" +#include "geometry/pose.hpp" +#include "geometry/profilepoint.hpp" + +#include "physicalmodel/passthroughmodel.hpp" +#include "physicalmodel/physicalmodel.hpp" +#include "physicalmodel/tankmodel.hpp" + +#include "constraints.hpp" +#include "io.hpp" +#include "spline.hpp" + +#endif \ No newline at end of file diff --git a/include/pros/abstract_motor.hpp b/include/pros/abstract_motor.hpp new file mode 100644 index 0000000..1468f35 --- /dev/null +++ b/include/pros/abstract_motor.hpp @@ -0,0 +1,1163 @@ +/** + * \file abstract_motor.hpp + * \ingroup cpp-abstract-motor + * + * Contains prototypes for AbstractMotor, the abstract base class of both + * motors and motor groups. Abstract motors cannot be directly constructed, but + * you can use motors and motor groups as abstract motors. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef _PROS_ABSTRACT_MOTORS_HPP_ +#define _PROS_ABSTRACT_MOTORS_HPP_ + +#include +#include + +#include "pros/device.hpp" +#include "pros/motors.h" +#include "rtos.hpp" + +namespace pros { +inline namespace v5 { + +/** + * \enum motor_brake + * Indicates the current 'brake mode' of a motor. + */ +enum class MotorBrake { + coast = 0, ///< Motor coasts when stopped, traditional behavior + brake = 1, ///< Motor brakes when stopped + hold = 2, ///< Motor actively holds position when stopped + invalid = INT32_MAX ///< Invalid brake mode +}; + +/** + * \enum Motor_Encoder_Units + * Indicates the units used by the motor encoders. + */ +enum class MotorEncoderUnits { + degrees = 0, ///< Position is recorded as angle in degrees as a floating point number + deg = 0, ///< Position is recorded as angle in degrees as a floating point number + rotations = 1, ///< Position is recorded as angle in rotations as a floating point number + counts = 2, ///< Position is recorded as raw encoder ticks as a whole number + invalid = INT32_MAX ///< Invalid motor encoder units +}; + +// Alias for Motor_Encoder_Units +using MotorUnits = MotorEncoderUnits; + +enum class MotorGears { + ratio_36_to_1 = 0, ///< 36:1, 100 RPM, Red gear set + red = ratio_36_to_1, ///< 36:1, 100 RPM, Red gear set + rpm_100 = ratio_36_to_1, ///< 36:1, 100 RPM, Red gear set + ratio_18_to_1 = 1, ///< 18:1, 200 RPM, Green gear set + green = ratio_18_to_1, ///< 18:1, 200 RPM, Green gear set + rpm_200 = ratio_18_to_1, ///< 18:1, 200 RPM, Green gear set + ratio_6_to_1 = 2, ///< 6:1, 600 RPM, Blue gear set + blue = ratio_6_to_1, ///< 6:1, 600 RPM, Blue gear set + rpm_600 = ratio_6_to_1, ///< 6:1, 600 RPM, Blue gear set + invalid = INT32_MAX ///< Error return code +}; + + +// Provide Aliases for Motor_Gears +using MotorGearset = MotorGears; +using MotorCart = MotorGears; +using MotorCartridge = MotorGears; +using MotorGear = MotorGears; + +/** + * \ingroup cpp-abstract-motor + */ +class AbstractMotor { + /** + * \addtogroup cpp-abstract-motor + * @{ + */ + public: + /// \name Motor movement functions + /// These functions allow programmers to make motors move + ///@{ + + /** + * Sets the voltage for the motor from -127 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of pros::Motor::move(). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param voltage + * The new motor voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t operator=(std::int32_t voltage) const = 0; + + /** + * Sets the voltage for the motor from -127 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of motor_move(), or motorSet() from the PROS 2 API. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param voltage + * The new motor voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move(std::int32_t voltage) const = 0; + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_absolute(const double position, const std::int32_t velocity) const = 0; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor as given in + * pros::Motor::motor_get_position(). Providing 10.0 as the position parameter + * would result in the motor moving clockwise 10 units, no matter what the + * current position is. + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_relative(const double position, const std::int32_t velocity) const = 0; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from -+-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_velocity(const std::int32_t velocity) const = 0; + + /** + * Sets the output voltage for the motor from -12000 to 12000 in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1-21 + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t move_voltage(const std::int32_t voltage) const = 0; + + /** + * Stops the motor using the currently configured brake mode. + * + * This function sets motor velocity to zero, which will cause it to act + * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, + * this function may behave differently than calling move_absolute(0) + * or motor_move_relative(0). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + */ + virtual std::int32_t brake(void) const = 0; + + /** + * Changes the output velocity for a profiled movement (motor_move_absolute or + * motor_move_relative). This will have no effect if the motor is not following + * a profiled movement. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t modify_profiled_velocity(const std::int32_t velocity) const = 0; + + /** + * Gets the target position set for the motor by the user, with a parameter + * for the motor index. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_target_position(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the target position(s) set for the motor(s) by the user + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing the target position(s) in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual std::vector get_target_position_all(void) const = 0; + + /** + * Gets the velocity commanded to the motor by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_target_velocity(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the velocity/velocities commanded to the motor(s) by the user + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the commanded motor velocity/velocities from +-100, + * +-200, or +-600, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::vector get_target_velocity_all(void) const = 0; + + ///@} + + /// \name Motor telemetry functions + /// \addtogroup cpp-motor-telemetry + /// These functions allow programmers to collect telemetry from motors + ///@{ + + /** + * Gets the actual velocity of the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_actual_velocity(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the actual velocity/velocities of the motor(s) + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's/motors' actual velocity/velocities in RPM or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual std::vector get_actual_velocity_all(void) const = 0; + + /** + * Gets the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_draw(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the current(s) drawn by the motor(s) in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector conatining the motor's/motors' current(s) in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::vector get_current_draw_all(void) const = 0; + + /** + * Gets the direction of movement for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t get_direction(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the direction(s) of movement for the motor(s). + * + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + */ + virtual std::vector get_direction_all(void) const = 0; + + /** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_efficiency(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the efficiency/efficiencies of the motor(s) in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing the motor's/motors' efficiency/efficiencies in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual std::vector get_efficiency_all(void) const = 0; + + /** + * Gets the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A bitfield containing the motor's faults. + */ + virtual std::uint32_t get_faults(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the faults experienced by the motor(s). + * + * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \return A bitfield containing the motor's/motors' faults. + */ + virtual std::vector get_faults_all(void) const = 0; + /** + * Gets the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A bitfield containing the motor's flags. + */ + virtual std::uint32_t get_flags(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the flags set by the motor's/motors' operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A bitfield containing the motor's/motors' flags. + */ + virtual std::vector get_flags_all(void) const = 0; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual double get_position(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the absolute position(s) of the motor(s) in its encoder units. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + + * + * \return A vector containing the motor's/motors' absolute position(s) in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual std::vector get_position_all(void) const = 0; + + /** + * Gets the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_power(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector containing the power(s) drawn by the motor(s) in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's/motors' power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual std::vector get_power_all(void) const = 0; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param[in] timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + */ + virtual std::int32_t get_raw_position(std::uint32_t* const timestamp, const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the raw encoder count(s) of the motor(s) at a given timestamp. + * + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \param timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \return A vector containing the raw encoder count(s) at the given timestamp or PROS_ERR if the + * operation failed. + */ + virtual std::vector get_raw_position_all(std::uint32_t* const timestamp) const = 0; + + /** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_temperature(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the temperature(s) of the motor(s) in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing the motor's/motors' temperature(s) in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual std::vector get_temperature_all(void) const = 0; + /** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double get_torque(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the torque(s) generated by the motor(s) in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing the motor's/motors' torque(s) in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::vector get_torque_all(void) const = 0; + /** + * Gets the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the voltage(s) delivered to the motor(s) in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing the motor's/motors' voltage(s) in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::vector get_voltage_all(void) const = 0; + + /** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::int32_t is_over_current(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of whether each motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + */ + virtual std::vector is_over_current_all(void) const = 0; + + /** + * Gets the temperature limit flag for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t is_over_temp(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the temperature limit flag(s) for the motor(s). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::vector is_over_temp_all(void) const = 0; + + ///@} + + /// \name Motor configuration functions + /// \addtogroup cpp-motor-configuration + /// These functions allow programmers to configure the behavior of motors + ///@{ + + /** + * Gets the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return One of Motor_Brake, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ + virtual MotorBrake get_brake_mode(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the brake mode(s) that was set for the motor(s). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing Motor_Brake(s), according to what was set for the + * motor(s), or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + */ + virtual std::vector get_brake_mode_all(void) const = 0; + + /** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_limit(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the current limit(s) for the motor(s) in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing the motor's/motors' current limit(s) in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::vector get_current_limit_all(void) const = 0; + + /** + * Gets the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return One of Motor_Units according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + */ + virtual MotorUnits get_encoder_units(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the encoder units that were set for the motor(s). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector of Motor_Units according to what is set for the + * motor(s) or E_MOTOR_ENCODER_INVALID if the operation failed. + */ + virtual std::vector get_encoder_units_all(void) const = 0; + + /** + * Gets the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return One of Motor_Gears according to what is set for the motor, + * or pros::Motor_Gears::invalid if the operation failed. + */ + virtual MotorGears get_gearing(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the gearset(s) that was/were set for the motor(s). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector of Motor_Gears according to what is set for the motor(s), + * or pros::Motor_Gears::invalid if the operation failed. + */ + virtual std::vector get_gearing_all(void) const = 0; + + /** + * @brief Gets returns a vector with all the port numbers in the motor group. + * + * @return std::vector + */ + virtual std::vector get_port_all(void) const = 0; + + /** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage_limit(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the voltage limit(s) set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return A vector containing the motor's/motors' voltage limit(s) in V or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::vector get_voltage_limit_all(void) const = 0; + + /** + * Gets the operation direction of the motor as set by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t is_reversed(const std::uint8_t index = 0) const = 0; + + /** + * Gets a vector of the operation direction(s) of the motor(s) as set by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + */ + virtual std::vector is_reversed_all(void) const = 0; + + /** + * Sets one of Motor_Brake to the motor. Works with the C enum + * and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param mode + * The Motor_Brake to set for the motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_brake_mode(const MotorBrake mode, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_brake_mode(const pros::motor_brake_mode_e_t mode, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_brake_mode_all(const MotorBrake mode) const = 0; + virtual std::int32_t set_brake_mode_all(const pros::motor_brake_mode_e_t mode) const = 0; + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new current limit in mA + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_current_limit(const std::int32_t limit, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_current_limit_all(const std::int32_t limit) const = 0; + /** + * Sets one of Motor_Units for the motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param units + * The new motor encoder units + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_encoder_units(const MotorUnits units, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_encoder_units(const pros::motor_encoder_units_e_t units, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_encoder_units_all(const MotorUnits units) const = 0; + virtual std::int32_t set_encoder_units_all(const pros::motor_encoder_units_e_t units) const = 0; + /** + * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param gearset + * The new motor gearset + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_gearing(const pros::motor_gearset_e_t gearset, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_gearing_all(const MotorGears gearset) const = 0; + virtual std::int32_t set_gearing_all(const pros::motor_gearset_e_t gearset) const = 0; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param reverse + * True reverses the motor, false is default + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_reversed(const bool reverse, const std::uint8_t index = 0) = 0; + virtual std::int32_t set_reversed_all(const bool reverse) = 0; + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new voltage limit in Volts + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_voltage_limit(const std::int32_t limit, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_voltage_limit_all(const std::int32_t limit) const = 0; + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The new reference position in its encoder units + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_zero_position(const double position, const std::uint8_t index = 0) const = 0; + virtual std::int32_t set_zero_position_all(const double position) const = 0; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param index Optional parameter. + * The index of the motor to get the target position of. + * By default index is 0, and will return an error for an out of bounds index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t tare_position(const std::uint8_t index = 0) const = 0; + virtual std::int32_t tare_position_all(void) const = 0; + virtual std::int8_t get_port(const std::uint8_t index = 0) const = 0; + /** + * @brief Returns the number of objects + * + * @return std::int8_t + */ + virtual std::int8_t size(void) const = 0; + + ///@} + private: +}; + +} // namespace v5 +} // namespace pros + +///@} + +#endif diff --git a/include/pros/adi.h b/include/pros/adi.h new file mode 100644 index 0000000..f1bbe37 --- /dev/null +++ b/include/pros/adi.h @@ -0,0 +1,1383 @@ +/** + * \file pros/adi.h + * \ingroup c-adi + * + * Contains prototypes for interfacing with the ADI. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-adi ADI (TriPort) C API + * \note The external ADI API can be found [here.](@ref ext-adi) + * \note Additional example code for this module can be found in its [Tutorial.](@ref adi) + */ + +#ifndef _PROS_ADI_H_ +#define _PROS_ADI_H_ + +#include +#include +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \ingroup c-adi + */ + +/** + * \addtogroup c-adi + * @{ + */ + +/** + * \enum adi_port_config_e + * Represents the port type for an ADI port. + */ +typedef enum adi_port_config_e { + E_ADI_ANALOG_IN = 0, + E_ADI_ANALOG_OUT = 1, + E_ADI_DIGITAL_IN = 2, + E_ADI_DIGITAL_OUT = 3, + +#ifdef _INTELLISENSE +#define _DEPRECATE_DIGITAL_IN = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN = E_ADI_ANALOG_IN +#else +#define _DEPRECATE_DIGITAL_IN __attribute__((deprecated("use E_ADI_DIGITAL_IN instead"))) = E_ADI_DIGITAL_IN +#define _DEPRECATE_ANALOG_IN __attribute__((deprecated("use E_ADI_ANALOG_IN instead"))) = E_ADI_ANALOG_IN +#endif + + E_ADI_SMART_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_SMART_POT _DEPRECATE_ANALOG_IN, + + E_ADI_LEGACY_BUTTON _DEPRECATE_DIGITAL_IN, + E_ADI_LEGACY_POT _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LINE_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_LIGHT_SENSOR _DEPRECATE_ANALOG_IN, + E_ADI_LEGACY_GYRO = 10, + E_ADI_LEGACY_ACCELEROMETER _DEPRECATE_ANALOG_IN, + +#undef _DEPRECATE_DIGITAL_IN +#undef _DEPRECATE_ANALOG_IN + + E_ADI_LEGACY_SERVO = 12, + E_ADI_LEGACY_PWM = 13, + + E_ADI_LEGACY_ENCODER = 14, + E_ADI_LEGACY_ULTRASONIC = 15, + + E_ADI_TYPE_UNDEFINED = 255, + E_ADI_ERR = PROS_ERR +} adi_port_config_e_t; + +/** + * \enum adi_potentiometer_type_e_t + * Represents the potentiometer version type. + */ +typedef enum adi_potentiometer_type_e { + E_ADI_POT_EDR = 0, + E_ADI_POT_V2 +} adi_potentiometer_type_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define ADI_ANALOG_IN pros::E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT pros::E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN pros::E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT pros::E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON pros::E_ADI_SMART_BUTTON +#define ADI_SMART_POT pros::E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON pros::E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT pros::E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR pros::E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR pros::E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO pros::E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER pros::E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO pros::E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM pros::E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER pros::E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC pros::E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED pros::E_ADI_TYPE_UNDEFINED +#define ADI_ERR pros::E_ADI_ERR +#else +#define ADI_ANALOG_IN E_ADI_ANALOG_IN +#define ADI_ANALOG_OUT E_ADI_ANALOG_OUT +#define ADI_DIGITAL_IN E_ADI_DIGITAL_IN +#define ADI_DIGITAL_OUT E_ADI_DIGITAL_OUT +#define ADI_SMART_BUTTON E_ADI_SMART_BUTTON +#define ADI_SMART_POT E_ADI_SMART_POT +#define ADI_LEGACY_BUTTON E_ADI_LEGACY_BUTTON +#define ADI_LEGACY_POT E_ADI_LEGACY_POT +#define ADI_LEGACY_LINE_SENSOR E_ADI_LEGACY_LINE_SENSOR +#define ADI_LEGACY_LIGHT_SENSOR E_ADI_LEGACY_LIGHT_SENSOR +#define ADI_LEGACY_GYRO E_ADI_LEGACY_GYRO +#define ADI_LEGACY_ACCELEROMETER E_ADI_LEGACY_ACCELEROMETER +#define ADI_LEGACY_SERVO E_ADI_LEGACY_SERVO +#define ADI_LEGACY_PWM E_ADI_LEGACY_PWM +#define ADI_LEGACY_ENCODER E_ADI_LEGACY_ENCODER +#define ADI_LEGACY_ULTRASONIC E_ADI_LEGACY_ULTRASONIC +#define ADI_TYPE_UNDEFINED E_ADI_TYPE_UNDEFINED +#define ADI_ERR E_ADI_ERR +#endif +#endif + +#define INTERNAL_ADI_PORT 22 +#define NUM_ADI_PORTS 8 + +#ifdef __cplusplus +namespace c { +#endif + +/** @} Add to group c-adi*/ + +/** + * \ingroup c-adi + */ + +/** + * \addtogroup c-adi + * @{ + */ + +/** + * Gets the configuration for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports. + * + * \param port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * adi_port_set_config(ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * // Displays the value of E_ADI_ANALOG_IN + * printf("Port Type: %d\n", adi_port_get_config(ANALOG_SENSOR_PORT)); + * } + * \endcode + */ +adi_port_config_e_t adi_port_get_config(uint8_t port); + +/** + * Gets the value for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports. + * + * \param port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be returned + * + * \return The value stored for the given port + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * adi_port_set_config(ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * printf("Port Value: %d\n", adi_get_value(ANALOG_SENSOR_PORT)); + * } + * \endcode + */ +int32_t adi_port_get_value(uint8_t port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports. + * + * \param port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * adi_port_set_config(ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * } + * \endcode + */ +int32_t adi_port_set_config(uint8_t port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports. + * + * \param port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void initialize() { + * adi_port_set_config(DIGITAL_SENSOR_PORT, E_ADI_DIGITAL_OUT); + * adi_set_value(DIGITAL_SENSOR_PORT, HIGH); + * } + * \endcode + */ +int32_t adi_port_set_value(uint8_t port, int32_t value); + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * \note The ADI currently returns data at 10ms intervals, in constrast to the + * calibrate function’s 1ms sample rate. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * + * \param port + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * adi_analog_calibrate(ANALOG_SENSOR_PORT); + * printf("Calibrated Reading: %d\n", adi_analog_read_calibrated(ANALOG_SENSOR_PORT)); + * // All readings from then on will be calibrated + * } + * \endcode + */ +int32_t adi_analog_calibrate(uint8_t port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The analog sensor value, where a value of 0 reflects an input voltage + * of nearly 0 V and a value of 4095 reflects an input voltage of nearly 5 V + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Sensor Reading: %d\n", adi_analog_read(ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_analog_read(uint8_t port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Sensor Reading: %d\n", adi_analog_read_calibrated(ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_analog_read_calibrated(uint8_t port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an analog input + * + * \param port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * adi_analog_calibrate(ANALOG_SENSOR_PORT); + * printf("Sensor Reading: %d\n", adi_analog_read_calibrated_HR(ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_analog_read_calibrated_HR(uint8_t port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Sensor Value: %d\n", adi_digital_read(DIGITAL_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_digital_read(uint8_t port); + +/** + * Gets a rising-edge case for a digital button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under the + * same circumstances, so only one task should call this function for any given + * button. E.g., Task A calls this function for buttons 1 and 2. Task B may call + * this function for button 3, but should not for buttons 1 or 2. A typical + * use-case for this function is to call inside opcontrol to detect new button + * presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a digital input + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * if (adi_digital_get_new_press(DIGITAL_SENSOR_PORT)) { + * // Toggle pneumatics or other state operations + * } + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_digital_get_new_press(uint8_t port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior is undefined. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a digital output + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT + * + * void opcontrol() { + * bool state = LOW; + * while (true) { + * state != state; + * adi_digital_write(DIGITAL_SENSOR_PORT, state); + * delay(5); // toggle the sensor value every 50ms + * } + * } + * \endcode + */ +int32_t adi_digital_write(uint8_t port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * + * \param port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * adi_pin_mode(ANALOG_SENSOR_PORT, INPUT_ANALOG); + * } + * \endcode + */ +int32_t adi_pin_mode(uint8_t port, uint8_t mode); + +/** + * Sets the speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * adi_motor_set(MOTOR_PORT, 127); // Go full speed forward + * delay(1000); + * adi_motor_set(MOTOR_PORT, 0); // Stop the motor + * } + * \endcode + */ +int32_t adi_motor_set(uint8_t port, int8_t speed); + +/** + * Gets the last set speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * adi_motor_set(MOTOR_PORT, 127); // Go full speed forward + * printf("Commanded Motor Power: %d\n", adi_motor_get(MOTOR_PORT)); // Will display 127 + * delay(1000); + * adi_motor_set(MOTOR_PORT, 0); // Stop the motor + * } + * \endcode + */ +int32_t adi_motor_get(uint8_t port); + +/** + * Stops the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an motor + * + * \param port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * adi_motor_set(MOTOR_PORT, 127); // Go full speed forward + * delay(1000); + * // adi_motor_set(MOTOR_PORT, 0); // Stop the motor + * adi_motor_stop(MOTOR_PORT); // use this instead + * } + * \endcode + */ +int32_t adi_motor_stop(uint8_t port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder. + */ +typedef int32_t adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * adi_encoder_t enc = adi_encoder_init(PORT_TOP, PORT_BOTTOM, false); + * while (true) { + * printf("Encoder Value: %d\n", adi_encoder_get(enc)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_encoder_get(adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an encoder + + * + * \param port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * adi_encoder_t enc = adi_encoder_init(PORT_TOP, PORT_BOTTOM, false); + * while (true) { + * printf("Encoder Value: %d\n", adi_encoder_get(enc)); + * delay(5); + * } + * } + * \endcode + */ +adi_encoder_t adi_encoder_init(uint8_t port_top, uint8_t port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an encoder + + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * adi_encoder_t enc = adi_encoder_init(PORT_TOP, PORT_BOTTOM, false); + * delay(1000); // Move the encoder around in this time + * adi_encoder_reset(enc); // The encoder is now zero again + * } + * \endcode + */ +int32_t adi_encoder_reset(adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * adi_encoder_t enc = adi_encoder_init(PORT_TOP, PORT_BOTTOM, false); + * // Use the encoder + * adi_encoder_shutdown(enc); + * } + * \endcode + */ +int32_t adi_encoder_shutdown(adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic. + */ +typedef int32_t adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + * + * \b Example + * \code + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * + * void opcontrol() { + * adi_ultrasonic_t ult = adi_ultrasonic_init(PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", adi_ultrasonic_get(ult)); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_ultrasonic_get(adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + * + * \b Example + * \code + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * + * void opcontrol() { + * adi_ultrasonic_t ult = adi_ultrasonic_init(PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", adi_ultrasonic_get(ult)); + * delay(5); + * } + * } + * \endcode + */ +adi_ultrasonic_t adi_ultrasonic_init(uint8_t port_ping, uint8_t port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * + * void opcontrol() { + * adi_ultrasonic_t ult = adi_ultrasonic_init(PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", adi_ultrasonic_get(ult)); + * delay(5); + * } + * adi_ultrasonic_shutdown(ult); + * } + * \endcode + */ +int32_t adi_ultrasonic_shutdown(adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope. + */ +typedef int32_t adi_gyro_t; + +/** + * Gets the current gyro angle in tenths of a degree. Unless a multiplier is + * applied to the gyro, the return value will be a whole number representing + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * + * void opcontrol() { + * adi_gyro_t gyro = adi_gyro_init(GYRO_PORT, GYRO_MULTIPLIER); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", adi_gyro_get(gyro)); + * delay(5); + * } + * } + * \endcode + */ +double adi_gyro_get(adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a gyro + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * + * void opcontrol() { + * adi_gyro_t gyro = adi_gyro_init(GYRO_PORT, GYRO_MULTIPLIER); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", adi_gyro_get(gyro)); + * delay(5); + * } + * } + * \endcode + */ +adi_gyro_t adi_gyro_init(uint8_t port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * + * void opcontrol() { + * adi_gyro_t gyro = adi_gyro_init(GYRO_PORT, GYRO_MULTIPLIER); + * uint32_t now = millis(); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", adi_gyro_get(gyro)); + * + * if (millis() - now > 2000) { + * // Reset the gyro every 2 seconds + * adi_gyro_reset(gyro); + * now = millis(); + * } + * + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_gyro_reset(adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * + * void opcontrol() { + * adi_gyro_t gyro = adi_gyro_init(GYRO_PORT, GYRO_MULTIPLIER); + * uint32_t now = millis(); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", adi_gyro_get(gyro)); + * + * if (millis() - now > 2000) { + * adi_gyro_shutdown(gyro); + * // Shut down the gyro after two seconds + * break; + * } + * + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_gyro_shutdown(adi_gyro_t gyro); + +/** + * Reference type for an initialized potentiometer. + * + * This merely contains the port number for the potentiometer. + */ +typedef int32_t adi_potentiometer_t; + +/** + * Initializes a potentiometer on the given port of the original potentiometer. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + * + * \b Example + * \code + * #define POTENTIOMETER_PORT 1 + * + * void opcontrol() { + * adi_potentiometer_t potentiometer = adi_potentiometer_init(POTENTIOMETER_PORT); + * while (true) { + * // Print the potentiometer's angle + * printf("Angle: %lf\n", adi_potentiometer_get_angle(potentiometer)); + * delay(5); + * } + * } + * \endcode + */ +adi_potentiometer_t adi_potentiometer_init(uint8_t port); + +/** + * Initializes a potentiometer on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + * + * \b Example + * \code + * #define POTENTIOMETER_PORT 1 + * #define POTENTIOMETER_TYPE E_ADI_POT_EDR + * + * void opcontrol() { + * adi_potentiometer_t potentiometer = adi_potentiometer_type_init(POTENTIOMETER_PORT, POTENTIOMETER_TYPE); + * while (true) { + * // Print the potentiometer's angle + * printf("Angle: %lf\n", adi_potentiometer_get_angle(potentiometer)); + * delay(5); + * } + * } + * \endcode + */ +adi_potentiometer_t adi_potentiometer_type_init(uint8_t port, adi_potentiometer_type_e_t potentiometer_type); + +/** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 330 degrees thus returning an angle between 0-330 degrees. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param potentiometer + * The adi_potentiometer_t object for which the angle will be returned + * + * \return The potentiometer angle in degrees. + * + * \b Example + * \code + * #define POTENTIOMETER_PORT 1 + * + * void opcontrol() { + * adi_potentiometer_t potentiometer = adi_potentiometer_t(POTENTIOMETER_PORT); + * while (true) { + * // Print the potnetiometer's angle + * printf("Angle: %lf\n", adi_potentiometer_get_angle(potentiometer)); + * delay(5); + * } + * } + * \endcode + */ +double adi_potentiometer_get_angle(adi_potentiometer_t potentiometer); + +/** + * Reference type for an initialized addressable led. + * + * This merely contains the port number for the led, unlike its use as an + * object to store led data in the C++ API. + */ +typedef int32_t adi_led_t; + +/** + * Initializes a led on the given port of the original led. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - The ADI port given is not a valid port as defined below + * EADDRINUSE - The port is not configured for ADI output + * + * \param port + * The ADI port to initialize as a led (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An adi_led_t object containing the given port, or PROS_ERR if the + * initialization failed, setting errno + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the led to the colors in the buffer + * adi_led_set(led, buffer, 10); + * delay(5); + * } + * } + * \endcode + */ +adi_led_t adi_led_init(uint8_t port); + +/** + * @brief Clear the entire led strip of color + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the led to the colors in the buffer + * adi_led_set(led, buffer, 10); + * delay(5); + * + * // Clear the led strip + * adi_led_clear(led); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_led_clear_all(adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip using the colors contained in the buffer + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the led strip to the colors in the buffer + * adi_led_set(led, buffer, 10); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_led_set(adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip to one color + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @param color color to set all the led strip value to + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the led strip to red + * adi_led_set_all(led, buffer, 10, 0xFF0000); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_led_set_all(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t color); + +/** + * @brief Set one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param color color to clear all the led strip to + * @param pixel_position position of the pixel to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the first pixel to red + * adi_led_set_pixel(led, buffer, 10, 0xFF0000, 0); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_led_set_pixel(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t color, uint32_t pixel_position); + +/** + * @brief Clear one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param pixel_position position of the pixel to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example + * \code + * #define LED_PORT 1 + * + * void opcontrol() { + * adi_led_t led = adi_led_init(LED_PORT); + * uint32_t buffer[10] = {0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0x000000, 0x000000, 0x000000}; + * while (true) { + * // Set the first pixel to red + * adi_led_set_pixel(led, buffer, 10, 0xFF0000, 0); + * delay(5); + * + * // Clear the first pixel + * adi_led_clear_pixel(led, buffer, 10, 0); + * delay(5); + * } + * } + * \endcode + */ +int32_t adi_led_clear_pixel(adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t pixel_position); + +/** + * \name Ease of use macro definitions + * These functions provide ease of use definitions for the ADI functions. + * @{ + */ + +/** + * Used for adi_digital_write() to specify a logic HIGH state to output. + * + * In reality, using any non-zero expression or "true" will work to set a pin to + * HIGH. + */ +#define HIGH 1 +/** + * Used for adi_digital_write() to specify a logic LOW state to output. + * + * In reality, using a zero expression or "false" will work to set a pin to LOW. + */ +#define LOW 0 + +/** + * adi_pin_mode() state for a digital input. + */ +#define INPUT 0x00 +/** + * adi_pin_mode() state for a digital output. + */ +#define OUTPUT 0x01 +/** + * adi_pin_mode() state for an analog input. + */ +#define INPUT_ANALOG 0x02 + +/** + * adi_pin_mode() state for an analog output. + */ +#define OUTPUT_ANALOG 0x03 + +/** @} Name: Ease of use macro definitions*/ + +/** @} Add to group: c-adi*/ + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/include/pros/adi.hpp b/include/pros/adi.hpp new file mode 100644 index 0000000..a12bd4a --- /dev/null +++ b/include/pros/adi.hpp @@ -0,0 +1,1995 @@ +/** + * \file pros/adi.hpp + * \ingroup cpp-adi + * + * Contains prototypes for interfacing with the ADI. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-adi ADI (TriPort) C++ API + * \note The external ADI API can be found [here.](@ref ext-adi) + * \note Additional example code for this module can be found in its [Tutorial.](@ref adi) + */ + +#ifndef _PROS_ADI_HPP_ +#define _PROS_ADI_HPP_ + +#include +#include +#include +#include +#include + +#include "pros/adi.h" + +#define LEGACY_TYPEDEF(old_name, new_name) \ + using old_name [[deprecated("use " #new_name " instead")]] = new_name + +namespace pros { +namespace adi { + +/** type definition for the pair of smart port and adi port for the basic adi devices */ +using ext_adi_port_pair_t = std::pair; + +/** type definition for the triplet of smart port and two adi ports for the two wire adi devices*/ +using ext_adi_port_tuple_t = std::tuple; + +/** + * \ingroup cpp-adi + */ +class Port { + /** + * \addtogroup cpp-adi + * @{ + */ + + public: + /** + * Configures an ADI port to act as a given sensor type. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \b Example + * \code + * #define POTENTIOMETER_PORT 1 + * #define POTENTIOMETER_TYPE pros::E_ADI_POT_EDR + * + * void opcontrol() { + * pros::ADIPotentiometer potentiometer (POTENTIOMETER_PORT, POTENTIOMETER_TYPE); + * while (true) { + * // Get the potentiometer angle + * std::cout << "Angle: " << potnetiometer.get_angle(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Port(std::uint8_t adi_port, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Configures an ADI port on an adi expander to act as a given sensor type. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the ADI port number + * (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 'a' + * #define EXT_ADI_SMART_PORT 1 + * + * void initialize() { + * pros::adi::Port sensor ({{ EXT_ADI_SMART_PORT , ANALOG_SENSOR_PORT }}, E_ADI_ANALOG_IN); + * // Displays the value of E_ADI_ANALOG_IN + * std::cout << "Port Type: " << sensor.get_config(); + * } + * \endcode + */ + explicit Port(ext_adi_port_pair_t port_pair, adi_port_config_e_t type = E_ADI_TYPE_UNDEFINED); + + /** + * Gets the configuration for the given ADI port. + * + * \return The ADI configuration for the given port + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * void initialize() { + * adi_port_set_config(ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * // Displays the value of E_ADI_ANALOG_IN + * printf("Port Type: %d\n", adi_port_get_config(ANALOG_SENSOR_PORT)); + * } + * \endcode + */ + std::int32_t get_config() const; + + /** + * Gets the value for the given ADI port. + * + * \return The value stored for the given port + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::adi::Port sensor (ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * std::cout << "Port Value: " << sensor.get_value(); + * } + * \endcode + */ + std::int32_t get_value() const; + + /** + * Configures an ADI port to act as a given sensor type. + * + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::Port sensor (ANALOG_SENSOR_PORT, E_ADI_DIGITAL_IN); + * // Do things as a digital sensor + * // Digital is unplugged and an analog is plugged in + * sensor.set_config(E_ADI_ANALOG_IN); + * } + * \endcode + */ + std::int32_t set_config(adi_port_config_e_t type) const; + + /** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will + * change depending on the configuration of the port. + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::Port sensor (DIGITAL_SENSOR_PORT, E_ADI_DIGITAL_OUT); + * sensor.set_value(DIGITAL_SENSOR_PORT, HIGH); + * } + * \endcode + */ + std::int32_t set_value(std::int32_t value) const; + + protected: + std::uint8_t _smart_port; + std::uint8_t _adi_port; +}; +///@} + +class AnalogIn : protected Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as an Analog Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::ADIAnalogIn sensor (ANALOG_SENSOR_PORT); + * while (true) { + * // Use the sensor + * } + * } + * \endcode + */ + explicit AnalogIn(std::uint8_t adi_port); + + /** + * Configures an ADI port to act as an Analog Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define EXT_ADI_SENSOR_PORT 1 + * #define ADI_PORT 'a' + * + * void opcontrol() { + * pros::ADIAnalogIn sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}}); + * while (true) { + * // Use the sensor + * } + * } + * \endcode + */ + explicit AnalogIn(ext_adi_port_pair_t port_pair); + + /** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms + * apart, for a 0.5 s period of calibration. The average value thus calculated + * is returned and stored for later calls to the + * pros::AnalogIn::get_value_calibrated() and + * pros::AnalogIn::get_value_calibrated_HR() functions. These functions + * will return the difference between this value and the current sensor value + * when called. + * + * Do not use this function when the sensor value might be unstable (gyro + * rotation, accelerometer movement). + * + * \note The ADI currently returns data at 10ms intervals, in contrast to the + * calibrate function’s 1ms sample rate. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an analog input + * + * \return The average sensor value computed by this function + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT); + * sensor.calibrate(ANALOG_SENSOR_PORT); + * std::cout << "Calibrated Reading:" << sensor.get_value_calibrated(); + * // All readings from then on will be calibrated + * } + * \endcode + */ + std::int32_t calibrate() const; + + /** + * Gets the 12 bit calibrated value of an analog input port. + * + * The pros::adi::AnalogIn::calibrate() function must be run first. This + * function is inappropriate for sensor values intended for integration, as + * round-off error can accumulate causing drift over time. Use + * pros::adi::AnalogIn::get_value_calibrated_HR() instead. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an analog input + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT); + * sensor.calibrate(ANALOG_SENSOR_PORT); + * std::cout << "Calibrated Reading:" << sensor.get_value_calibrated(); + * // All readings from then on will be calibrated + * } + * \endcode + */ + std::int32_t get_value_calibrated() const; + + /** + * Gets the 16 bit calibrated value of an analog input port. + * + * The pros::adi::AnalogIn::calibrate() function must be run first. This is + * intended for integrated sensor values such as gyros and accelerometers to + * reduce drift due to round-off, and should not be used on a sensor such as a + * line tracker or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being + * between two values when integrated over time is trivial. Think of the value + * as the true value times 16. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an analog input + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT); + * sensor.calibrate(ANALOG_SENSOR_PORT); + * std::cout << "Calibrated Reading:" << sensor.get_value_calibrated(); + * // All readings from then on will be calibrated + * } + * \endcode + */ + std::int32_t get_value_calibrated_HR() const; + + /** + * Reads an analog input channel and returns the 12-bit value. + * + * The value returned is undefined if the analog pin has been switched to a different mode. The meaning of the returned value varies depending on the sensor attached. + * + * Inherited from ADIPort::get_value. + * + * This function uses the following values of errno when an error state is reached: + * EADDRINUSE - The port is not configured as an analog input (e.g. the port has been reconfigured) + * + * \return The analog sensor value, where a value of 0 reflects an input + * voltage of nearly 0 V and a value of 4095 reflects an input voltage of + * nearly 5 V + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * pros::adi::AnalogIn sensor (ANALOG_SENSOR_PORT); + * std::cout << "Sensor Reading:" << sensor.get_value(); + * } + * \endcode + */ + using Port::get_value; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * AnalogIn [smart_port: analog_in._smart_port, adi_port: analog_in._adi_port, + * value calibrated: (12 bit calibrated value), + * value calibrated HR: (16 bit calibrated value), value: (12 bit value)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::AnalogIn& analog_in); +}; + +///@} + +// using ADIPotentiometer = ADIAnalogIn; +using LineSensor = AnalogIn; +using LightSensor = AnalogIn; +using Accelerometer = AnalogIn; + +class AnalogOut : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as an Analog Output. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::AnalogOut sensor (ANALOG_SENSOR_PORT); + * // Use the sensor + * } + * @endcode + */ + explicit AnalogOut(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as an Analog Output. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define EXT_ADI_SMART_PORT 1 + * #define ADI_PORT 'a' + * + * void opcontrol() { + * pros::AnalogOut sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}}); + * // Use the sensor + * } + * \endcode + */ + explicit AnalogOut(ext_adi_port_pair_t port_pair); + + /** + * Sets the output for the Analog Output from 0 (0V) to 4095 (5V). + * + * Inherited from ADIPort::set_value. + * + * This function uses the following values of errno when an error state is reached: + * EACCES - Another resource is currently trying to access the ADI. + * + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::AnalogOut sensor (ANALOG_SENSOR_PORT); + * sensor.set_value(4095); // Set the port to 5V + * } + * \endcode + */ + using Port::set_value; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * AnalogOut [smart_port: analog_out._smart_port, adi_port: analog_out._adi_port, + * value: (value)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::AnalogOut& analog_out); +}; +///@} + +class DigitalOut : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as a Digital Output. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param init_state + * The initial state for the port + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * bool state = LOW; + * pros::adi::DigitalOut sensor (DIGITAL_SENSOR_PORT, state); + * while (true) { + * state != state; + * sensor.set_value(state); + * pros::delay(10); // toggle the sensor value every 50ms + * } + * } + * \endcode + */ + explicit DigitalOut(std::uint8_t adi_port, bool init_state = LOW); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Output. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param init_state + * The initial state for the port + * + * \b Example + * \code + * #define EXT_ADI_SMART_PORT 1 + * #define ADI_PORT 'a' + * + * void opcontrol() { + * bool state = LOW; + * pros::adi::DigitalOut sensor ( {{ EXT_ADI_SMART_PORT , ADI_PORT }}); + * while (true) { + * state != state; + * sensor.set_value(state); + * pros::delay(10); // toggle the sensor value every 50ms + * } + * } + * \endcode + */ + explicit DigitalOut(ext_adi_port_pair_t port_pair, bool init_state = LOW); + + /** + * Sets the digital value (1 or 0) of a pin. + * + * Inherited from ADIPort::set_value. + * + * This function uses the following values of errno when an error state is + * reached: + * EADDRINUSE - The port is not configured as a digital output (e.g. the port has been reconfigured) + * + * \param value + * The value to set the ADI port to + * + * \return if the operation was successful or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * bool state = LOW; + * pros::adi::DigitalOut sensor (DIGITAL_SENSOR_PORT); + * while (true) { + * state != state; + * sensor.set_value(state); + * pros::delay(10); // toggle the sensor value every 50ms + * } + * } + * \endcode + */ + using Port::set_value; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * DigitalOut [smart_port: digital_out._smart_port, adi_port: digital_out._adi_port, + * value: (value)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::DigitalOut& digital_out); +}; +///@} + +class DigitalIn : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as a Digital Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::adi::DigitalIn sensor (ANALOG_SENSOR_PORT); + * // Use the sensor + * } + * \endcode + */ + explicit DigitalIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Digital Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define EXT_ADI_SMART_PORT 1 + * #define ADI_PORT 'a' + * + * void opcontrol() { + * pros::adi::DigitalIn sensor ({{EXT_ADI_SMART_PORT, ADI_PORT}}); + * // Use the sensor + * } + * \endcode + */ + explicit DigitalIn(ext_adi_port_pair_t port_pair); + + /** + * Gets a rising-edge case for a digital button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under + * the same circumstances, so only one task should call this function for any + * given button. E.g., Task A calls this function for buttons 1 and 2. Task B + * may call this function for button 3, but should not for buttons 1 or 2. A + * typical use-case for this function is to call inside opcontrol to detect + * new button presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a digital input + * + * \return 1 if the button is pressed and had not been pressed the last time + * this function was called, 0 otherwise. + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::adi::DigitalIn sensor (DIGITAL_SENSOR_PORT); + * while (true) { + * if (sensor.get_new_press()) { + * // Toggle pneumatics or other state operations + * } + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t get_new_press() const; + + /** + * Gets the digital value (1 or 0) of a pin. + * + * Inherited from ADIPort::get_value. + * + * This function uses the following values of errno when an error state is reached: + * + * EADDRINUSE - The port is not configured as a digital input (e.g. the port has been reconfigured) + * + * Analogous to adi_digital_read. + * + * \return The value stored for the given port + * + * \b Example + * \code + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * pros::adi::DigitalIn sensor (DIGITAL_SENSOR_PORT); + * while (true) { + * std::cout << "Sensor Value:" << sensor.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + using Port::get_value; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * DigitalIn [smart_port: digital_in._smart_port, adi_port: digital_in._adi_port, + * value: (value)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::DigitalIn& digital_in); +}; + +///@} + +//Derived Class(es) from DigitalIn +using Button = DigitalIn; + +class Motor : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as a Motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * pros::adi::Motor motor (MOTOR_PORT); + * motor.set_value(127); // Go full speed forward + * std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127 + * delay(1000); + * motor.set_value(0); // Stop the motor + * } + * \endcode + */ + explicit Motor(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi_expander to act as a Motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * + * \b Example + * \code + * #define EXT_ADI_SMART_PORT 1 + * #define ADI_MOTOR_PORT 'a' + * + * void opcontrol() { + * pros::adi::Motor motor ( {{ EXT_ADI_SMART_PORT , ADI_MOTOR_PORT}} ); + * motor.set_value(127); // Go full speed forward + * std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127 + * delay(1000); + * motor.set_value(0); // Stop the motor + * } + * \endcode + */ + explicit Motor(ext_adi_port_pair_t port_pair); + + /** + * Stops the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * pros::adi::Motor motor (MOTOR_PORT); + * motor.set_value(127); // Go full speed forward + * std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127 + * delay(1000); + * motor.stop(); // Stop the motor + * } + * \endcode + */ + std::int32_t stop() const; + + /** + * Sets the speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \param value + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * pros::adi::Motor motor (MOTOR_PORT); + * motor.set_value(127); // Go full speed forward + * std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127 + * delay(1000); + * motor.set_value(0); // Stop the motor + * } + * \endcode + */ + using Port::set_value; + + /** + * Gets the last set speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The last set speed of the motor on the given + * + * \b Example + * \code + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * pros::adi::Motor motor (MOTOR_PORT); + * motor.set_value(127); // Go full speed forward + * std::cout << "Commanded Motor Power: " << motor.get_value(); // Will display 127 + * delay(1000); + * motor.set_value(0); // Stop the motor + * } + * \endcode + */ + using Port::get_value; +}; + +///@} + +class Encoder : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures a set of ADI ports to act as an Encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side up + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false); + * // Use the sensor + * } + * \endcode + */ + explicit Encoder(std::uint8_t adi_port_top, std::uint8_t adi_port_bottom, bool reversed = false); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the "top" wire from the encoder + * sensor with the removable cover side up, and the "bottom" wire from + * the encoder sensor + * \param reverse + * If "true", the sensor will count in theopposite direction + * + * \b Example + * \code + * #define PORT_TOP 'A' + * #define PORT_BOTTOM 'B' + * #define SMART_PORT 1 + * + * void opcontrol() { + * pros::adi::Encoder sensor ({ SMART_PORT, PORT_TOP, PORT_BOTTOM }, false); + * // Use the sensor + * } + * \endcode + */ + explicit Encoder(ext_adi_port_tuple_t port_tuple, bool reversed = false); + + /** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false); + * delay(1000); // Move the encoder around in this time + * sensor.reset(); // The encoder is now zero again + * } + * \endcode + */ + std::int32_t reset() const; + + /** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a motor + * + * \return The signed and cumulative number of counts since the last start or + * + * \b Example + * \code + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * pros::adi::Encoder sensor (PORT_TOP, PORT_BOTTOM, false); + * while (true) { + * std::cout << "Encoder Value: " << sensor.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t get_value() const; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * Encoder [smart_port: encoder._smart_port, adi_port: encoder._adi_port, + * value: (value)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::Encoder& encoder); +}; + +///@} + +class Ultrasonic : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures a set of ADI ports to act as an Ultrasonic sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \b Example + * \code + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * + * void opcontrol() { + * pros::adi::Ultrasonic sensor (PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * std::cout << "Distance: " << sensor.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Ultrasonic(std::uint8_t adi_port_ping, std::uint8_t adi_port_echo); + + /** + * Configures a set of ADI ports on an adi_expander to act as an Ultrasonic sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_tuple + * The tuple of the smart port number, the port connected to the orange + * OUTPUT cable (1, 3, 5, 7 or 'A', 'C', 'E', 'G'), and the port + * connected to the yellow INPUT cable (the next) highest port + * following port_ping). + * + * \b Example + * \code + * #define PORT_PING 'A' + * #define PORT_ECHO 'B' + * #define SMART_PORT 1 + * + * void opcontrol() { + * pros::adi::Ultrasonic sensor ( {{ SMART_PORT, PORT_PING, PORT_ECHO }} ); + * while (true) { + * // Print the distance read by the ultrasonic + * std::cout << "Distance: " << sensor.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Ultrasonic(ext_adi_port_tuple_t port_tuple); + + /** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was + * never started, the return value is undefined. Round and fluffy objects can + * cause inaccurate values to be returned. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as an ultrasonic + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 + * meter), measured from the sensor's mounting points. + * + * \b Example + * \code + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * + * void opcontrol() { + * pros::adi::Ultrasonic sensor (PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * std::cout << "Distance: " << sensor.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t get_value() const; +}; + +///@} + +class Gyro : private Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300ms + * calibration period. + * + * It is highly recommended that an Gyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an Gyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the + * + * \b Example + * \code + * #define GYRO_PORT 1 + * + * void opcontrol() { + * pros::adi::Gyro gyro (GYRO_PORT); + * while (true) { + * // Get the gyro heading + * std::cout << "Distance: " << gyro.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Gyro(std::uint8_t adi_port, double multiplier = 1); + + /** + * Initializes a gyroscope on the given port of an adi expander. If the given + * port has not previously been configured as a gyro, then this function starts + * a 1300ms calibration period. + * + * It is highly recommended that an adi::Gyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an adi::Gyro + * object is declared at the global scope, a hardcoded 1300ms delay at the + * beginning of initialize will be necessary to ensure that the gyro's + * returned values are correct at the beginning of autonomous/opcontrol. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the + * + * \b Example + * \code + * #define ADI_GYRO_PORT 'a' + * #define SMART_PORT 1 + * + * void opcontrol() { + * pros::adi::Gyro gyro ({{ SMART_PORT , ADI_GYRO_PORT }}); + * while (true) { + * // Get the gyro heading + * std::cout << "Distance: " << gyro.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Gyro(ext_adi_port_pair_t port_pair, double multiplier = 1); + + /** + * Gets the current gyro angle in tenths of a degree. Unless a multiplier is + * applied to the gyro, the return value will be a whole number representing + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return The gyro angle in degrees. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * + * void opcontrol() { + * pros::adi::Gyro gyro (GYRO_PORT); + * while (true) { + * // Get the gyro heading + * std::cout << "Distance: " << gyro.get_value(); + * pros::delay(10); + * } + * } + * \endcode + */ + double get_value() const; + + /** + * Resets the gyroscope value to zero. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a gyro + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GYRO_PORT 1 + * + * void opcontrol() { + * pros::adi::Gyro gyro (GYRO_PORT); + * std::uint32_t now = pros::millis(); + * while (true) { + * // Get the gyro heading + * std::cout << "Distance: " << gyro.get_value(); + * + * if (pros::millis() - now > 2000) { + * // Reset the gyro every 2 seconds + * gyro.reset(); + * now = pros::millis(); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t reset() const; +}; + +///@} + +class Potentiometer : public AnalogIn { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * Configures an ADI port to act as a Potentiometer. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \b Example + * \code + * #define POTENTIOMETER_PORT 1 + * #define POTENTIOMETER_TYPE pros::E_ADI_POT_EDR + * + * void opcontrol() { + * pros::adi::Potentiometer potentiometer (POTENTIOMETER_PORT, POTENTIOMETER_TYPE); + * while (true) { + * // Get the potentiometer angle + * std::cout << "Angle: " << potentiometer.get_angle(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Potentiometer(std::uint8_t adi_port, adi_potentiometer_type_e_t potentiometer_type = E_ADI_POT_EDR); + + /** + * Configures an ADI port on an adi_expander to act as a Potentiometer. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \b Example + * \code + * #define ADI_POTENTIOMETER_PORT 'a' + * #define SMART_PORT 1 + * + * void opcontrol() { + * pros::adi::Potentiometer potentiometer ({{ SMART_PORT , ADI_POTENTIOMETER_PORT }}); + * while (true) { + * // Get the potentiometer angle + * std::cout << "Angle: " << potentiometer.get_angle(); + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Potentiometer(ext_adi_port_pair_t port_pair, adi_potentiometer_type_e_t potentiometer_type = E_ADI_POT_EDR); + + /** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 330 degrees thus returning an angle between 0-330 degrees. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \return The potentiometer angle in degrees. + * + * \b Example + * \code + * #define ADI_POTENTIOMETER_PORT 'a' + * #define SMART_PORT 1 + * + * void opcontrol() { + * pros::adi::Potentiometer potentiometer ({{ SMART_PORT , ADI_POTENTIOMETER_PORT }}); + * while (true) { + * // Get the potentiometer angle + * std::cout << "Angle: " << potentiometer.get_angle(); + * pros::delay(10); + * } + * } + * \endcode + */ + double get_angle() const; + + /** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \return The analog sensor value, where a value of 0 reflects an input + * voltage of nearly 0 V and a value of 4095 reflects an input voltage of + * nearly 5 V + */ + using AnalogIn::get_value; + + /** + * Calibrates the potentiometer on the specified port and returns the new + * calibration value. + * + * This method assumes that the potentiometer value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms + * apart, for a 0.5 s period of calibration. The average value thus calculated + * is returned and stored for later calls to the + * pros::adi::Potentiometer::get_value_calibrated() function. This function + * will return the difference between this value and the current sensor value + * when called. + * + * Do not use this function when the potentiometer value might be unstable (rotating the potentiometer) + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \return The average potentiometer value computed by this function + */ + using AnalogIn::calibrate; + + /** + * Gets the 12 bit calibrated value of a potentiometer port. + * + * The pros::adi::Potentiometer::calibrate() function must be run first. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port is not configured as a potentiometer + * + * \return The difference of the potentiometer value from its calibrated default from + * -4095 to 4095 + */ + using AnalogIn::get_value_calibrated; + + /** + * This is the overload for the << operator for printing to streams + * Potentiometer [value: (value), value calibrated: (calibrated value), + * angle: (angle)] + * Prints in format(this below is all in one line with no new line): + */ + friend std::ostream& operator<<(std::ostream& os, pros::adi::Potentiometer& potentiometer); +}; + +///@} + +class Led : protected Port { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + /** + * @brief Configures an ADI port to act as a LED. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param length + * The number of LEDs in the chain + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set entire LED strip to red + * led.set_all(0xFF0000); + * pros::delay(20); + * } + * } + * \endcode + * + */ + explicit Led(std::uint8_t adi_port, std::uint32_t length); + + /** + * @brief Configures an ADI port on a adi_expander to act as a LED. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param length + * The number of LEDs in the chain + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define SMART_PORT 1 + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led ({{ SMART_PORT , LED_PORT }}, LED_LENGTH); + * while (true) { + * // Set entire LED strip to red + * led.set_all(0xFF0000); + * pros::delay(20); + * } + * } + * \endcode + */ + explicit Led(ext_adi_port_pair_t port_pair, std::uint32_t length); + + /** + * @brief Operator overload to access the buffer in the ADILed class, it is + * recommended that you call .update(); after doing any operations with this. + * + * @param i 0 indexed pixel of the lED + * @return uint32_t& the address of the buffer at i to modify + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the first 3 pixels to red, green, and blue + * led.set_pixel(0xFF0000, 0); + * led.set_pixel(0x00FF00, 1); + * led.set_pixel(0x0000FF, 2); + * pros::delay(20); + * + * // Use the [] operator to set the first pixel to black + * led.operator[](0) = 0x000000; + * led.update(); + * pros::delay(20); + * } + * } + */ + std::uint32_t& operator[] (size_t i); + + /** + * @brief Clear the entire led strip of color + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the first 3 pixels to red, green, and blue + * led.set_pixel(0xFF0000, 0); + * led.set_pixel(0x00FF00, 1); + * led.set_pixel(0x0000FF, 2); + * pros::delay(20); + * + * // Clear the led strip of color + * led.clear(); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t clear_all(); + std::int32_t clear(); + + /** + * @brief Force the LED strip to update with the current buffered values, this + * should be called after any changes to the buffer using the [] operator. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the first 3 pixels to red, green, and blue + * led.set_pixel(0xFF0000, 0); + * led.set_pixel(0x00FF00, 1); + * led.set_pixel(0x0000FF, 2); + * pros::delay(20); + * + * // Use the [] operator to set the first pixel to black + * led.operator[](0) = 0x000000; + * // Update the led strip with the new values + * led.update(); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t update() const; + + /** + * @brief Set the entire led strip to one color + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @param color color to set all the led strip value to + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the entire led strip to blue + * led.set_all(0x0000FF); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t set_all(uint32_t color); + + /** + * @brief Set one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @param color color to clear all the led strip to + * @param pixel_position position of the pixel to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the first pixel to blue + * led.set_pixel(0x0000FF, 0); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t set_pixel(uint32_t color, uint32_t pixel_position); + + /** + * @brief Clear one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @param pixel_position position of the pixel to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Set the first pixel to blue + * led.set_pixel(0x0000FF, 0); + * pros::delay(20); + * + * // Clear the first pixel + * led.clear_pixel(0); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t clear_pixel(uint32_t pixel_position); + + /** + * @brief Get the length of the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A parameter is out of bounds/incorrect + * EADDRINUSE - The port is not configured for ADI output + * + * @return The length (in pixels) of the LED strip + * + * \b Example: + * \code + * #define LED_PORT 'a' + * #define LED_LENGTH 3 + * + * void opcontrol() { + * pros::Led led (LED_PORT, LED_LENGTH); + * while (true) { + * // Get the length of the led strip + * int length = led.length(); + * pros::lcd::print(1, "Length: %d", length); + * pros::delay(20); + * } + * } + * \endcode + */ + std::int32_t length(); + + protected: + std::vector _buffer; +}; +///@} + +/// @brief Alias for ADILed +using LED = Led; + +class Pneumatics : public DigitalOut { + /** + * \addtogroup cpp-adi + * @{ + */ + public: + + /** + * Creates a Pneumatics object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param start_extended + * If true, the pneumatic will start extended when the program starts. + * By default, the piston starts retracted when the program starts. + * \param extended_is_low + * A flag to set whether the the pneumatic is extended when the ADI + * it receives a high or a low value. When true, the extended state + * corresponds to a output low on the ADI port. This allows the user + * to reverse the behavior of the pneumatics if needed. + * + * /b Example: + * \code + * void opcontrol() { + * pros::adi::Pneumatics left_piston('a', false); // Starts retracted, extends when the ADI port is high + * pros::adi::Pneumatics right_piston('b', false, true); // Starts retracted, extends when the ADI port is low + * + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * + * while (true) { + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L1)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L2)) { + * left_piston.retract(); + * } + * + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R1)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_2)) { + * left_piston.retract(); + * } + * + * pros::delay(10); + * } + * + * \endcode + */ + explicit Pneumatics(std::uint8_t adi_port, + bool start_extended, + bool extended_is_low = false + ); + + /** + * Creates a Pneumatics object for the given port pair. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * + * \param port_pair + * The pair of the smart port number (from 1-22) and the + * ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param start_extended + * If true, the pneumatic will start extended when the program starts. + * By default, the piston starts retracted when the program starts. + * \param extended_is_low + * A flag to set whether the the pneumatic is extended when the ADI + * it receives a high or a low value. When true, the extended state + * corresponds to a output low on the ADI port. This allows the user + * to reverse the behavior of the pneumatics if needed. + * + * /b Example: + * \code + * void opcontrol() { + * pros::adi::Pneumatics left_piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high + * pros::adi::Pneumatics right_piston({1, 'b'}, false, true); // Starts retracted, extends when the ADI port is low + * + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * + * while (true) { + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L1)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_L2)) { + * left_piston.retract(); + * } + * + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R1)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_R2)) { + * left_piston.retract(); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + explicit Pneumatics(ext_adi_port_pair_t port_pair, + bool start_extended, + bool extended_is_low = false + ); + + /** + * Extends the piston, if not already extended. + * + * \return 1 if the piston newly extended, 0 if the piston was already + * extended, or PROS_ERR is the operation failed, setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high + * + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * + * while (true) { + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_B)) { + * left_piston.retract(); + * } + * if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) { + * left_piston.toggle(); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t extend(); + + /** + * Retracts the piston, if not already retracted. + * + * \return 1 if the piston newly retracted, 0 if the piston was already + * retracted, or PROS_ERR is the operation failed, setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high + * + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * + * while (true) { + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_B)) { + * left_piston.retract(); + * } + * if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) { + * left_piston.toggle(); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t retract(); + + /** + * Puts the piston into the opposite state of its current state. + * If it is retracted, it will extend. If it is extended, it will retract. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \return 1 if the piston successfully toggled, or PROS_ERR if the + * operation failed, setting errno. + * + *\b Example: + * \code + * void opcontrol() { + * pros::adi::Pneumatics piston({1, 'a'}, false); // Starts retracted, extends when the ADI port is high + * + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * + * while (true) { + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_X)) { + * left_piston.extend(); + * } + * if(master.get_digital(pros::E_CONTROLLER_DIGITAL_B)) { + * left_piston.retract(); + * } + * if(mastetr.get_digital(pros::E_CONTROLLER_DIGITAL_A)) { + * left_piston.toggle(); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + std::int32_t toggle(); + + /** + * Returns whether the piston is extended or not. + * + * \return true if the piston is extended, false if it is retracted. + * + * \b Example + * \code + * #define ADI_PNEUMATICS_PORT 'a' + * + * void opcontrol() { + * pros::adi::Pneumatics pneumatics (ADI_PNEUMATICS_PORT); + * while (true) { + * // Check if the piston is extended + * if (pneumatics.is_extended()) { + * printf("The pneumatic is extended\n"); + * } + * else { + * printf("The pneumatic is not extended\n"); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + bool is_extended() const; + +private: + bool state; // Holds the physical state of the ADI port + bool extended_is_low; // A flag that sets whether extended corresponds to + // a low signal + + +}; +///@} + +} // namespace adi + +/* +Pros4 upgrade backwards compatibility for ADI api. + +Prints a deprecated warning when user uses old pros::ADIDevice style API. +Remove when and if fully removing old API. +*/ +LEGACY_TYPEDEF(ADIPort, pros::adi::Port); +LEGACY_TYPEDEF(ADIAnalogIn, pros::adi::AnalogIn); +LEGACY_TYPEDEF(ADIAnalogOut, pros::adi::AnalogOut); +LEGACY_TYPEDEF(ADIDigitalIn, pros::adi::DigitalIn); +LEGACY_TYPEDEF(ADIDigitalOut, pros::adi::DigitalOut); +LEGACY_TYPEDEF(ADIMotor, pros::adi::Motor); +LEGACY_TYPEDEF(ADIGyro, pros::adi::Gyro); +LEGACY_TYPEDEF(ADIEncoder, pros::adi::Encoder); +LEGACY_TYPEDEF(ADIUltrasonic, pros::adi::Ultrasonic); +LEGACY_TYPEDEF(LED, pros::adi::Led); + +// Backwards Compatibility for Derived Classes +LEGACY_TYPEDEF(ADIPotentiometer,pros::adi::Potentiometer); +LEGACY_TYPEDEF(ADILineSensor,pros::adi::LineSensor); +LEGACY_TYPEDEF(ADILightSensor,pros::adi::LightSensor); +LEGACY_TYPEDEF(ADIAccelerometer,pros::adi::Accelerometer); +LEGACY_TYPEDEF(ADIButton,pros::adi::Button); +LEGACY_TYPEDEF(ADIPneumatics,pros::adi::Pneumatics); +LEGACY_TYPEDEF(ADILED, pros::adi::Led); +LEGACY_TYPEDEF(ADILed, pros::adi::Led); + +} // namespace pros + +#endif // _PROS_ADI_HPP_ diff --git a/include/pros/apix.h b/include/pros/apix.h new file mode 100644 index 0000000..165c054 --- /dev/null +++ b/include/pros/apix.h @@ -0,0 +1,939 @@ +/** + * \file pros/apix.h + * \ingroup apix + * + * PROS Extended API header + * + * Contains additional declarations for use by advaned users of PROS. These + * functions do not typically have as much error handling or require deeper + * knowledge of real time operating systems. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup apix Extended API + * \note Also included in the Extended API is [LVGL.](https://lvgl.io/) + */ + +#ifndef _PROS_API_EXTENDED_H_ +#define _PROS_API_EXTENDED_H_ + +#include "api.h" +#include "pros/device.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic pop +#include "pros/serial.h" + +#ifdef __cplusplus +#include "pros/serial.hpp" +namespace pros::c { +extern "C" { +#endif + +/** + * \ingroup apix + */ + +/** + * \addtogroup apix + * @{ + */ + +/// \name RTOS Facilities +///@{ + +typedef void* queue_t; +typedef void* sem_t; + +/** + * Unblocks a task in the Blocked state (e.g. waiting for a delay, on a + * semaphore, etc.). + * + * \param task + * The task to unblock + * + * \return True if the task was unblocked, false otherwise + * + * \b Example: + * \code + * task_t task = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * task_delay(1000); + * // in another task somewhere else, this will abort the task_delay bove: + * task_abort_delay(task); + * \endcode + */ +bool task_abort_delay(task_t task); + +/** + * Notify a task when a target task is being deleted. + * + * \param target_task + * The task being watched for deletion + * \param task_to_notify + * The task to notify when target_task is deleted + * \param value + * The value to supply to task_notify_ext + * \param notify_action + * The action to supply to task_notify_ext + * + * \b Example: + * \code + * task_t task_to_delete = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * task_t task_to_notify = task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn2"); + * + * task_notify_ext(task_to_notify, 0, NOTIFY_ACTION_INCREMENT, NULL); + * + * task_notify_when_deleting(task_to_delete, task_get_current(), 0, NOTIFY_ACTION_NONE); + * task_delete(task_to_delete); + * \endcode + */ +void task_notify_when_deleting(task_t target_task, task_t task_to_notify, uint32_t value, + notify_action_e_t notify_action); + +/** + * Creates a recursive mutex which can be locked recursively by the owner. + * + * \return A newly created recursive mutex. + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +mutex_t mutex_recursive_create(void); + +/** + * Takes a recursive mutex. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * \param wait_time + * Amount of time to wait before timing out + * + * \return 1 if the mutex was obtained, 0 otherwise + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); + +/** + * Gives a recursive mutex. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * + * \return 1 if the mutex was obtained, 0 otherwise + * + * \b Example: + * \code + * mutex_t mutex = mutex_recursive_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_recursive_take(mutex, 1000); + * // critical section + * mutex_recursive_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +bool mutex_recursive_give(mutex_t mutex); + +/** + * Returns a handle to the current owner of a mutex. + * + * \param mutex + * A mutex handle + * + * \return A handle to the current task that owns the mutex, or NULL if the + * mutex isn't owned. + * + * \b Example: + * \code + * mutex_t mutex = mutex_create(); + * + * void task_fn(void* param) { + * while(1) { + * mutex_take(mutex, 1000); + * // critical section + * mutex_give(mutex); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * void opcontrol(void) { +* while (1) { +* if (joystick_get_digital(1, 7, JOY_UP)) { +* task_t owner = mutex_get_owner(mutex); +* if (owner != NULL) { +* printf("Mutex is owned by task %s", task_get_name(owner)); +* } else { +* printf("Mutex is not owned"); +* } +* } +* task_delay(20); +* } +* } + * \endcode + */ +task_t mutex_get_owner(mutex_t mutex); + +/** + * Creates a counting sempahore. + * + * \param max_count + * The maximum count value that can be reached. + * \param init_count + * The initial count value assigned to the new semaphore. + * + * \return A newly created semaphore. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why sem_create failed. + * + * \b Example: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_create(1, 0); + * + * void task_fn(void* param) { + * while(1) { + * sem_take(sem, 1000); + * // critical section + * sem_give(sem); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +sem_t sem_create(uint32_t max_count, uint32_t init_count); + +/** + * Deletes a semaphore (or binary semaphore) + * + * \param sem + * Semaphore to delete + * + * \b Example: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_create(1, 0); + * + * void task_fn(void* param) { + * while(1) { + * sem_take(sem, 1000); + * // critical section + * sem_give(sem); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * void opcontrol(void) { + * while (1) { + * if (joystick_get_digital(1, 7, JOY_UP)) { + * // honestly this is a bad example because you should never + * // delete a semaphore like this + * sem_delete(sem); + * } + * task_delay(20); + * } + * } + * + * \endcode + */ +void sem_delete(sem_t sem); + +/** + * Creates a binary semaphore. + * + * \return A newly created semaphore. + * + * \b Example: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_binary_create(); + * + * void task_fn(void* param) { + * while(1) { + * sem_take(sem, 1000); + * // critical section + * sem_give(sem); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +sem_t sem_binary_create(void); + +/** + * Waits for the semaphore's value to be greater than 0. If the value is already + * greater than 0, this function immediately returns. + * + * \param sem + * Semaphore to wait on + * \param timeout + * Time to wait before the semaphore's becomes available. A timeout of 0 + * can be used to poll the sempahore. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the semaphore was successfully take, false otherwise. If + * false is returned, then errno is set with a hint about why the sempahore + * couldn't be taken. + * + * \b Example: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_create(1, 0); + * + * void task_fn(void* param) { + * while(1) { + * if(!sem_wait(sem, 1000)) { + * printf("Failed to take semaphore"); + * task_delay(1000); + * continue; + * } + * // critical section + * sem_give(sem); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * void opcontrol(void) { + * while (1) { + * if (sem_wait(sem, 0))) { + * printf("Semaphore is available"); + * } + * task_delay(20); + * } + * } + * \endcode + */ +bool sem_wait(sem_t sem, uint32_t timeout); + +/** + * Increments a semaphore's value. + * + * \param sem + * Semaphore to post + * + * \return True if the value was incremented, false otherwise. If false is + * returned, then errno is set with a hint about why the semaphore couldn't be + * taken. + * + * \b Example: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_create(1, 0); + * + * void task_fn(void* param) { + * while(1) { + * sem_post(sem); // increments, mimicking to "claim" + * // critical section + * sem_give(sem); + * task_delay(1000); + * } + * } + * task_create(task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "task_fn"); + * + * \endcode + */ +bool sem_post(sem_t sem); + +/** + * Returns the current value of the semaphore. + * + * \param sem + * A semaphore handle + * + * \return The current value of the semaphore (e.g. the number of resources + * available) + * + * \b Example of sem_get_count: + * \code + * // Binary semaphore acts as a mutex + * sem_t sem = sem_create(1, 0); + * printf("semaphore count: %d", sem_get_count(sem)); + * // semaphore count: 0 + * sem_take(sem, 1000); + * printf("semaphore count: %d", sem_get_count(sem)); + * // semaphore count: 1 + * sem_give(sem); + * printf("semaphore count: %d", sem_get_count(sem)); + * // semaphore count: 0 + * + * \endcode + */ +uint32_t sem_get_count(sem_t sem); + +/** + * Creates a queue. + * + * \param length + * The maximum number of items that the queue can contain. + * \param item_size + * The number of bytes each item in the queue will require. + * + * \return A handle to a newly created queue, or NULL if the queue cannot be + * created. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + * \endcode + */ +queue_t queue_create(uint32_t length, uint32_t item_size); + +/** + * Posts an item to the front of a queue. The item is queued by copy, not by + * reference. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + */ +bool queue_prepend(queue_t queue, const void* item, uint32_t timeout); + +/** + * Posts an item to the end of a queue. The item is queued by copy, not by + * reference. + * + * \param queue + * The queue handle + * \param item + * A pointer to the item that will be placed on the queue. + * \param timeout + * Time to wait for space to become available. A timeout of 0 can be used + * to attempt to post without blocking. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the item was preprended, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue length: %d", queue_get_length(queue)); + * } + * \endcode + */ +bool queue_append(queue_t queue, const void* item, uint32_t timeout); + +/** + * Receive an item from a queue without removing the item from the queue. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block waiting for an item to receive should the queue be empty at + * the time of the call. TIMEOUT_MAX can be used to block indefinitely. + * + * \return True if an item was copied into the buffer, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * char* item = "Hello! this is a test"; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * char* recv = malloc(sizeof("Hello! this is a test")); + * queue_peek(queue, recv, 1000); + * printf("Queue: %s", recv); + * free(recv); + * } + * \endcode + */ +bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Receive an item from the queue. + * + * \param queue + * The queue handle + * \param buffer + * Pointer to a buffer to which the received item will be copied + * \param timeout + * The maximum amount of time the task should block + * waiting for an item to receive should the queue be empty at the time + * of the call. queue_recv() will return immediately if timeout + * is zero and the queue is empty. + * + * \return True if an item was copied into the buffer, false otherwise. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * char* item = "Hello! this is a test"; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * char* recv = malloc(sizeof("Hello! this is a test")); + * queue_recv(queue, recv, 1000); + * printf("Queue: %s", recv); + * free(recv); + * } + * \endcode + */ +bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Return the number of messages stored in a queue. + * + * \param queue + * The queue handle. + * + * \return The number of messages available in the queue. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue waiting: %d", queue_get_waiting(queue)); + * } + * \endcode + */ +uint32_t queue_get_waiting(const queue_t queue); + +/** + * Return the number of spaces left in a queue. + * + * \param queue + * The queue handle. + * + * \return The number of spaces available in the queue. + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * printf("queue available: %d", queue_get_available(queue)); + * } + * \endcode + */ +uint32_t queue_get_available(const queue_t queue); + +/** + * Delete a queue. + * + * \param queue + * Queue handle to delete + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * queue_delete(queue); + * } + * \endcode + */ +void queue_delete(queue_t queue); + +/** + * Resets a queue to an empty state + * + * \param queue + * Queue handle to reset + * + * \b Example: + * \code + * void opcontrol(void) { + * queue_t queue = queue_create(10, sizeof(int)); + * int item[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + * queue_prepend(queue, item, 1000); + * queue_append(queue, item, 1000); + * queue_reset(queue); + * } + * \endcode + */ +void queue_reset(queue_t queue); + +///@} + +/// \name Device Registration +///@{ + +/** + * Registers a device in the given zero-indexed port + * + * Registers a device of the given type in the given port into the registry, if + * that type of device is detected to be plugged in to that port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (0-20), or a + * a different device than specified is plugged in. + * EADDRINUSE - The port is already registered to another device. + * + * \param port + * The port number to register the device + * \param device + * The type of device to register + * + * \return 1 upon success, PROS_ERR upon failure + * + * \b Example: + * \code + * void opcontrol(void) { + * registry_bind_port(1, E_DEVICE_MOTOR); + * } + * \endcode + */ +int registry_bind_port(uint8_t port, v5_device_e_t device_type); + +/** + * Deregisters a devices from the given zero-indexed port + * + * Removes the device registed in the given port, if there is one. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (0-20). + * + * \param port + * The port number to deregister + * + * \return 1 upon success, PROS_ERR upon failure + * + * \b Example: + * \code + * void opcontrol(void) { + * registry_bind_port(1, E_DEVICE_MOTOR); + * registry_unbind_port(1); + * } + * \endcode + */ +int registry_unbind_port(uint8_t port); + +/** + * Returns the type of device registered to the zero-indexed port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (0-20). + * + * \param port + * The V5 port number from 0-20 + * + * \return The type of device that is registered into the port (NOT what is + * plugged in) + * + * \b Example: + * \code + * void opcontrol(void) { + * registry_bind_port(1, E_DEVICE_MOTOR); + * printf("port 1 is registered to a motor: %d", registry_get_bound_type(1) == E_DEVICE_MOTOR); + * } + * \endcode + */ +v5_device_e_t registry_get_bound_type(uint8_t port); + +/** + * Returns the type of the device plugged into the zero-indexed port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (0-20). + * + * \param port + * The V5 port number from 0-20 + * + * \return The type of device that is plugged into the port (NOT what is + * registered) + * + * \b Example: + * \code + * void opcontrol(void) { + * registry_bind_port(1, E_DEVICE_MOTOR); + * printf("port 1 is registered to a motor: %d", registry_get_plugged_type(1) == E_DEVICE_MOTOR); + * } + * \endcode + */ +v5_device_e_t registry_get_plugged_type(uint8_t port); + +///@} + +/// \name Filesystem +///@{ + +/** + * Control settings of the serial driver. + * + * \param action + * An action to perform on the serial driver. See the SERCTL_* macros for + * details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + * + * \b Example: + * \code + * void opcontrol(void) { + * serctl(SERCTL_SET_BAUDRATE, (void*) 9600); + * } + */ +int32_t serctl(const uint32_t action, void* const extra_arg); + +/* + * Control settings of the microSD card driver. + * + * \param action + * An action to perform on the microSD card driver. See the USDCTL_* macros + * for details on the different actions. + * \param extra_arg + * An argument to pass in based on the action + */ +// Not yet implemented +// int32_t usdctl(const uint32_t action, void* const extra_arg); + +/** + * Control settings of the way the file's driver treats the file + * + * \param file + * A valid file descriptor number + * \param action + * An action to perform on the file's driver. See the *CTL_* macros for + * details on the different actions. Note that the action passed in must + * match the correct driver (e.g. don't perform a SERCTL_* action on a + * microSD card file) + * \param extra_arg + * An argument to pass in based on the action + * + * \b Example: + * \code + * void opcontrol(void) { + * int32_t fd = open("serial", O_RDWR); + * fdctl(fd, SERCTL_SET_BAUDRATE, (void*) 9600); + * } + * \endcode + */ +int32_t fdctl(int file, const uint32_t action, void* const extra_arg); + +/** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1-21 + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_set_reversed(1, true); + * printf("Is this motor reversed? %d\n", motor_is_reversed(1)); + * } + * \endcode + */ +int32_t motor_set_reversed(int8_t port, const bool reverse); + +/** + * Gets the operation direction of the motor as set by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor has been reversed and 0 if the motor was not reversed, + * or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * printf("Is the motor reversed? %d\n", motor_is_reversed(1)); + * // Prints "Is the motor reversed? 0" + * } + * \endcode + */ +int32_t motor_is_reversed(int8_t port); + +/** + * Action macro to pass into serctl or fdctl that activates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + */ +#define SERCTL_ACTIVATE 10 + +/** + * Action macro to pass into serctl or fdctl that deactivates the stream + * identifier. + * + * When used with serctl, the extra argument must be the little endian + * representation of the stream identifier (e.g. "sout" -> 0x74756f73) + * + */ +#define SERCTL_DEACTIVATE 11 + +/** + * Action macro to pass into fdctl that enables blocking writes for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + */ +#define SERCTL_BLKWRITE 12 + +/** + * Action macro to pass into fdctl that makes writes non-blocking for the file + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + */ +#define SERCTL_NOBLKWRITE 13 + +/** + * Action macro to pass into serctl that enables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + */ +#define SERCTL_ENABLE_COBS 14 + +/** + * Action macro to pass into serctl that disables advanced stream multiplexing + * capabilities + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + * + */ +#define SERCTL_DISABLE_COBS 15 + +/** + * Action macro to check if there is data available from the Generic Serial + * Device + * + */ +#define DEVCTL_FIONREAD 16 + +/** + * Action macro to check if there is space available in the Generic Serial + * Device's output buffer + * + */ +#define DEVCTL_FIONWRITE 18 + +/** + * Action macro to set the Generic Serial Device's baudrate. + * + * The extra argument is the baudrate. + */ +#define DEVCTL_SET_BAUDRATE 17 + +///@} + +///@} + +#ifdef __cplusplus +} +} +#endif + +#endif // _PROS_API_EXTENDED_H_ diff --git a/include/pros/colors.h b/include/pros/colors.h new file mode 100644 index 0000000..b70a8f9 --- /dev/null +++ b/include/pros/colors.h @@ -0,0 +1,204 @@ +/** + * \file pros/colors.h + * + * Contains macro definitions of colors (as `uint32_t`) + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * Copyright (c) 2017-2020 Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License v. 2.0. If a copy of the MPL was not distributed with this + * file You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-colors Colors C API + */ + +/** + * \ingroup c-colors + * \note These functions can be used for dynamic device instantiation. + */ + +/** + * \addtogroup c-colors + * @{ + */ + +#ifndef _PROS_COLORS_H_ +#define _PROS_COLORS_H_ + +#define RGB2COLOR(R, G, B) ((R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff)) +#define COLOR2R(COLOR) ((COLOR >> 16) & 0xff) +#define COLOR2G(COLOR) ((COLOR >> 8) & 0xff) +#define COLOR2B(COLOR) (COLOR & 0xff) + +#ifdef __cplusplus +namespace pros { +namespace c { +#endif + +/** + * \enum color_e_t + * @brief + * Enum of possible colors + * + * Contains common colors, all members are self descriptive. + */ +typedef enum color_e { + COLOR_ALICE_BLUE = 0x00F0F8FF, + COLOR_ANTIQUE_WHITE = 0x00FAEBD7, + COLOR_AQUA = 0x0000FFFF, + COLOR_AQUAMARINE = 0x007FFFD4, + COLOR_AZURE = 0x00F0FFFF, + COLOR_BEIGE = 0x00F5F5DC, + COLOR_BISQUE = 0x00FFE4C4, + COLOR_BLACK = 0x00000000, + COLOR_BLANCHED_ALMOND = 0x00FFEBCD, + COLOR_BLUE = 0x000000FF, + COLOR_BLUE_VIOLET = 0x008A2BE2, + COLOR_BROWN = 0x00A52A2A, + COLOR_BURLY_WOOD = 0x00DEB887, + COLOR_CADET_BLUE = 0x005F9EA0, + COLOR_CHARTREUSE = 0x007FFF00, + COLOR_CHOCOLATE = 0x00D2691E, + COLOR_CORAL = 0x00FF7F50, + COLOR_CORNFLOWER_BLUE = 0x006495ED, + COLOR_CORNSILK = 0x00FFF8DC, + COLOR_CRIMSON = 0x00DC143C, + COLOR_CYAN = 0x0000FFFF, + COLOR_DARK_BLUE = 0x0000008B, + COLOR_DARK_CYAN = 0x00008B8B, + COLOR_DARK_GOLDENROD = 0x00B8860B, + COLOR_DARK_GRAY = 0x00A9A9A9, + COLOR_DARK_GREY = COLOR_DARK_GRAY, + COLOR_DARK_GREEN = 0x00006400, + COLOR_DARK_KHAKI = 0x00BDB76B, + COLOR_DARK_MAGENTA = 0x008B008B, + COLOR_DARK_OLIVE_GREEN = 0x00556B2F, + COLOR_DARK_ORANGE = 0x00FF8C00, + COLOR_DARK_ORCHID = 0x009932CC, + COLOR_DARK_RED = 0x008B0000, + COLOR_DARK_SALMON = 0x00E9967A, + COLOR_DARK_SEA_GREEN = 0x008FBC8F, + COLOR_DARK_SLATE_GRAY = 0x002F4F4F, + COLOR_DARK_SLATE_GREY = COLOR_DARK_SLATE_GRAY, + COLOR_DARK_TURQUOISE = 0x0000CED1, + COLOR_DARK_VIOLET = 0x009400D3, + COLOR_DEEP_PINK = 0x00FF1493, + COLOR_DEEP_SKY_BLUE = 0x0000BFFF, + COLOR_DIM_GRAY = 0x00696969, + COLOR_DIM_GREY = COLOR_DIM_GRAY, + COLOR_DODGER_BLUE = 0x001E90FF, + COLOR_FIRE_BRICK = 0x00B22222, + COLOR_FLORAL_WHITE = 0x00FFFAF0, + COLOR_FOREST_GREEN = 0x00228B22, + COLOR_FUCHSIA = 0x00FF00FF, + COLOR_GAINSBORO = 0x00DCDCDC, + COLOR_GHOST_WHITE = 0x00F8F8FF, + COLOR_GOLD = 0x00FFD700, + COLOR_GOLDENROD = 0x00DAA520, + COLOR_GRAY = 0x00808080, + COLOR_GREY = COLOR_GRAY, + COLOR_GREEN = 0x00008000, + COLOR_GREEN_YELLOW = 0x00ADFF2F, + COLOR_HONEYDEW = 0x00F0FFF0, + COLOR_HOT_PINK = 0x00FF69B4, + COLOR_INDIAN_RED = 0x00CD5C5C, + COLOR_INDIGO = 0x004B0082, + COLOR_IVORY = 0x00FFFFF0, + COLOR_KHAKI = 0x00F0E68C, + COLOR_LAVENDER = 0x00E6E6FA, + COLOR_LAVENDER_BLUSH = 0x00FFF0F5, + COLOR_LAWN_GREEN = 0x007CFC00, + COLOR_LEMON_CHIFFON = 0x00FFFACD, + COLOR_LIGHT_BLUE = 0x00ADD8E6, + COLOR_LIGHT_CORAL = 0x00F08080, + COLOR_LIGHT_CYAN = 0x00E0FFFF, + COLOR_LIGHT_GOLDENROD_YELLOW = 0x00FAFAD2, + COLOR_LIGHT_GREEN = 0x0090EE90, + COLOR_LIGHT_GRAY = 0x00D3D3D3, + COLOR_LIGHT_GREY = COLOR_LIGHT_GRAY, + COLOR_LIGHT_PINK = 0x00FFB6C1, + COLOR_LIGHT_SALMON = 0x00FFA07A, + COLOR_LIGHT_SEA_GREEN = 0x0020B2AA, + COLOR_LIGHT_SKY_BLUE = 0x0087CEFA, + COLOR_LIGHT_SLATE_GRAY = 0x00778899, + COLOR_LIGHT_SLATE_GREY = COLOR_LIGHT_SLATE_GRAY, + COLOR_LIGHT_STEEL_BLUE = 0x00B0C4DE, + COLOR_LIGHT_YELLOW = 0x00FFFFE0, + COLOR_LIME = 0x0000FF00, + COLOR_LIME_GREEN = 0x0032CD32, + COLOR_LINEN = 0x00FAF0E6, + COLOR_MAGENTA = 0x00FF00FF, + COLOR_MAROON = 0x00800000, + COLOR_MEDIUM_AQUAMARINE = 0x0066CDAA, + COLOR_MEDIUM_BLUE = 0x000000CD, + COLOR_MEDIUM_ORCHID = 0x00BA55D3, + COLOR_MEDIUM_PURPLE = 0x009370DB, + COLOR_MEDIUM_SEA_GREEN = 0x003CB371, + COLOR_MEDIUM_SLATE_BLUE = 0x007B68EE, + COLOR_MEDIUM_SPRING_GREEN = 0x0000FA9A, + COLOR_MEDIUM_TURQUOISE = 0x0048D1CC, + COLOR_MEDIUM_VIOLET_RED = 0x00C71585, + COLOR_MIDNIGHT_BLUE = 0x00191970, + COLOR_MINT_CREAM = 0x00F5FFFA, + COLOR_MISTY_ROSE = 0x00FFE4E1, + COLOR_MOCCASIN = 0x00FFE4B5, + COLOR_NAVAJO_WHITE = 0x00FFDEAD, + COLOR_NAVY = 0x00000080, + COLOR_OLD_LACE = 0x00FDF5E6, + COLOR_OLIVE = 0x00808000, + COLOR_OLIVE_DRAB = 0x006B8E23, + COLOR_ORANGE = 0x00FFA500, + COLOR_ORANGE_RED = 0x00FF4500, + COLOR_ORCHID = 0x00DA70D6, + COLOR_PALE_GOLDENROD = 0x00EEE8AA, + COLOR_PALE_GREEN = 0x0098FB98, + COLOR_PALE_TURQUOISE = 0x00AFEEEE, + COLOR_PALE_VIOLET_RED = 0x00DB7093, + COLOR_PAPAY_WHIP = 0x00FFEFD5, + COLOR_PEACH_PUFF = 0x00FFDAB9, + COLOR_PERU = 0x00CD853F, + COLOR_PINK = 0x00FFC0CB, + COLOR_PLUM = 0x00DDA0DD, + COLOR_POWDER_BLUE = 0x00B0E0E6, + COLOR_PURPLE = 0x00800080, + COLOR_RED = 0x00FF0000, + COLOR_ROSY_BROWN = 0x00BC8F8F, + COLOR_ROYAL_BLUE = 0x004169E1, + COLOR_SADDLE_BROWN = 0x008B4513, + COLOR_SALMON = 0x00FA8072, + COLOR_SANDY_BROWN = 0x00F4A460, + COLOR_SEA_GREEN = 0x002E8B57, + COLOR_SEASHELL = 0x00FFF5EE, + COLOR_SIENNA = 0x00A0522D, + COLOR_SILVER = 0x00C0C0C0, + COLOR_SKY_BLUE = 0x0087CEEB, + COLOR_SLATE_BLUE = 0x006A5ACD, + COLOR_SLATE_GRAY = 0x00708090, + COLOR_SLATE_GREY = COLOR_SLATE_GRAY, + COLOR_SNOW = 0x00FFFAFA, + COLOR_SPRING_GREEN = 0x0000FF7F, + COLOR_STEEL_BLUE = 0x004682B4, + COLOR_TAN = 0x00D2B48C, + COLOR_TEAL = 0x00008080, + COLOR_THISTLE = 0x00D8BFD8, + COLOR_TOMATO = 0x00FF6347, + COLOR_TURQUOISE = 0x0040E0D0, + COLOR_VIOLET = 0x00EE82EE, + COLOR_WHEAT = 0x00F5DEB3, + COLOR_WHITE = 0x00FFFFFF, + COLOR_WHITE_SMOKE = 0x00F5F5F5, + COLOR_YELLOW = 0x00FFFF00, + COLOR_YELLOW_GREEN = 0x009ACD32, +} color_e_t; + + ///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +#endif + +#endif // _PROS_COLORS_H_ diff --git a/include/pros/colors.hpp b/include/pros/colors.hpp new file mode 100644 index 0000000..970c2cf --- /dev/null +++ b/include/pros/colors.hpp @@ -0,0 +1,190 @@ +/** + * \file pros/colors.hpp + * + * Contains enum class definitions of colors + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * Copyright (c) 2017-2022 Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License v. 2.0. If a copy of the MPL was not distributed with this + * file You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-colors C++ Color API + */ +#ifndef _PROS_COLORS_HPP_ +#define _PROS_COLORS_HPP_ + + +namespace pros{ +/** + * \ingroup cpp-colors + */ + +/** + * \addtogroup cpp-colors + * @{ + */ + +/** + * \enum Color + * @brief + * Enum class of possible colors + * + * Contains common colors, all members are self descriptive. + */ +enum class Color { + alice_blue = 0x00F0F8FF, + antique_white = 0x00FAEBD7, + aqua = 0x0000FFFF, + aquamarine = 0x007FFFD4, + azure = 0x00F0FFFF, + beige = 0x00F5F5DC, + bisque = 0x00FFE4C4, + black = 0x00000000, + blanched_almond = 0x00FFEBCD, + blue = 0x000000FF, + blue_violet = 0x008A2BE2, + brown = 0x00A52A2A, + burly_wood = 0x00DEB887, + cadet_blue = 0x005F9EA0, + chartreuse = 0x007FFF00, + chocolate = 0x00D2691E, + coral = 0x00FF7F50, + cornflower_blue = 0x006495ED, + cornsilk = 0x00FFF8DC, + crimson = 0x00DC143C, + cyan = 0x0000FFFF, + dark_blue = 0x0000008B, + dark_cyan = 0x00008B8B, + dark_goldenrod = 0x00B8860B, + dark_gray = 0x00A9A9A9, + dark_grey = dark_gray, + dark_green = 0x00006400, + dark_khaki = 0x00BDB76B, + dark_magenta = 0x008B008B, + dark_olive_green = 0x00556B2F, + dark_orange = 0x00FF8C00, + dark_orchid = 0x009932CC, + dark_red = 0x008B0000, + dark_salmon = 0x00E9967A, + dark_sea_green = 0x008FBC8F, + dark_slate_gray = 0x002F4F4F, + dark_slate_grey = dark_slate_gray, + dark_turquoise = 0x0000CED1, + dark_violet = 0x009400D3, + deep_pink = 0x00FF1493, + deep_sky_blue = 0x0000BFFF, + dim_gray = 0x00696969, + dim_grey = dim_gray, + dodger_blue = 0x001E90FF, + fire_brick = 0x00B22222, + floral_white = 0x00FFFAF0, + forest_green = 0x00228B22, + fuchsia = 0x00FF00FF, + gainsboro = 0x00DCDCDC, + ghost_white = 0x00F8F8FF, + gold = 0x00FFD700, + goldenrod = 0x00DAA520, + gray = 0x00808080, + grey = gray, + green = 0x00008000, + green_yellow = 0x00ADFF2F, + honeydew = 0x00F0FFF0, + hot_pink = 0x00FF69B4, + indian_red = 0x00CD5C5C, + indigo = 0x004B0082, + ivory = 0x00FFFFF0, + khaki = 0x00F0E68C, + lavender = 0x00E6E6FA, + lavender_blush = 0x00FFF0F5, + lawn_green = 0x007CFC00, + lemon_chiffon = 0x00FFFACD, + light_blue = 0x00ADD8E6, + light_coral = 0x00F08080, + light_cyan = 0x00E0FFFF, + light_goldenrod_yellow = 0x00FAFAD2, + light_green = 0x0090EE90, + light_gray = 0x00D3D3D3, + light_grey = light_gray, + light_pink = 0x00FFB6C1, + light_salmon = 0x00FFA07A, + light_sea_green = 0x0020B2AA, + light_sky_blue = 0x0087CEFA, + light_slate_gray = 0x00778899, + light_slate_grey = light_slate_gray, + light_steel_blue = 0x00B0C4DE, + light_yellow = 0x00FFFFE0, + lime = 0x0000FF00, + lime_green = 0x0032CD32, + linen = 0x00FAF0E6, + magenta = 0x00FF00FF, + maroon = 0x00800000, + medium_aquamarine = 0x0066CDAA, + medium_blue = 0x000000CD, + medium_orchid = 0x00BA55D3, + medium_purple = 0x009370DB, + medium_sea_green = 0x003CB371, + medium_slate_blue = 0x007B68EE, + medium_spring_green = 0x0000FA9A, + medium_turquoise = 0x0048D1CC, + medium_violet_red = 0x00C71585, + midnight_blue = 0x00191970, + mint_cream = 0x00F5FFFA, + misty_rose = 0x00FFE4E1, + moccasin = 0x00FFE4B5, + navajo_white = 0x00FFDEAD, + navy = 0x00000080, + old_lace = 0x00FDF5E6, + olive = 0x00808000, + olive_drab = 0x006B8E23, + orange = 0x00FFA500, + orange_red = 0x00FF4500, + orchid = 0x00DA70D6, + pale_goldenrod = 0x00EEE8AA, + pale_green = 0x0098FB98, + pale_turquoise = 0x00AFEEEE, + pale_violet_red = 0x00DB7093, + papay_whip = 0x00FFEFD5, + peach_puff = 0x00FFDAB9, + peru = 0x00CD853F, + pink = 0x00FFC0CB, + plum = 0x00DDA0DD, + powder_blue = 0x00B0E0E6, + purple = 0x00800080, + red = 0x00FF0000, + rosy_brown = 0x00BC8F8F, + royal_blue = 0x004169E1, + saddle_brown = 0x008B4513, + salmon = 0x00FA8072, + sandy_brown = 0x00F4A460, + sea_green = 0x002E8B57, + seashell = 0x00FFF5EE, + sienna = 0x00A0522D, + silver = 0x00C0C0C0, + sky_blue = 0x0087CEEB, + slate_blue = 0x006A5ACD, + slate_gray = 0x00708090, + slate_grey = slate_gray, + snow = 0x00FFFAFA, + spring_green = 0x0000FF7F, + steel_blue = 0x004682B4, + tan = 0x00D2B48C, + teal = 0x00008080, + thistle = 0x00D8BFD8, + tomato = 0x00FF6347, + turquoise = 0x0040E0D0, + violet = 0x00EE82EE, + wheat = 0x00F5DEB3, + white = 0x00FFFFFF, + white_smoke = 0x00F5F5F5, + yellow = 0x00FFFF00, + yellow_green = 0x009ACD32, +}; +} // namespace pros + + ///@} + +#endif //_PROS_COLORS_HPP_ diff --git a/include/pros/device.h b/include/pros/device.h new file mode 100644 index 0000000..889e008 --- /dev/null +++ b/include/pros/device.h @@ -0,0 +1,91 @@ +/** + * \file pros/device.h + * + * Contains functions for interacting with VEX devices. + * + * + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2021, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-device VEX Generic Device C API (For Advanced Users) + */ + +#ifndef _PROS_DEVICE_H_ +#define _PROS_DEVICE_H_ + +#include + +#ifdef __cplusplus +namespace pros::c { +extern "C" { +#endif + +/** + * \ingroup c-device + * \note These functions can be used for dynamic device instantiation. + */ + +/** + * \addtogroup c-device + * @{ + */ + +/** + * \enum v5_device_e + * \brief + * List of possible v5 devices + * + * This list contains all current V5 Devices, and mirrors V5_DeviceType from the + * api. + */ +typedef enum v5_device_e { + E_DEVICE_NONE = 0, ///< No device is plugged into the port + E_DEVICE_MOTOR = 2, ///< A motor is plugged into the port + E_DEVICE_ROTATION = 4, ///< A rotation sensor is plugged into the port + E_DEVICE_IMU = 6, ///< An inertial sensor is plugged into the port + E_DEVICE_DISTANCE = 7, ///< A distance sensor is plugged into the port + E_DEVICE_RADIO = 8, ///< A radio is plugged into the port + E_DEVICE_VISION = 11, ///< A vision sensor is plugged into the port + E_DEVICE_ADI = 12, ///< This port is an ADI expander + E_DEVICE_OPTICAL = 16, ///< An optical sensor is plugged into the port + E_DEVICE_GPS = 20, ///< A GPS sensor is plugged into the port + E_DEVICE_SERIAL = 129, ///< A serial device is plugged into the port + E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, + E_DEVICE_UNDEFINED = 255 ///< The device type is not defined, or is not a valid device +} v5_device_e_t; + +/** + * Gets the type of device on given port. + * + * \return The device type as an enum. + * + * \b Example + * \code + * #define DEVICE_PORT 1 + * + * void opcontrol() { + * while (true) { + * v5_device_e_t pt = get_plugged_type(DEVICE_PORT); + * printf("device plugged type: {plugged type: %d}\n", pt); + * delay(20); + * } + * } + * \endcode +*/ +v5_device_e_t get_plugged_type(uint8_t port); + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +#endif + +#endif // _PROS_DEVICE_H_ diff --git a/include/pros/device.hpp b/include/pros/device.hpp new file mode 100644 index 0000000..7fcee80 --- /dev/null +++ b/include/pros/device.hpp @@ -0,0 +1,162 @@ +/** + * \file pros/device.hpp + * + * Base class for all smart devices. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2021, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-device VEX Generic Device C++ API (For Advanced Users) + */ + +#ifndef _PROS_DEVICE_HPP_ +#define _PROS_DEVICE_HPP_ + +#include "pros/misc.hpp" +#include "pros/rtos.hpp" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-device + * \note These functions can be used for dynamic device instantiation. + */ + +/** + * \addtogroup cpp-device + * @{ + */ + +/** + * \enum DeviceType + * \brief + * Enum of possible v5 devices. + * + * Contains all current V5 Devices. + */ +enum class DeviceType { + none = 0, ///< No device is plugged into the port + motor = 2, ///< A motor is plugged into the port + rotation = 4, ///< A rotation sensor is plugged into the port + imu = 6, ///< An inertial sensor is plugged into the port + distance = 7, ///< A distance sensor is plugged into the port + radio = 8, ///< A radio is plugged into the port + vision = 11, ///< A vision sensor is plugged into the port + adi = 12, ///< This port is an ADI expander + optical = 16, ///< An optical sensor is plugged into the port + gps = 20, ///< A GPS sensor is plugged into the port + serial = 129, ///< A serial device is plugged into the port + undefined = 255 ///< The device type is not defined, or is not a valid device +}; + +class Device { + public: + /** + * Creates a Device object. + * + * \param port The V5 port number from 1-21 + * + * \b Example + * \code + * #define DEVICE_PORT 1 + * + * void opcontrol() { + * Device device(DEVICE_PORT); + * } + * \endcode + */ + explicit Device(const std::uint8_t port); + + /** + * Gets the port number of the Smart Device. + * + * \return The smart device's port number. + * + * \b Example + * \code + * void opcontrol() { + * #define DEVICE_PORT 1 + * while (true) { + * Device device(DEVICE_PORT); + * printf("device plugged type: {port: %d}\n", device.get_port()); + * delay(20); + * } + * } + * \endcode + */ + std::uint8_t get_port(void); + + /** + * Checks if the device is installed. + * + * \return true if the corresponding device is installed, false otherwise. + * \b Example + * + * \code + * #define DEVICE_PORT 1 + * + * void opcontrol() { + * Device device(DEVICE_PORT); + * while (true) { + * printf("device plugged type: {is_installed: %d}\n", device.is_installed()); + * delay(20); + * } + * } + * \endcode + */ + virtual bool is_installed(); + + /** + * Gets the type of device. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Mutex of port cannot be taken (access denied). + * + * \return The device type as an enum. + * + * \b Example + * \code + * #define DEVICE_PORT 1 + * + * void opcontrol() { + Device device(DEVICE_PORT); + * while (true) { + * DeviceType dt = device.get_plugged_type(); + * printf("device plugged type: {plugged type: %d}\n", dt); + * delay(20); + * } + * } + * \endcode + */ + pros::DeviceType get_plugged_type() const; + + + protected: + /** + * Creates a Device object. + * + * \param port The V5 port number from 1-21 + * + * \param deviceType The type of the constructed device + */ + Device(const std::uint8_t port, const enum DeviceType deviceType) : + _port(port), + _deviceType(deviceType) {} + + protected: + const std::uint8_t _port; + const enum DeviceType _deviceType = pros::DeviceType::none; + + ///@} +}; +} // namespace v5 +} // namespace pros + +#endif diff --git a/include/pros/distance.h b/include/pros/distance.h new file mode 100644 index 0000000..63bcd41 --- /dev/null +++ b/include/pros/distance.h @@ -0,0 +1,160 @@ +/** + * \file pros/distance.h + * \ingroup c-distance + * + * Contains prototypes for functions related to the VEX Distance sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-distance VEX Distance Sensor C API + */ + +#ifndef _PROS_DISTANCE_H_ +#define _PROS_DISTANCE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \ingroup c-distance + */ + +/** + * \addtogroup c-distance + * @{ + */ + +/** + * Get the currently measured distance from the sensor in mm + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The distance value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Distance Value: %d mm\n", distance_get(DISTANCE_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t distance_get(uint8_t port); + +/** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm (the value 10 is returned in this scenario). + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The confidence value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Distance Confidence Value: %d\n", distance_get_confidence(DISTANCE_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t distance_get_confidence(uint8_t port); + +/** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The size value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Distance Object Size: %d\n", distance_get_object_size(DISTANCE_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t distance_get_object_size(uint8_t port); + +/** + * Get the object velocity in m/s + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \param port The V5 Distance Sensor port number from 1-21 + * \return The velocity value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Distance Object Velocity: %f\n", distance_get_object_velocity(DISTANCE_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double distance_get_object_velocity(uint8_t port); + +///@} + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/include/pros/distance.hpp b/include/pros/distance.hpp new file mode 100644 index 0000000..288dff1 --- /dev/null +++ b/include/pros/distance.hpp @@ -0,0 +1,191 @@ +/** + * \file pros/distance.hpp + * \ingroup cpp-distance + * + * Contains prototypes for the V5 Distance Sensor-related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-distance VEX Distance Sensor C++ API + */ + +#ifndef _PROS_DISTANCE_HPP_ +#define _PROS_DISTANCE_HPP_ + +#include +#include + +#include "pros/device.hpp" +#include "pros/distance.h" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-distance + */ +class Distance : public Device { + /** + * \addtogroup cpp-distance + * @{ + */ + public: + /** + * Creates a Distance Sensor object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a Distance Sensor + * + * \param port + * The V5 port number from 1-21 + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + * Distance distance(DISTANCE_PORT); + * } + * \endcode + */ + explicit Distance(const std::uint8_t port); + + /** + * Get the currently measured distance from the sensor in mm + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \return The distance value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + Distance distance(DISTANCE_PORT); + * while (true) { + * printf("Distance confidence: %d\n", distance.get()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get(); + + /** + * Get the confidence in the distance reading + * + * This is a value that has a range of 0 to 63. 63 means high confidence, + * lower values imply less confidence. Confidence is only available + * when distance is > 200mm. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \return The confidence value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + Distance distance(DISTANCE_PORT); + * while (true) { + * printf("Distance confidence: %d\n", distance.get_confidence()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_confidence(); + + /** + * Get the current guess at relative object size + * + * This is a value that has a range of 0 to 400. + * A 18" x 30" grey card will return a value of approximately 75 + * in typical room lighting. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \return The size value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define DISTANCE_PORT 1 + * + * void opcontrol() { + Distance distance(DISTANCE_PORT); + * while (true) { + * printf("Distance confidence: %d\n", distance.get_object_size()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_object_size(); + + /** + * Get the object velocity in m/s + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Distance Sensor + * + * \return The velocity value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * + * void opcontrol() { + * Distance distance(DISTANCE_PORT); + * while (true) { + * printf("Distance Object velocity: %f\n", distance.get_object_velocity()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_object_velocity(); + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * Distance [port: (port number), distance: (distance), confidence: (confidence), + * object size: (object size), object velocity: (object velocity)] + */ + friend std::ostream& operator<<(std::ostream& os, pros::Distance& distance); + + private: + ///@} +}; + +namespace literals { +const pros::Distance operator"" _dist(const unsigned long long int d); +} // namespace literals +} +} // namespace pros + +#endif diff --git a/include/pros/error.h b/include/pros/error.h new file mode 100644 index 0000000..17dd6d3 --- /dev/null +++ b/include/pros/error.h @@ -0,0 +1,42 @@ +/** + * \file pros/error.h + * + * Contains macro definitions for return types, mostly errors + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef _PROS_ERROR_H_ +#define _PROS_ERROR_H_ + +#include "limits.h" + +// Different Byte Size Errors + +/// @brief +/// Return This on Byte Sized Return Error +#define PROS_ERR_BYTE (INT8_MAX) + +/// @brief +/// Return This on 2 Byte Sized Return Error +#define PROS_ERR_2_BYTE (INT16_MAX) + +/// @brief +/// Return This on 4 Byte Sized Return Error +#define PROS_ERR (INT32_MAX) + +/// @brief +/// Return This on 8 Byte Sized Return Error +#define PROS_ERR_F (INFINITY) + +/// @brief +/// Return This on Success (1) +#define PROS_SUCCESS (1) + +#endif diff --git a/include/pros/ext_adi.h b/include/pros/ext_adi.h new file mode 100644 index 0000000..421b193 --- /dev/null +++ b/include/pros/ext_adi.h @@ -0,0 +1,1330 @@ +/** + * \file pros/ext_adi.h + * \ingroup ext-adi + * + * Contains prototypes for interfacing with the 3-Wire Expander. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup ext-adi ADI Expander C API + * \note The internal ADI API can be found [here.](@ref c-adi) + */ + +#ifndef _PROS_EXT_ADI_H_ +#define _PROS_EXT_ADI_H_ + +#include +#include + +#include "adi.h" +#include "pros/adi.h" +#ifndef PROS_ERR +#define PROS_ERR (INT32_MAX) +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * \ingroup ext-adi + */ + +/** + * \addtogroup ext-adi + * @{ + */ + +/******************************************************************************/ +/** General ADI Use Functions **/ +/** **/ +/** These functions allow for interaction with any ADI port type **/ +/******************************************************************************/ + +/** + * Gets the configuration for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The ADI configuration for the given port + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * ext_adi_port_set_config(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * // Displays the value of E_ADI_ANALOG_IN + * printf("Port Type: %d\n", ext_adi_port_get_config(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * } + * \endcode + */ +adi_port_config_e_t ext_adi_port_get_config(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the value for the given ADI port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which to return + * the configuration + * + * \return The value stored for the given port + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * ext_adi_port_set_config(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * printf("Port Value: %d\n", ext_adi_get_value(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * } + * \endcode + */ +int32_t ext_adi_port_get_value(uint8_t smart_port, uint8_t adi_port); + +/** + * Configures an ADI port to act as a given sensor type. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param type + * The configuration type for the port + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * ext_adi_port_set_config(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT, E_ADI_ANALOG_IN); + * } + * \endcode + */ +int32_t ext_adi_port_set_config(uint8_t smart_port, uint8_t adi_port, adi_port_config_e_t type); + +/** + * Sets the value for the given ADI port. + * + * This only works on ports configured as outputs, and the behavior will change + * depending on the configuration of the port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') for which the value + * will be set + * \param value + * The value to set the ADI port to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define DIGITAL_SENSOR_PORT 1 + * + * void initialize() { + * ext_adi_port_set_config(ADI_EXPANDER_PORT, DIGITAL_SENSOR_PORT, E_ADI_DIGITAL_OUT); + * ext_adi_set_value(ADI_EXPANDER_PORT, DIGITAL_SENSOR_PORT, HIGH); + * } + * \endcode + */ +int32_t ext_adi_port_set_value(uint8_t smart_port, uint8_t adi_port, int32_t value); + +/** + * Calibrates the analog sensor on the specified port and returns the new + * calibration value. + * + * This method assumes that the true sensor value is not actively changing at + * this time and computes an average from approximately 500 samples, 1 ms apart, + * for a 0.5 s period of calibration. The average value thus calculated is + * returned and stored for later calls to the adi_analog_read_calibrated() and + * adi_analog_read_calibrated_HR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to calibrate (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The average sensor value computed by this function + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * ext_adi_analog_calibrate(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT); + * printf("Calibrated Reading: %d\n", + * ext_adi_analog_read_calibrated(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * // All readings from then on will be calibrated + * } + * \endcode + */ +int32_t ext_adi_analog_calibrate(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12-bit value of the specified port. + * + * The value returned is undefined if the analog pin has been switched to a + * different mode. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The analog sensor value, where a value of 0 reflects an input voltage + * of nearly 0 V and a value of 4095 reflects an input voltage of nearly 5 V + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Sensor Reading: %d\n", ext_adi_analog_read(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_analog_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 12 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This function is + * inappropriate for sensor values intended for integration, as round-off error + * can accumulate causing drift over time. Use adi_analog_read_calibrated_HR() + * instead. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -4095 to 4095 + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Sensor Reading: %d\n", ext_adi_analog_read_calibrated(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_analog_read_calibrated(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the 16 bit calibrated value of an analog input port. + * + * The adi_analog_calibrate() function must be run first. This is intended for + * integrated sensor values such as gyros and accelerometers to reduce drift due + * to round-off, and should not be used on a sensor such as a line tracker + * or potentiometer. + * + * The value returned actually has 16 bits of "precision", even though the ADC + * only reads 12 bits, so that error induced by the average value being between + * two values when integrated over time is trivial. Think of the value as the + * true value times 16. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an analog input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port (from 1-8, 'a'-'h', 'A'-'H') for which the value will be + * returned + * + * \return The difference of the sensor value from its calibrated default from + * -16384 to 16384 + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * ext_adi_analog_calibrate(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT); + * + * printf("Sensor Reading: %d\n", ext_adi_analog_read_calibrated_HR(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_analog_read_calibrated_HR(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets the digital value (1 or 0) of a port configured as a digital input. + * + * If the port is configured as some other mode, the digital value which + * reflects the current state of the port is returned, which may or may not + * differ from the currently set value. The return value is undefined for ports + * configured as any mode other than a Digital Input. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return True if the pin is HIGH, or false if it is LOW + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf(“Sensor Value: %dn”, + * ext_adi_digital_read(ADI_EXPANDER_PORT, DIGITAL_SENSOR_PORT)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_digital_read(uint8_t smart_port, uint8_t adi_port); + +/** + * Gets a rising-edge case for a digital button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under the + * same circumstances, so only one task should call this function for any given + * button. E.g., Task A calls this function for buttons 1 and 2. Task B may call + * this function for button 3, but should not for buttons 1 or 2. A typical + * use-case for this function is to call inside opcontrol to detect new button + * presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital input + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to read (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the button is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * while (true) { + * if (ext_adi_digital_get_new_press(ADI_EXPANDER_PORT, DIGITAL_SENSOR_PORT)) { + * // Toggle pneumatics or other state operations + * } + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_digital_get_new_press(uint8_t smart_port, uint8_t adi_port); + +/** + * Sets the digital value (1 or 0) of a port configured as a digital output. + * + * If the port is configured as some other mode, behavior is undefined. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a digital output + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param value + * An expression evaluating to "true" or "false" to set the output to + * HIGH or LOW respectively, or the constants HIGH or LOW themselves + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define DIGITAL_SENSOR_PORT 1 + * + * void opcontrol() { + * bool state = LOW; + * while (true) { + * state != state; + * ext_adi_digital_write(ADI_EXPANDER_PORT, DIGITAL_SENSOR_PORT, state); + * + * delay(5); // toggle the sensor value every 50ms + * } + * } + * \endcode + */ +int32_t ext_adi_digital_write(uint8_t smart_port, uint8_t adi_port, bool value); + +/** + * Configures the port as an input or output with a variety of settings. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param mode + * One of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define ANALOG_SENSOR_PORT 1 + * + * void initialize() { + * ext_adi_pin_mode(ADI_EXPANDER_PORT, ANALOG_SENSOR_PORT, INPUT_ANALOG); + * } + * \endcode + */ +int32_t ext_adi_pin_mode(uint8_t smart_port, uint8_t adi_port, uint8_t mode); + +/** + * Sets the speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port number (from 1-8, 'a'-'h', 'A'-'H') to configure + * \param speed + * The new signed speed; -127 is full reverse and 127 is full forward, + * with 0 being off + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * ext_adi_motor_set(ADI_EXPANDER_PORT, MOTOR_PORT, 127); // Go full speed forward + * delay(1000); + * ext_adi_motor_set(ADI_EXPANDER_PORT, MOTOR_PORT, 0); // Stop the motor + * } + * \endcode + */ +int32_t ext_adi_motor_set(uint8_t smart_port, uint8_t adi_port, int8_t speed); + +/** + * Gets the last set speed of the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to get (from 1-8, 'a'-'h', 'A'-'H') + * + * \return The last set speed of the motor on the given port + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 # + * define MOTOR_PORT 1 + * + * void opcontrol() { + * ext_adi_motor_set(ADI_EXPANDER_PORT, + * MOTOR_PORT, 127); // Go full speed forward + * printf(“Commanded Motor Power: %dn”, + * ext_adi_motor_get(ADI_EXPANDER_PORT, MOTOR_PORT)); // Will display 127 + * delay(1000); + * ext_adi_motor_set(ADI_EXPANDER_PORT, MOTOR_PORT, 0); // Stop the motor + * } + * \endcode + */ +int32_t ext_adi_motor_get(uint8_t smart_port, uint8_t adi_port); + +/** + * Stops the motor on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an motor + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to set (from 1-8, 'a'-'h', 'A'-'H') + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define MOTOR_PORT 1 + * + * void opcontrol() { + * ext_adi_motor_set(ADI_EXPANDER_PORT, MOTOR_PORT, 127); // Go full speed forward + * delay(1000); + * ext_adi_motor_set(ADI_EXPANDER_PORT, MOTOR_PORT, 0); // Stop the motor + * ext_adi_motor_stop(ADI_EXPANDER_PORT, MOTOR_PORT); // use this instead + * } + * \endcode + */ +int32_t ext_adi_motor_stop(uint8_t smart_port, uint8_t adi_port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder. + */ +typedef int32_t ext_adi_encoder_t; + +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to read + * + * \return The signed and cumulative number of counts since the last start or + * reset + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define PORT_TOP 1 #define PORT_BOTTOM 2 + * + * void opcontrol() { + * ext_adi_encoder_t enc = ext_adi_encoder_init(ADI_EXPANDER_PORT, + * PORT_TOP, PORT_BOTTOM, false); + * while (true) { + * printf(“Encoder Value: %dn”, + * ext_adi_encoder_get(enc)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_encoder_get(ext_adi_encoder_t enc); + +/** + * Creates an encoder object and configures the specified ports accordingly. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_top + * The "top" wire from the encoder sensor with the removable cover side + * up. This should be in port 1, 3, 5, or 7 ('A', 'C', 'E', or 'G'). + * \param adi_port_bottom + * The "bottom" wire from the encoder sensor + * \param reverse + * If "true", the sensor will count in the opposite direction + * + * \return An adi_encoder_t object to be stored and used for later calls to + * encoder functions + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * ext_adi_encoder_t enc = ext_adi_encoder_init(ADI_EXPANDER_PORT, PORT_TOP, PORT_BOTTOM, false); + * while (true) { + * printf("Encoder Value: %d\n", ext_adi_encoder_get(enc)); + * delay(5); + * } + * } + * \endcode + */ +ext_adi_encoder_t ext_adi_encoder_init(uint8_t smart_port, uint8_t adi_port_top, uint8_t adi_port_bottom, bool reverse); + +/** + * Sets the encoder value to zero. + * + * It is safe to use this method while an encoder is enabled. It is not + * necessary to call this method before stopping or starting an encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to reset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * ext_adi_encoder_t enc = ext_adi_encoder_init(ADI_EXPANDER_PORT, PORT_TOP, PORT_BOTTOM, false); + * delay(1000); // Move the encoder around in this time + * ext_adi_encoder_reset(enc); // The encoder is now zero again + * } + * \endcode + */ +int32_t ext_adi_encoder_reset(ext_adi_encoder_t enc); + +/** + * Disables the encoder and voids the configuration on its ports. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an encoder + * + * \param enc + * The adi_encoder_t object from adi_encoder_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define ADI_EXPANDER_PORT 20 + * #define PORT_TOP 1 + * #define PORT_BOTTOM 2 + * + * void opcontrol() { + * ext_adi_encoder_t enc = ext_adi_encoder_init(ADI_EXPANDER_PORT, PORT_TOP, PORT_BOTTOM, false); + * // Use the encoder + * ext_adi_encoder_shutdown(enc); + * } + * \endcode + */ +int32_t ext_adi_encoder_shutdown(ext_adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic. + */ +typedef int32_t ext_adi_ultrasonic_t; + +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found, zero is returned. If the ultrasonic sensor was never + * started, the return value is undefined. Round and fluffy objects can cause + * inaccurate values to be returned. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to read + * + * \return The distance to the nearest object in m^-4 (10000 indicates 1 meter), + * measured from the sensor's mounting points. + * + * \b Example + * \code + * + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_ultrasonic_t ult = ext_adi_ultrasonic_init(ADI_EXPANDER_PORT, PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", ext_adi_ultrasonic_get(ult)); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_ultrasonic_get(ext_adi_ultrasonic_t ult); + +/** + * Creates an ultrasonic object and configures the specified ports accordingly. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port_ping + * The port connected to the orange OUTPUT cable. This should be in port + * 1, 3, 5, or 7 ('A', 'C', 'E', 'G'). + * \param adi_port_echo + * The port connected to the yellow INPUT cable. This should be in the + * next highest port following port_ping. + * + * \return An adi_ultrasonic_t object to be stored and used for later calls to + * ultrasonic functions + * + * \b Example + * \code + * + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_ultrasonic_t ult = ext_adi_ultrasonic_init(ADI_EXPANDER_PORT, PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", ext_adi_ultrasonic_get(ult)); + * delay(5); + * } + * } + * \endcode + */ +ext_adi_ultrasonic_t ext_adi_ultrasonic_init(uint8_t smart_port, uint8_t adi_port_ping, uint8_t adi_port_echo); + +/** + * Disables the ultrasonic sensor and voids the configuration on its ports. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as an ultrasonic + * + * \param ult + * The adi_ultrasonic_t object from adi_ultrasonic_init() to stop + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define PORT_PING 1 + * #define PORT_ECHO 2 + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_ultrasonic_t ult = ext_adi_ultrasonic_init(ADI_EXPANDER_PORT, PORT_PING, PORT_ECHO); + * while (true) { + * // Print the distance read by the ultrasonic + * printf("Distance: %d\n", ext_adi_ultrasonic_get(ult)); + * delay(5); + * } + * ext_adi_ultrasonic_shutdown(ult); + * } + * \endcode + */ +int32_t ext_adi_ultrasonic_shutdown(ext_adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope. + * + * (Might Be useless with the wire expander.) + */ +typedef int32_t ext_adi_gyro_t; + +/** + * Gets the current gyro angle in tenths of a degree. Unless a multiplier is + * applied to the gyro, the return value will be a whole number representing + * the number of degrees of rotation times 10. + * + * There are 360 degrees in a circle, thus the gyro will return 3600 for one + * whole rotation. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return The gyro angle in degrees. + * + * \b Example + * \code + * + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_gyro_t gyro = ext_adi_gyro_init(ADI_EXPANDER_PORT, GYRO_PORT, GYRO_MULTIPLIER); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", ext_adi_gyro_get(gyro)); + * delay(5); + * } + * } + * \endcode + */ +double ext_adi_gyro_get(ext_adi_gyro_t gyro); + +/** + * Initializes a gyroscope on the given port. If the given port has not + * previously been configured as a gyro, then this function starts a 1300 ms + * calibration period. + * + * It is highly recommended that this function be called from initialize() when + * the robot is stationary to ensure proper calibration. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param smart_port + * The smart port number that the ADI Expander is in + * \param adi_port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param multiplier + * A scalar value that will be multiplied by the gyro heading value + * supplied by the ADI + * + * \return An adi_gyro_t object containing the given port, or PROS_ERR if the + * initialization failed. + * + * \b Example + * \code + * + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_gyro_t gyro = ext_adi_gyro_init(ADI_EXPANDER_PORT, GYRO_PORT, GYRO_MULTIPLIER); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", ext_adi_gyro_get(gyro)); + * delay(5); + * } + * } + * \endcode + */ +ext_adi_gyro_t ext_adi_gyro_init(uint8_t smart_port, uint8_t adi_port, double multiplier); + +/** + * Resets the gyroscope value to zero. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object for which the angle will be returned + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_gyro_t gyro = ext_adi_gyro_init(ADI_EXPANDER_PORT, GYRO_PORT, GYRO_MULTIPLIER); + * uint32_t now = millis(); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", ext_adi_gyro_get(gyro)); + * + * if (millis() - now > 2000) { + * // Reset the gyro every 2 seconds + * ext_adi_gyro_reset(gyro); + * now = millis(); + * } + * + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_gyro_reset(ext_adi_gyro_t gyro); + +/** + * Disables the gyro and voids the configuration on its port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - Either the ADI port value or the smart port value is not within its + * valid range (ADI port: 1-8, 'a'-'h', or 'A'-'H'; smart port: 1-21). + * EADDRINUSE - The port is not configured as a gyro + * + * \param gyro + * The adi_gyro_t object to be shut down + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define GYRO_PORT 1 + * #define GYRO_MULTIPLIER 1 // Standard behavior + * #define ADI_EXPANDER_PORT 20 + * + * void opcontrol() { + * ext_adi_gyro_t gyro = ext_adi_gyro_init(ADI_EXPANDER_PORT, GYRO_PORT, GYRO_MULTIPLIER); + * uint32_t now = millis(); + * while (true) { + * // Print the gyro's heading + * printf("Heading: %lf\n", ext_adi_gyro_get(gyro)); + * + * if (millis() - now > 2000) { + * ext_adi_gyro_shutdown(gyro); + * // Shut down the gyro after two seconds + * break; + * } + * + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_gyro_shutdown(ext_adi_gyro_t gyro); + +/** + * Reference type for an initialized potentiometer. + * + * This merely contains the port number for the potentiometer. + */ +typedef int32_t ext_adi_potentiometer_t; + +/** + * Initializes a potentiometer on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param port + * The ADI port to initialize as a gyro (from 1-8, 'a'-'h', 'A'-'H') + * \param potentiometer_type + * An adi_potentiometer_type_e_t enum value specifying the potentiometer version type + * + * \return An adi_potentiometer_t object containing the given port, or PROS_ERR if the + * initialization failed. + */ +ext_adi_potentiometer_t ext_adi_potentiometer_init(uint8_t smart_port, uint8_t adi_port, adi_potentiometer_type_e_t potentiometer_type); + +/** + * Gets the current potentiometer angle in tenths of a degree. + * + * The original potentiometer rotates 250 degrees thus returning an angle between 0-250 degrees. + * Potentiometer V2 rotates 333 degrees thus returning an angle between 0-333 degrees. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EADDRINUSE - The port is not configured as a potentiometer + * + * \param potentiometer + * The adi_potentiometer_t object for which the angle will be returned + * + * \return The potentiometer angle in degrees. + */ +double ext_adi_potentiometer_get_angle(ext_adi_potentiometer_t potentiometer); + +/** + * Reference type for an initialized addressable led. + * + * This merely contains the port number for the led, unlike its use as an + * object to store led data in the C++ API. + */ +typedef int32_t ext_adi_led_t; + +/** + * Initializes a led on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * \param smart_port + * The smart port with the adi expander (1-21) + * \param adi_port + * The ADI port to initialize as a led (from 1-8, 'a'-'h', 'A'-'H') + * + * \return An ext_adi_led_t object containing the given port, or PROS_ERR if the + * initialization failed. + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with a single color of red + * uint32_t buffer[1] = {0xFF0000}; + * + * while (true) { + * // Set the led to colors in the buffer + * ext_adi_led_set(led, buffer, 1); + * delay(5); + * } + * } + * \endcode + */ +ext_adi_led_t ext_adi_led_init(uint8_t smart_port, uint8_t adi_port); + +/** + * @brief Clear the entire led strip of color + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with a single color of red + * uint32_t buffer[1] = {0xFF0000}; + * + * while (true) { + * // Set the led to colors in the buffer + * ext_adi_led_set(led, buffer, 1); + * delay(5); + * + * // Clear the led + * ext_adi_led_clear_all(led, buffer, 1); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_led_clear_all(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip using the colors contained in the buffer + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with a single color of red + * uint32_t buffer[1] = {0xFF0000}; + * + * while (true) { + * // Set the led to colors in the buffer + * ext_adi_led_set(led, buffer, 1); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_led_set(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length); + +/** + * @brief Set the entire led strip to one color + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of buffer to clear + * @param color color to set all the led strip value to + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with a single color of red + * uint32_t buffer[1] = {0xFF0000}; + * + * while (true) { + * // Set the entire led strip to red + * ext_adi_led_set_all(led, buffer, 1, 0xFF0000); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_led_set_all(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t color); + +/** + * @brief Set one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param color color to clear all the led strip to + * @param pixel_position position of the pixel to clear (0 indexed) + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with multiple colors + * uint32_t buffer[3] = {0xFF0000, 0x00FF00, 0x0000FF}; + * + * while (true) { + * // Set the first pixel to red + * ext_adi_led_set_pixel(led, buffer, 3, 0xFF0000, 0); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_led_set_pixel(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t color, uint32_t pixel_position); + +/** + * @brief Clear one pixel on the led strip + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of ADI Ports + * EINVAL - A given value is not correct, or the buffer is null + * EADDRINUSE - The port is not configured for ADI output + * + * @param led port of type adi_led_t + * @param buffer array of colors in format 0xRRGGBB, recommended that individual RGB value not to exceed 0x80 due to current draw + * @param buffer_length length of the input buffer + * @param pixel_position position of the pixel to clear (0 indexed) + * @return PROS_SUCCESS if successful, PROS_ERR if not + * + * \b Example: + * \code + * #define SMART_PORT 1 + * #define ADI_PORT 'A' + * + * void opcontrol() { + * // Initialize a led on smart port 1 and adi port A + * ext_adi_led_t led = ext_adi_led_init(SMART_PORT, ADI_PORT); + * // Initialize a buffer with multiple colors + * uint32_t buffer[3] = {0xFF0000, 0x00FF00, 0x0000FF}; + * + * while (true) { + * // Set the first pixel to red + * ext_adi_led_set_pixel(led, buffer, 3, 0xFF0000, 0); + * delay(5); + * + * // Clear the first pixel + * ext_adi_led_clear_pixel(led, buffer, 3, 0); + * delay(5); + * } + * } + * \endcode + */ +int32_t ext_adi_led_clear_pixel(ext_adi_led_t led, uint32_t* buffer, uint32_t buffer_length, uint32_t pixel_position); + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_ADI_H_ diff --git a/include/pros/gps.h b/include/pros/gps.h new file mode 100644 index 0000000..9304e0f --- /dev/null +++ b/include/pros/gps.h @@ -0,0 +1,668 @@ +/** + * \file pros/gps.h + * \ingroup c-gps + * + * Contains prototypes for functions related to the VEX GPS. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-gps VEX GPS Sensor C API + * \note For a pros-specific usage guide on the GPS, please check out our article [here.](@ref gps) + */ + +#ifndef _PROS_GPS_H_ +#define _PROS_GPS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \ingroup c-gps + */ + +/** + * \addtogroup c-gps + * @{ + */ + +/** + * \struct gps_position_s_t + */ +typedef struct __attribute__((__packed__)) gps_position_s { + /// X Position (meters) + double x; + /// Y Position (meters) + double y; +} gps_position_s_t; + +/** + * \struct gps_status_s_t + */ +typedef struct __attribute__((__packed__)) gps_status_s { + /// X Position (meters) + double x; + /// Y Position (meters) + double y; + /// Percieved Pitch based on GPS + IMU + double pitch; + /// Percieved Roll based on GPS + IMU + double roll; + /// Percieved Yaw based on GPS + IMU + double yaw; +} gps_status_s_t; + +/** + * \struct gps_raw_s + */ +struct gps_raw_s { + /// Percieved Pitch based on GPS + IMU + double x; + /// Percieved Roll based on GPS + IMU + double y; + /// Percieved Yaw based on GPS + IMU + double z; +}; + +/** + * \struct gps_accel_s_t + * + */ +typedef struct gps_raw_s gps_accel_s_t; + +/** + * \struct gps_gyro_s_t + * + */ +typedef struct gps_raw_s gps_gyro_s_t; + +#ifdef __cplusplus +namespace c { +#endif + + +/** + * Set the GPS's offset relative to the center of turning in meters, + * as well as its initial position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Heading with 0 being north on the field, in degrees [0,360) going clockwise + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * #define X_OFFSET .225 + * #define Y_OFFSET .223 + * #define X_INITIAL 1.54 + * #define Y_INITIAL 1.14 + * #define HEADING_INITIAL 90 + * + * void initialize() { + * gps_initialize_full(GPS_PORT, X_OFFSET, Y_OFFSET, X_INITIAL, Y_INITIAL, HEADING_INITIAL); + * } + * \endcode + */ +int32_t gps_initialize_full(uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, + double yOffset); + +/** + * Set the GPS's offset relative to the center of turning in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * #define X_OFFSET -.225 + * #define Y_OFFSET .225 + * + * void initialize() { + * gps_set_offset(GPS_PORT, X_OFFSET, Y_OFFSET); + * } + * \endcode + */ +int32_t gps_set_offset(uint8_t port, double xOffset, double yOffset); + +/** + * Gets the position and roll, yaw, and pitch of the GPS. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return A struct (gps_status_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_status_s_t status; + * + * while (true) { + * status = gps_get_status(GPS_PORT); + * printf("X: %f, Y: %f, Pitch: %f, Roll: %f, Yaw: %f\n", status.x, status.y, status.pitch, status.roll, status.yaw); + * delay(20); + * } + * } + * \endcode + */ +gps_status_s_t gps_get_status(uint8_t port); + +/** + * Gets the x and y position on the field of the GPS in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return A struct (gps_position_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_position_s_t position; + * + * while (true) { + * position = gps_get_position(GPS_PORT); + * printf("X: %f, Y: %f\n", position.x, position.y); + * delay(20); + * } + * } + * \endcode + */ +gps_position_s_t gps_get_position(uint8_t port); + +/** + * Get the GPS's raw gyroscope values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return The raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_gyro_s_t gyro; + * + * while (true) { + * gyro = gps_get_gyro(GPS_PORT); + * printf("Gyro: %f %f %f\n", gyro.x, gyro.y, gyro.z); + * delay(20); + * } + * } + * \endcode + */ +gps_gyro_s_t gps_get_gyro_rate(uint8_t port); + +/** + * Get the GPS's raw accelerometer values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_accel_s_t accel; + * + * while (true) { + * accel = gps_get_accel(GPS_PORT); + * printf("X: %f, Y: %f, Z: %f\n", accel.x, accel.y, accel.z); + * delay(20); + * } + * } + * \endcode + */ +gps_accel_s_t gps_get_accel(uint8_t port); + +/** + * Get the GPS's cartesian location relative to the center of turning/origin in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return A struct (gps_position_s_t) containing the X and Y values if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_position_s_t pos; + * + * while (true) { + * pos = gps_get_offset(GPS_PORT, x, y); + * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ +gps_position_s_t gps_get_offset(uint8_t port); + +/** + * Sets the robot's location relative to the center of the field in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Heading with 0 being north on the field, in degrees [0,360) going clockwise + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * #define X_INITIAL -1.15 + * #define Y_INITIAL 1.45 + * #define HEADING_INITIAL 90 + * + * void initialize() { + * gps_set_position(GPS_PORT, X_INITIAL, Y_INITIAL, HEADING_INITIAL); + * } + * \endcode + */ +int32_t gps_set_position(uint8_t port, double xInitial, double yInitial, double headingInitial); + +/** + * Set the GPS sensor's data rate in milliseconds, only applies to IMU on GPS. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \param rate + * Data rate in milliseconds (Minimum: 5 ms) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * #define GPS_DATA_RATE 5 + * + * void initialize() { + * gps_set_data_rate(GPS_PORT, GPS_DATA_RATE); + * while (true) { + * // Do something + * } + * } + * \endcode + */ +int32_t gps_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Get the possible RMS (Root Mean Squared) error in meters for GPS position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return Possible RMS (Root Mean Squared) error in meters for GPS position. + * If the operation failed, returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double error; + * error = gps_get_error(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "Error: %4d", error); + * } + * \endcode + */ +double gps_get_error(uint8_t port); + +/** + * Gets the position and roll, yaw, and pitch of the GPS. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return A struct (gps_status_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * struct gps_status_s_t status; + * + * while (true) { + * status = gps_get_status(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "x: %3f, y: %3f, pitch: %3f", status.x, status.y); + * screen_print(TEXT_MEDIUM, 2, "yaw: %3f, roll: %3f", status.pitch, status.yaw); + * screen_print(TEXT_MEDIUM, 3, "roll: %3f", status.roll); + * delay(20); + * } + * } + * \endcode + */ +gps_status_s_t gps_get_status(uint8_t port); + +/** + * Get the heading in [0,360) degree values. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return The heading in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double heading; + * + * while (true) { + * heading = gps_get_heading(GPS_PORT); + * delay(20); + * } + * } + * \endcode + */ +double gps_get_heading(uint8_t port); + +/** + * Get the heading in the max double value and min double value scale. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * + * \return The heading in [DOUBLE_MIN, DOUBLE_MAX] values. If the operation + * fails, returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double heading; + * + * while (true) { + * heading = gps_get_heading_raw(GPS_PORT); + * delay(20); + * } + * } + * \endcode + */ +double gps_get_heading_raw(uint8_t port); + +/** + * Gets the GPS sensor's elapsed rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return The elased heading in degrees. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * double elapsed_rotation; + * + * elapsed_rotation = gps_get_rotation(GPS_PORT); + * printf("Elapsed rotation: %3f", elapsed_rotation); + * } + * \endcode + */ +double gps_get_rotation(uint8_t port); + +/** + * Set the GPS sensor's rotation value to target value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \param target + * Target rotation value to set rotation value to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_set_rotation(GPS_PORT, 60); + * printf("Elapsed rotation: %3f", gps_get_rotation(GPS_PORT)); + * } + * \endcode + */ +int32_t gps_set_rotation(uint8_t port, double target); + +/** + * Tare the GPS sensor's rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void initialize() { + * gps_tare_rotation(GPS_PORT); + * printf("Elapsed rotation: %3f", gps_get_rotation(GPS_PORT)); // should be 0 + * } + * \endcode + */ +int32_t gps_tare_rotation(uint8_t port); + +/** + * Get the GPS's raw gyroscope values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return The raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * struct gps_gyro_s_t gyro; + * + * while (true) { + * gyro = gps_get_gyro_rate(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "gyroscope- x: %3f, y: %3f, z: %3f", gyro.x, gyro.y, gyro.z); + * delay(20); + * } + * } + * \endcode + */ +gps_gyro_s_t gps_get_gyro_rate(uint8_t port); + +/** + * Get the GPS's raw accelerometer values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * struct gps_accel_s_t accel; + * + * while (true) { + * accel = gps_get_accel(GPS_PORT); + * screen_print(TEXT_MEDIUM, 1, "accleration- x: %3f, y: %3f, z: %3f", accel.x, accel.y, accel.z); + * } + * } + * \endcode + */ +gps_accel_s_t gps_get_accel(uint8_t port); + +///@} + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/include/pros/gps.hpp b/include/pros/gps.hpp new file mode 100644 index 0000000..d081d61 --- /dev/null +++ b/include/pros/gps.hpp @@ -0,0 +1,649 @@ +/** + * \file pros/gps.hpp + * \ingroup cpp-gps + * + * Contains prototypes for functions related to the VEX GPS. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-gps VEX GPS Sensor C API + * \note For a pros-specific usage guide on the GPS, please check out our article [here.](@ref gps) + */ + +#ifndef _PROS_GPS_HPP_ +#define _PROS_GPS_HPP_ + +#include + +#include +#include + +#include "pros/gps.h" +#include "pros/device.hpp" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-gps + * @{ + */ +class Gps : public Device { + /** + * \addtogroup cpp-gps + * @{ + */ + + public: + + /** + * Creates a GPS object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 port number from 1-21 + * \b Example: + * \code + * pros::Gps gps(1); + * \endcode + * + */ + explicit Gps(const std::uint8_t port) : Device(port, DeviceType::gps){}; + + /** + * Creates a GPS object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 port number from 1-21 + * \param xInitial + * Cartesian 4-Quadrant X initial position (meters) + * \param yInitial + * Cartesian 4-Quadrant Y initial position (meters) + * \param headingInitial + * Initial heading (degrees) + * + * \b Example: + * \code + * pros::Gps gps(1, 1.30, 1.20, 90); + * \endcode + * + */ + explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial) : Device(port, DeviceType::gps){ + pros::c::gps_set_position(port, xInitial, yInitial, headingInitial); + }; + + /** + * Creates a GPS object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 port number from 1-21 + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * + * \b Example: + * \code + * pros::Gps gps(1, 1.30, 1.20); + * \endcode + * + */ + explicit Gps(const std::uint8_t port, double xOffset, double yOffset) : Device(port, DeviceType::gps){ + pros::c::gps_set_offset(port, xOffset, yOffset); + }; + + /** + * Creates a GPS object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 port number from 1-21 + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Initial Heading, with 0 being North, 90 being East, 180 being South, and 270 being West (degrees) + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * + * \b Example: + * \code + * pros::Gps gps(1, 1.30, 1.20, 180, 1.30, 1.20); + * \endcode + * + */ + explicit Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, double yOffset) + : Device(port, DeviceType::gps){ + pros::c::gps_initialize_full(port, xInitial, yInitial, headingInitial, xOffset, yOffset); + }; + + /** + * Set the GPS's offset relative to the center of turning in meters, + * as well as its initial position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Heading with 0 being north on the field, in degrees [0,360) going clockwise + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT, 1.1, 1.2, 180, .4, .4); + * // this is equivalent to the above line + * gps.initialize_full(1.1, 1.2, 180, .4, .4); + * while (true) { + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t initialize_full(double xInitial, double yInitial, double headingInitial, double xOffset, + double yOffset) const; + + /** + * Set the GPS's offset relative to the center of turning in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param xOffset + * Cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Cartesian 4-Quadrant Y offset from center of turning (meters) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT, 1.1, 1.2, 180, .4, .4); + * // this is equivalent to the above line + * gps.set_offset(.4, .4); + * while (true) { + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t set_offset(double xOffset, double yOffset) const; + + /** + * Get the GPS's cartesian location relative to the center of turning/origin in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS port number from 1-21 + * \return A struct (gps_position_s_t) containing the X and Y values if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * gps_position_s_t pos; + * Gps gps(GPS_PORT); + * while (true) { + * pos = gps.get_offset(); + * screen_print(TEXT_MEDIUM, 1, "X Offset: %4d, Y Offset: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ + virtual pros::gps_position_s_t get_offset() const; + + /** + * Sets the robot's location relative to the center of the field in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param xInitial + * Initial 4-Quadrant X Position, with (0,0) being at the center of the field (meters) + * \param yInitial + * Initial 4-Quadrant Y Position, with (0,0) being at the center of the field (meters) + * \param headingInitial + * Heading with 0 being north on the field, in degrees [0,360) going clockwise + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps.set_position(1.3, 1.4, 180); + * while (true) { + * printf("X: %f, Y: %f, Heading: %f\n", gps.get_position().x, + * gps.get_position().y, gps.get_position().heading); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t set_position(double xInitial, double yInitial, double headingInitial) const; + + /** + * Set the GPS sensor's data rate in milliseconds, only applies to IMU on GPS. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param rate + * Data rate in milliseconds (Minimum: 5 ms) + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps.set_data_rate(10); + * while (true) { + * printf("X: %f, Y: %f, Heading: %f\n", gps.get_position().x, + * gps.get_position().y, gps.get_position().heading); + * delay(10); + * } + * } + * \endcode + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + + /** + * Get the possible RMS (Root Mean Squared) error in meters for GPS position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return Possible RMS (Root Mean Squared) error in meters for GPS position. + * If the operation failed, returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * double error = gps.get_error(); + * printf("Error: %f\n", error); + * pros::delay(20); + * } + * \endcode + */ + virtual double get_error() const; + + /** + * Gets the position and roll, yaw, and pitch of the GPS. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * + * \return A struct (gps_status_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps_status_s_t status; + * while (true) { + * status = gps.get_status(); + * printf("X: %f, Y: %f, Heading: %f, Roll: %f, Pitch: %f, Yaw: %f\n", + * status.x, status.y, status.heading, status.roll, status.pitch, status.yaw); + * delay(20); + * } + * } + * \endcode + */ + virtual pros::gps_status_s_t get_status() const; + + /** + * Gets the x and y position on the field of the GPS in meters. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return A struct (gps_position_s_t) containing values mentioned above. + * If the operation failed, all the structure's members are filled with + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps_position_s_t position; + * while (true) { + * position = gps.get_position(); + * printf("X: %f, Y: %f, Heading: %f\n", position.x, position.y, + * position.heading); + * delay(20); + * } + * } + * \endcode + */ + virtual pros::gps_position_s_t get_position() const; + + /** + * Get the heading in [0,360) degree values. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * + * \return The heading in [0,360) degree values. If the operation failed, + * returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double heading = gps.get_heading(); + * printf("Heading: %f\n", heading); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_heading() const; + + /** + * Get the heading in the max double value and min double value scale. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return The heading in [DOUBLE_MIN, DOUBLE_MAX] values. If the operation + * fails, returns PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * double heading = gps.get_heading_raw(); + * printf("Heading: %f\n", heading); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_heading_raw() const; + + /** + * Gets the GPS sensor's elapsed rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return The elased heading in degrees. If the operation fails, returns + * PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + double rotation = gps.get_rotation(); + * printf("Rotation: %f\n", rotation); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual double get_rotation() const; + + /** + * Set the GPS sensor's rotation value to target value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \param target + * Target rotation value to set rotation value to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * double rotation = gps.set_rotation(90); + * while(true) { + * printf("Rotation: %f\n", rotation); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t set_rotation(double target) const; + + /** + * Tare the GPS sensor's rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * gps.tare_rotation(); + * while(true) { + * Should be around 0 on first call since it was tared. + * printf("Rotation: %f\n", rotation); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_rotation() const; + + /** + * Get the GPS's raw gyroscope values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a GPS + * EAGAIN - The sensor is still calibrating + * + * \return The raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * pros::gps_gyro_s_t gyro = gps.get_gyro_rate(); + * printf("Gyro: %f, %f, %f\n", gyro.x, gyro.y, gyro.z); + * pros::delay(20); + * } + * } + * \endcode + */ + virtual pros::gps_gyro_s_t get_gyro_rate() const; + + /** + * Get the GPS's raw accelerometer values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an GPS + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 GPS's port number from 1-21 + * \return The raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + */ + virtual pros::gps_accel_s_t get_accel() const; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format: + * Gps [port: gps._port, x: (x position), y: (y position), heading: (gps heading), rotation: (gps rotation)] + * + * \b Example + * \code + * #define GPS_PORT 1 + * + * void opcontrol() { + * Gps gps(GPS_PORT); + * while(true) { + * std::cout << gps << std::endl; + * pros::delay(20); + * } + * } + * \endcode + */ + friend std::ostream& operator<<(std::ostream& os, const pros::Gps& gps); + +///@} +}; // Gps Class + +namespace literals { + /** + * Constructs a Gps object with the given port number + * + * \b Example + * \code + * using namespace literals; + * + * void opcontrol() { + * pros::Gps gps = 1_gps; + * while (true) { + * pos = gps.get_position(); + * screen_print(TEXT_MEDIUM, 1, "X Position: %4d, Y Position: %4d", pos.x, pos.y); + * delay(20); + * } + * } + * \endcode + */ + const pros::Gps operator""_gps(const unsigned long long int g); +} // namespace literals + +/// @brief +/// Alias for Gps is GPS for user convenience. +using GPS = Gps; + +} // namespace v5 +} // namespace pros + +#endif diff --git a/include/pros/imu.h b/include/pros/imu.h new file mode 100644 index 0000000..bf724ab --- /dev/null +++ b/include/pros/imu.h @@ -0,0 +1,947 @@ +/** + * \file pros/imu.h + * \ingroup c-imu + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-imu VEX Inertial Sensor C API + */ + +#ifndef _PROS_IMU_H_ +#define _PROS_IMU_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \ingroup c-imu + * */ + +/** + * \addtogroup c-imu + * @{ + */ + +/** + * \enum imu_status_e_t + * @brief Indicates IMU status. + */ +typedef enum imu_status_e { + /** The IMU is calibrating */ + E_IMU_STATUS_CALIBRATING = 0x01, + /** Used to indicate that an error state was reached in the imu_get_status function,\ + not that the IMU is necessarily in an error state */ + E_IMU_STATUS_ERROR = 0xFF, +} imu_status_e_t; + +/** + * \struct quaternion_s_t + */ +typedef struct __attribute__((__packed__)) quaternion_s { + double x; + double y; + double z; + double w; +} quaternion_s_t; + +/** + * \struct imu_raw_s + * + */ +struct imu_raw_s { + double x; + double y; + double z; +}; + +/** + * \struct imu_gyro_s_t + * + */ +typedef struct imu_raw_s imu_gyro_s_t; + +/** + * \struct imu_accel_s_t + * + */ +typedef struct imu_raw_s imu_accel_s_t; + +/** + * \struct euler_s_t + * + */ +typedef struct __attribute__((__packed__)) euler_s { + double pitch; + double roll; + double yaw; +} euler_s_t; + +#ifdef __cplusplus +namespace c { +#endif +/** + * \def IMU_MINIMUM_DATA_RATE + */ +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define IMU_STATUS_CALIBRATING pros::E_IMU_STATUS_CALIBRATING +#define IMU_STATUS_ERROR pros::E_IMU_STATUS_ERROR +#else +#define IMU_STATUS_CALIBRATING E_IMU_STATUS_CALIBRATING +#define IMU_STATUS_ERROR E_IMU_STATUS_ERROR +#endif +#endif + +#define IMU_MINIMUM_DATA_RATE 5 + +/** + * Calibrate IMU + * + * Calibration takes approximately 2 seconds, but this function only blocks + * until the IMU status flag is set properly to E_IMU_STATUS_CALIBRATING, + * with a minimum blocking time of 5ms. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void initialize() { + * imu_reset(IMU_PORT); + * int time = millis(); + * int iter = 0; + * while (imu_get_status(IMU_PORT) & E_IMU_STATUS_CALIBRATING) { + * printf("IMU calibrating... %d\n", iter); + * iter += 10; + * delay(10); + * } + * // should print about 2000 ms + * printf("IMU is done calibrating (took %d ms)\n", iter - time); + * } + * \endcode + */ +int32_t imu_reset(uint8_t port); + +/** + * Calibrate IMU and Blocks while Calibrating + * + * Calibration takes approximately 2 seconds and blocks during this period, + * with a timeout for this operation being set a 3 seconds as a safety margin. + * Like the other reset function, this function also blocks until the IMU + * status flag is set properly to E_IMU_STATUS_CALIBRATING, with a minimum + * blocking time of 5ms and a timeout of 1 second if it's never set. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed (timing out or port claim failure), setting errno. + */ +int32_t imu_reset_blocking(uint8_t port); +/** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * \endcode + */ +int32_t imu_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("IMU get rotation: %f degrees\n", imu_get_rotation(IMU_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double imu_get_rotation(uint8_t port); + +/** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by [0,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("IMU get heading: %f degrees\n", imu_get_heading(IMU_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double imu_get_heading(uint8_t port); + +/** + * Get a quaternion representing the Inertial Sensor's orientation + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The quaternion representing the sensor's orientation. If the + * operation failed, all the quaternion's members are filled with PROS_ERR_F and + * errno is set. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * quaternion_s_t qt = imu_get_quaternion(IMU_PORT); + * printf("IMU quaternion: {x: %f, y: %f, z: %f, w: %f}\n", qt.x, qt.y, qt.z, qt.w); + * delay(20); + * } + * } + * \endcode + */ +quaternion_s_t imu_get_quaternion(uint8_t port); + +/** + * Get the Euler angles representing the Inertial Sensor's orientation + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The Euler angles representing the sensor's orientation. If the + * operation failed, all the structure's members are filled with PROS_ERR_F and + * errno is set. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * euler_s_t eu = imu_get_euler(IMU_PORT); + * printf("IMU euler angles: {pitch: %f, roll: %f, yaw: %f}\n", eu.pitch, eu.roll, eu.yaw); + * delay(20); + * } + * } + * \endcode + */ +euler_s_t imu_get_euler(uint8_t port); + +/** + * Get the Inertial Sensor's raw gyroscope values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("IMU pitch: %f\n", imu_get_pitch(IMU_PORT)); + * delay(20); + * } + * } + * \endcode + */ +imu_gyro_s_t imu_get_gyro_rate(uint8_t port); + +/** + * Get the Inertial Sensor's raw acceleroneter values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The roll angle, or PROS_ERR_F if the operation failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("IMU roll: %f\n", imu_get_roll(IMU_PORT)); + * delay(20); + * } + * } + * \endcode + */ +imu_accel_s_t imu_get_accel(uint8_t port); + +/** + * Get the Inertial Sensor's status + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The yaw angle, or PROS_ERR_F if the operation failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("IMU yaw: %f\n", imu_get_yaw(IMU_PORT)); + * delay(20); + * } + * } + * \endcode + */ +imu_status_e_t imu_get_status(uint8_t port); + +// Value set functions: +/** + * Sets the current reading of the Inertial Sensor's euler values to + * target euler values. Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * int32_t val = imu_set_euler(IMU_PORT, {45, 60, 90}); + * printf("IMU : {gyro vals: %d}\n", val); + * delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_euler(uint8_t port, euler_s_t target); + +/** + * Get the Inertial Sensor's pitch angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * imu_accel_s_t accel = imu_get_accel(IMU_PORT); + * printf("IMU accel values: {x: %f, y: %f, z: %f}\n", accel.x, accel.y, accel.z); + * delay(20); + * } + * } + * \endcode + */ +double imu_get_pitch(uint8_t port); + +/** + * Get the Inertial Sensor's roll angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The Inertial Sensor's status code, or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void initialize() { + * imu_reset(IMU_PORT); + * int time = millis(); + * int iter = 0; + * while (imu_get_status(IMU_PORT) & E_IMU_STATUS_CALIBRATING) { + * printf("IMU calibrating... %d\n", iter); + * iter += 10; + * delay(10); + * } + * // should print about 2000 ms + * printf("IMU is done calibrating (took %d ms)\n", iter - time); + * } + * \endcode + */ +double imu_get_roll(uint8_t port); + +/** + * Get the Inertial Sensor's yaw angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The yaw angle, or PROS_ERR_F if the operation failed, setting errno. + */ +double imu_get_yaw(uint8_t port); + +// NOTE: not used +// void imu_set_mode(uint8_t port, uint32_t mode); +// uint32_t imu_get_mode(uint8_t port); + +/** + * \name Value Reset Functions + * @{ + */ + +/** + * Resets the current reading of the Inertial Sensor's heading to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_heading(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_heading(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's rotation to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_rotation(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_rotation(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's pitch to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_pitch(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_pitch(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's roll to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_roll(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_roll(uint8_t port); + +/** + * Resets the current reading of the Inertial Sensor's yaw to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_yaw(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_yaw(uint8_t port); + +/** + * Reset all 3 euler values of the Inertial Sensor to 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare_euler(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare_euler(uint8_t port); + +/** + * Resets all 5 values of the Inertial Sensor to 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_tare(IMU_PORT); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_tare(uint8_t port); + +/** @} */ + +/** + * \name Value Set Functions + * @{ + */ + +/** + * Sets the current reading of the Inertial Sensor's euler values to + * target euler values. Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target euler values for the euler values to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_euler(IMU_PORT, {45,45,45}); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_euler(uint8_t port, euler_s_t target); + +/** + * Sets the current reading of the Inertial Sensor's rotation to target value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the rotation value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_rotation(IMU_PORT, 45); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_rotation(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's heading to target value + * Target will default to 360 if above 360 and default to 0 if below 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the heading value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_heading(IMU_PORT, 45); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_heading(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's pitch to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the pitch value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_pitch(IMU_PORT, 45); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_pitch(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's roll to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the roll value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_roll(IMU_PORT, 45); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_roll(uint8_t port, double target); + +/** + * Sets the current reading of the Inertial Sensor's yaw to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the yaw value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define IMU_PORT 1void opcontrol() { + * + * while (true) { + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * imu_set_yaw(IMU_PORT, 45); + * } + * pros::delay(20); + * } + * } + * \endcode + */ +int32_t imu_set_yaw(uint8_t port, double target); + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/include/pros/imu.hpp b/include/pros/imu.hpp new file mode 100644 index 0000000..cb141ec --- /dev/null +++ b/include/pros/imu.hpp @@ -0,0 +1,1008 @@ +/** + * \file pros/imu.hpp + * \ingroup cpp-imu + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-imu VEX Inertial Sensor C++ API + */ +#ifndef _PROS_IMU_HPP_ +#define _PROS_IMU_HPP_ + +#include + +#include "pros/imu.h" +#include "pros/device.hpp" +#include + +namespace pros { +/** + * \ingroup cpp-imu + * */ + +/** + * \addtogroup cpp-imu + * @{ + */ + +/** + * \enum Imu_Status + * @brief Indicates IMU status. + */ + +enum class ImuStatus { + /** The IMU is calibrating */ + calibrating = 0x01, + /** Used to indicate that an error state was reached in the imu_get_status function,\ + not that the IMU is necessarily in an error state */ + error = 0xFF, +}; + +inline namespace v5 { +/** + * \ingroup cpp-imu + */ +class Imu : public Device { + /** + * \addtogroup cpp-imu + * ///@{ + */ + + + public: + /** + * Creates an Imu object for the given port + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * + * \b Example + * \code + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Do something with the sensor data + * } + * } + * \endcode + */ + explicit Imu(const std::uint8_t port) : Device(port, DeviceType::imu) {}; + + /** + * Calibrate IMU + * + * Calibration takes approximately 2 seconds and blocks during this period if + * the blocking param is true, with a timeout for this operation being set a 3 + * seconds as a safety margin. This function also blocks until the IMU + * status flag is set properly to E_IMU_STATUS_CALIBRATING, with a minimum + * blocking time of 5ms and a timeout of 1 second if it's never set. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is already calibrating, or time out setting the status flag. + * + * \param blocking + * Whether this function blocks during calibration. + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * imu.calibrate(); + * // Block until calibration is complete + * imu.reset(true); + * } + * \endcode + */ + virtual std::int32_t reset(bool blocking = false) const; + /** + * Set the Inertial Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the refresh rate to 5ms + * std::int32_t status = imu.set_data_rate(5); + * delay(20); + * + * // Check if the operation was successful + * if (status == PROS_ERR) { + * // Do something with the error + * } + * + * // Do something with the sensor data + * } + * } + * \endcode + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + /** + * Get the total number of degrees the Inertial Sensor has spun about the z-axis + * + * This value is theoretically unbounded. Clockwise rotations are represented + * with positive degree values, while counterclockwise rotations are represented + * with negative ones. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the total number of degrees the sensor has spun + * printf("Total rotation: %f\n", imu.get_rotation()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_rotation() const; + /** + * Get the Inertial Sensor's heading relative to the initial direction of its + * x-axis + * + * This value is bounded by [0,360). Clockwise rotations are represented with + * positive degree values, while counterclockwise rotations are represented with + * negative ones. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The degree value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's heading + * printf("Heading: %f\n", imu.get_heading()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_heading() const; + /** + * Get a quaternion representing the Inertial Sensor's orientation + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The quaternion representing the sensor's orientation. If the + * operation failed, all the quaternion's members are filled with PROS_ERR_F and + * errno is set. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's quaternion + * pros::quaternion_s_t quat = imu.get_quaternion(); + * cout << "Quaternion: " << quat.w << ", " << quat.x << ", " << quat.y << ", " << quat.z << endl; + * delay(20); + * } + * } + * \endcode + */ + virtual pros::quaternion_s_t get_quaternion() const; + /** + * Get the Euler angles representing the Inertial Sensor's orientation + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The Euler angles representing the sensor's orientation. If the + * operation failed, all the structure's members are filled with PROS_ERR_F and + * errno is set. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's Euler angles + * pros::euler_s_t euler = imu.get_euler(); + * cout << "Euler: " << euler.roll << ", " << euler.pitch << ", " << euler.yaw << endl; + * delay(20); + * } + * } + * \endcode + */ + virtual pros::euler_s_t get_euler() const; + /** + * Get the Inertial Sensor's pitch angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The pitch angle, or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's pitch + * printf("Pitch: %f\n", imu.get_pitch()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_pitch() const; + /** + * Get the Inertial Sensor's roll angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The roll angle, or PROS_ERR_F if the operation failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's roll + * printf("Roll: %f\n", imu.get_roll()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_roll() const; + /** + * Get the Inertial Sensor's yaw angle bounded by (-180,180) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The yaw angle, or PROS_ERR_F if the operation failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's yaw + * printf("Yaw: %f\n", imu.get_yaw()); + * delay(20); + * } + * } + * \endcode + */ + virtual double get_yaw() const; + /** + * Get the Inertial Sensor's raw gyroscope values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The raw gyroscope values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's raw gyroscope values + * pros::imu_gyro_s_t gyro = imu.get_gyro_rate(); + * cout << "Gyro: " << gyro.x << ", " << gyro.y << ", " << gyro.z << endl; + * delay(20); + * } + * } + * \endcode + */ + virtual pros::imu_gyro_s_t get_gyro_rate() const; + /** + * Resets the current reading of the Inertial Sensor's rotation to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's rotation value to 10 + * imu.set_rotation(10); + * delay(20); + * + * // Do something with sensor + * + * // Reset the sensor's rotation value to 0 + * imu.tare_rotation(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_rotation() const; + /** + * Resets the current reading of the Inertial Sensor's heading to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's heading value to 10 + * imu.set_heading(10); + * delay(20); + * + * // Do something with sensor + * + * // Reset the sensor's heading value to 0 + * imu.tare_heading(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_heading() const; + /** + * Resets the current reading of the Inertial Sensor's pitch to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's pitch value to 10 + * imu.set_pitch(10); + * delay(20); + * + * // Do something with sensor + * + * // Reset the sensor's pitch value to 0 + * imu.tare_pitch(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_pitch() const; + /** + * Resets the current reading of the Inertial Sensor's yaw to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's yaw value to 10 + * imu.set_yaw(10); + * delay(20); + * + * // Do something with sensor + * + * // Reset the sensor's yaw value to 0 + * imu.tare_yaw(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_yaw() const; + /** + * Resets the current reading of the Inertial Sensor's roll to zero + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's roll value to 10 + * imu.set_roll(10); + * delay(20); + * + * // Do something with sensor + * + * // Reset the sensor's roll value to 0 + * imu.tare_roll(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_roll() const; + /** + * Resets all 5 values of the Inertial Sensor to 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Reset all values of the sensor to 0 + * imu.tare(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare() const; + /** + * Reset all 3 euler values of the Inertial Sensor to 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Reset all euler values of the sensor to 0 + * imu.tare_euler(); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t tare_euler() const; + /** + * Sets the current reading of the Inertial Sensor's heading to target value + * Target will default to 360 if above 360 and default to 0 if below 0. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the heading value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's heading value to 10 + * imu.set_heading(10); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_heading(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's rotation to target value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the rotation value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's rotation value to 10 + * imu.set_rotation(10); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_rotation(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's yaw to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for yaw value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's yaw value to 10 + * imu.set_yaw(10); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_yaw(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's pitch to target value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target value for the pitch value to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's pitch value to 10 + * imu.set_pitch(10); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_pitch(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's roll to target value + * Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target euler values for the euler values to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's roll value to 100 + * imu.set_roll(100); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_roll(const double target) const; + /** + * Sets the current reading of the Inertial Sensor's euler values to + * target euler values. Will default to +/- 180 if target exceeds +/- 180. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \param target + * Target euler values for the euler values to be set to + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Set the sensor's euler values to 50 + * imu.set_euler(50); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual std::int32_t set_euler(const pros::euler_s_t target) const; + /** + * Get the Inertial Sensor's raw accelerometer values + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's raw accelerometer values + * pros::imu_accel_s_t accel = imu.get_accel(); + * printf("x: %f, y: %f, z: %f\n", accel.x, accel.y, accel.z); + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual pros::imu_accel_s_t get_accel() const; + /** + * Get the Inertial Sensor's status + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Inertial Sensor + * EAGAIN - The sensor is still calibrating + * + * \param port + * The V5 Inertial Sensor port number from 1-21 + * \return The Inertial Sensor's status code, or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Get the sensor's status + * pros::ImuStatus status = imu.get_status(); + * cout << "Status: " << status << endl; + * delay(20); + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual pros::ImuStatus get_status() const; + /** + * Check whether the IMU is calibrating + * + * \return true if the V5 Inertial Sensor is calibrating or false + * false if it is not. + * + * \b Example + * \code + * + * #define IMU_PORT 1 + * + * void opcontrol() { + * pros::Imu imu(IMU_PORT); + * + * while (true) { + * // Calibrate the sensor + * imu.calibrate(); + * delay(20); + * + * // Check if the sensor is calibrating + * if (imu.is_calibrating()) { + * printf("Calibrating...\n"); + * } + * + * // Do something with sensor + * } + * } + * \endcode + */ + virtual bool is_calibrating() const; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * Imu [port: imu._port, rotation: (rotation), heading: (heading), + * pitch: (pitch angle), roll: (roll angle), yaw: (yaw angle), + * gyro rate: {x,y,z}, get accel: {x,y,z}, calibrating: (calibrating boolean)] + */ + friend std::ostream& operator<<(std::ostream& os, const pros::Imu& imu); + + ///@} +}; + +namespace literals { +const pros::Imu operator"" _imu(const unsigned long long int i); +} // namespace literals + +using IMU = Imu; +} // namespace v5 +} // namespace pros + +#endif diff --git a/include/pros/link.h b/include/pros/link.h new file mode 100644 index 0000000..bd02a17 --- /dev/null +++ b/include/pros/link.h @@ -0,0 +1,421 @@ +/** + * \file pros/link.h + * \ingroup c-link + * + * Contains prototypes for functions related to the robot to robot communications. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-link VEX Link C API + */ + +#ifndef _PROS_LINK_H_ +#define _PROS_LINK_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \ingroup c-link + * */ + +/** + * \addtogroup c-link + * @{ + */ + +/** + * \enum link_type_e_t + * \brief Enum for the type of link (TX or RX) + */ +typedef enum link_type_e { + E_LINK_RECEIVER = 0, ///< Indicates that the radio is a receiver. + E_LINK_TRANSMITTER, ///< Indicates that the link is a transmitter. + E_LINK_RX = E_LINK_RECEIVER, ///< Alias for E_LINK_RECEIVER + E_LINK_TX = E_LINK_TRANSMITTER ///< Alias for E_LINK_TRANSMITTER +} link_type_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define LINK_RECEIVER pros::E_LINK_RECEIVER +#define LINK_TRANSMITTER pros::E_LINK_TRANSMITTER +#define LINK_RX pros::E_LINK_RX +#define LINK_TX pros::E_LINK_TX +#else +#define LINK_RECEIVER E_LINK_RECEIVER +#define LINK_TRANSMITTER E_LINK_TRANSMITTER +#define LINK_RX E_LINK_RX +#define LINK_TX E_LINK_TX +#endif +#endif + +/// @brief +/// The maximum size of a link buffer +#define LINK_BUFFER_SIZE 512 + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Initializes a link on a radio port, with an indicated type. There might be a + * 1 to 2 second delay from when this function is called to when the link is initializes. + * PROS currently only supports the use of one radio per brain. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or receiver, + * with the transmitter having double the transmitting bandwidth as the receiving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * #define LINK_ID "ROBOT1" + * + * void initialize() { + * link_init(LINK_TRANSMITTER_PORT, LINK_ID, E_LINK_TRANSMITTER); + * } + * \endcode + */ +uint32_t link_init(uint8_t port, const char* link_id, link_type_e_t type); + +/** + * Initializes a link on a radio port, with an indicated type and the ability for + * vexlink to override the controller radio. There might be a 1 to 2 second delay + * from when this function is called to when the link is initializes. + * PROS currently only supports the use of one radio per brain. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or receiver, + * with the transmitter having double the transmitting bandwidth as the receiving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + * + * \b Example + * \code + * #define LINK_PORT 1 + * #define LINK_ID "ROBOT1" + * + * void initialize() { + * link_init(LINK_PORT, LINK_ID, E_LINK_TRANSMITTER); + * link_init_override(LINK_PORT, LINK_ID, E_LINK_TRANSMITTER); + * } + * \endcode + */ +uint32_t link_init_override(uint8_t port, const char* link_id, link_type_e_t type); + +/** + * Checks if a radio link on a port is active or not. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return If a radio is connected to a port and it's connected to a link. + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * + * void opcontrol() { + * while (true) { + * if (link_connected(LINK_TRANSMITTER_PORT)) { + * screen_print(TEXT_MEDIUM, 1, "Link connected!"); + * } + * delay(20); + * } + * } + * \endcode + */ +bool link_connected(uint8_t port); + +/** + * Returns the bytes of data available to be read + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link/radio, else the bytes available to be + * read by the user. + * + * \b Example + * \code + * #define LINK_RECIVER_PORT 1 + * + * void opcontrol() { + * while (true) { + * uint32_t receiveable_size = link_raw_receivable_size(LINK_RECIVER_PORT); + * screen_print(TEXT_MEDIUM, 1, "link_raw_receiveable_size: %d", receiveable_size); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_raw_receivable_size(uint8_t port); + +/** + * Returns the bytes of data available in transmission buffer. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link/radio, + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * + * void opcontrol() { + * while (true) { + * uint32_t transmittable_size = link_raw_transmittable_size(LINK_TRANSMITTER_PORT); + * screen_print(TEXT_MEDIUM, 1, "link_raw_transmittable_size: %d", transmittable_size); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_raw_transmittable_size(uint8_t port); + +/** + * Send raw serial data through vexlink. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param port + * The port of the radio for the intended link. + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * + * void opcontrol() { + * while (true) { + * char* data = "Hello!"; + * link_transmit_raw(LINK_TRANSMITTER_PORT, (void*)data, sizeof(*data) * sizeof(data)); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_transmit_raw(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive raw serial data through vexlink. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * + * \param port + * The port of the radio for the intended link. + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + * + * \b Example + * \code + * #define LINK_RECIVER_PORT 1 + * + * void opcontrol() { + * while (true) { + * char* result; + * char* expected = "Hello!"; + * link_receive_raw(LINK_RECIVER_PORT, (void*)result, sizeof(*expected) * sizeof(expected)); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_receive_raw(uint8_t port, void* dest, uint16_t data_size); + +/** + * Send packeted message through vexlink, with a checksum and start byte. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param port + * The port of the radio for the intended link. + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * + * void opcontrol() { + * while (true) { + * char* data = "Hello!"; + * link_transmit(LINK_TRANSMITTER_PORT, (void*)data, sizeof(*data) * sizeof(data)); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_transmit(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * EBADMSG - Protocol error related to start byte, data size, or checksum. + * + * \param port + * The port of the radio for the intended link. + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link or protocol error, and the successfully + * transmitted data size if it succeeded. + * + * \b Example + * \code + * #define LINK_RECIVER_PORT 1 + * + * void opcontrol() { + * while (true) { + * char* result; + * char* expected = "Hello!"; + * link_receive(LINK_RECIVER_PORT, (void*)result, sizeof(*expected) * sizeof(expected)); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_receive(uint8_t port, void* dest, uint16_t data_size); + +/** + * Clear the receive buffer of the link, and discarding the data. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + * + * \b Example + * \code + * #define LINK_TRANSMITTER_PORT 1 + * + * void opcontrol() { + * while (true) { + * char* data = "Hello!"; + * link_transmit(LINK_TRANSMITTER_PORT, (void*)data, sizeof(*data) * sizeof(data)); + * link_clear_receive_buf(LINK_TRANSMITTER_PORT); + * delay(20); + * } + * } + * \endcode + */ +uint32_t link_clear_receive_buf(uint8_t port); + +///@} + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/include/pros/link.hpp b/include/pros/link.hpp new file mode 100644 index 0000000..45d98df --- /dev/null +++ b/include/pros/link.hpp @@ -0,0 +1,283 @@ +/** + * \file pros/link.hpp + * \ingroup cpp-link + * + * Contains prototypes for functions related to robot to robot communications. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * Copyright (c) 2017-2021, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-link VEX Link C++ API + */ +#ifndef _PROS_LINK_HPP_ +#define _PROS_LINK_HPP_ + +#include +#include + +#include "pros/link.h" +#include "pros/device.hpp" + +namespace pros { +/** + * \ingroup cpp-link + */ +class Link : public Device { + /** + * \addtogroup cpp-link + * ///@{ + */ + private: + + public: + /** + * Initializes a link on a radio port, with an indicated type. There might be a + * 1 to 2 second delay from when this function is called to when the link is initializes. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \param port + * The port of the radio for the intended link. + * \param link_id + * Unique link ID in the form of a string, needs to be different from other links in + * the area. + * \param type + * Indicates whether the radio link on the brain is a transmitter or receiver, + * with the transmitter having double the transmitting bandwidth as the receiving + * end (1040 bytes/s vs 520 bytes/s). + * \param ov + * Indicates if the radio on the given port needs vexlink to override the controller radio + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + * + * \b Example: + * \code + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * \endcode + */ + explicit Link(const std::uint8_t port, const std::string link_id, link_type_e_t type, bool ov = false); + + /** + * Checks if a radio link on a port is active or not. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return If a radio is connected to a port and it's connected to a link. + * + * \b Example: + * \code + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * if (link.connected()) { + * // do something + * } + * \endcode + */ + bool connected(); + + /** + * Returns the bytes of data number of without protocol available to be read + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return PROS_ERR if port is not a link/radio, else the bytes available to be + * read by the user. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * printf("Bytes available to read: %d", link.receivable_size()); + * } + * \endcode + */ + std::uint32_t raw_receivable_size(); + + /** + * Returns the bytes of data available in transmission buffer. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return PROS_ERR if port is not a link/radio, + * else the bytes available to be transmitted by the user. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * printf("Bytes available to transmit: %d", link.transmittable_size()); + * } + */ + std::uint32_t raw_transmittable_size(); + + /** + * Send raw serial data through vexlink. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param data + * Buffer with data to send + * \param data_size + * Buffer with data to send + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * std::uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; + * link.transmit_raw(data, 4); + * } + * + * \endcode + */ + std::uint32_t transmit_raw(void* data, std::uint16_t data_size); + + /** + * Receive raw serial data through vexlink. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * std::uint8_t data[4]; + * link.receive_raw(data, 4); + * } + * \endcode + */ + std::uint32_t receive_raw(void* dest, std::uint16_t data_size); + + /** + * Send packeted message through vexlink, with a checksum and start byte. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EBUSY - The transmitter buffer is still busy with a previous transmission, and there is no + * room in the FIFO buffer (queue) to transmit the data. + * EINVAL - The data given is NULL + * + * \param data + * Buffer with data to send + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully transmitted + * data size if it succeeded. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * std::uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; + * link.transmit(data, 4); + * } + * \endcode + */ + std::uint32_t transmit(void* data, std::uint16_t data_size); + + /** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * EINVAL - The destination given is NULL, or the size given is larger than the FIFO buffer + * or destination buffer. + * EBADMSG - Protocol error related to start byte, data size, or checksum. + + * \param dest + * Destination buffer to read data to + * \param data_size + * Bytes of data to be read to the destination buffer + * + * \return PROS_ERR if port is not a link, and the successfully received + * data size if it succeeded. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * std::uint8_t data[4]; + * link.receive(data, 4); + * } + * \endcode + */ + std::uint32_t receive(void* dest, std::uint16_t data_size); + + /** + * Clear the receive buffer of the link, and discarding the data. + * + * \note This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a radio. + * ENXIO - The sensor is still calibrating, or no link is connected via the radio. + * + * \return PROS_ERR if port is not a link, 1 if the operation succeeded. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Link link(1, "my_link", pros::E_LINK_TX); + * link.clear_receive_buf(); + * } + * \endcode + */ + std::uint32_t clear_receive_buf(); + + ///@} +}; +} // namespace pros + +#endif diff --git a/include/pros/llemu.h b/include/pros/llemu.h new file mode 100644 index 0000000..868cd73 --- /dev/null +++ b/include/pros/llemu.h @@ -0,0 +1,54 @@ +#ifndef _PROS_LLEMU_H_ +#define _PROS_LLEMU_H_ + +// TODO:? Should there be weak symbols for the C api in here as well? + +#include "stdint.h" + +/******************************************************************************/ +/** LLEMU Conditional Include **/ +/** **/ +/** When the libvgl versions of llemu.h is present, common.mk will **/ +/** define a macro which lets this file know that liblvgl's llemu.h is **/ +/** present. If it is, we conditionally include it so that it gets **/ +/** included into api.h. **/ +/******************************************************************************/ +#ifdef _PROS_INCLUDE_LIBLVGL_LLEMU_H +#include "liblvgl/llemu.h" +#endif + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif//__cplusplus + +/** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ... + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + */ +bool __attribute__((weak)) lcd_print(int16_t line, const char* fmt, ...) { + return false; +} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} // extern "C" +#endif//__cplusplus + +#endif // _PROS_LLEMU_H_ diff --git a/include/pros/llemu.hpp b/include/pros/llemu.hpp new file mode 100644 index 0000000..4f75d6c --- /dev/null +++ b/include/pros/llemu.hpp @@ -0,0 +1,138 @@ +/** + * \file pros/llemu.hpp + * \ingroup cpp-llemu + * + * Legacy LCD Emulator + * + * \details This file defines a high-level API for emulating the three-button, UART-based + * VEX LCD, containing a set of functions that facilitate the use of a software- + * emulated version of the classic VEX LCD module. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef _PROS_LLEMU_HPP_ +#define _PROS_LLEMU_HPP_ + +#include +#include + +/******************************************************************************/ +/** LLEMU Conditional Include **/ +/** **/ +/** When the libvgl versions of llemu.hpp is present, common.mk will **/ +/** define a macro which lets this file know that liblvgl's llemu.hpp is **/ +/** present. If it is, we conditionally include it so that it gets **/ +/** included into api.h. **/ +/******************************************************************************/ +#ifdef _PROS_INCLUDE_LIBLVGL_LLEMU_HPP +#include "liblvgl/llemu.hpp" +#endif + +/******************************************************************************/ +/** LLEMU Weak Stubs **/ +/** **/ +/** These functions allow main.cpp to be compiled without LVGL present **/ +/******************************************************************************/ + +namespace pros { + +/** + * \ingroup cpp-llemu + */ +namespace lcd { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-function" + namespace { + template + T convert_args(T arg) { + return arg; + } + const char* convert_args(const std::string& arg) { + return arg.c_str(); + } + } // namespace + #pragma GCC diagnostic pop + + using lcd_btn_cb_fn_t = void (*)(void); + + /* + * These weak symbols allow the example main.cpp in to compile even when + * the liblvgl template is missing from the project. + * + * For documentation on these functions, please see the doxygen comments for + * these functions in the libvgl llemu headers. + */ + + extern __attribute__((weak)) bool set_text(std::int16_t line, std::string text); + extern __attribute__((weak)) bool clear_line(std::int16_t line); + extern __attribute__((weak)) bool initialize(void); + extern __attribute__((weak)) std::uint8_t read_buttons(void); + extern __attribute__((weak)) void register_btn1_cb(lcd_btn_cb_fn_t cb); + extern __attribute__((weak)) bool is_initialized(void); + + /** + * \addtogroup cpp-llemu + * @{ + */ + + /* + * Note: This template resides in this file since the + */ + + /** + * Displays a formatted string on the emulated three-button LCD screen. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The LCD has not been initialized. Call lcd_initialize() first. + * EINVAL - The line number specified is not in the range [0-7] + * + * \param line + * The line on which to display the text [0-7] + * \param fmt + * Format string + * \param ...args + * Optional list of arguments for the format string + * + * \return True if the operation was successful, or false otherwise, setting + * errno values as specified above. + * + * \b Example + * \code + * #include "pros/llemu.hpp" + * + * void initialize() { + * pros::lcd::initialize(); + * pros::lcd::print(0, "My formatted text: %d!", 2); + * } + * \endcode + */ + template + bool print(std::int16_t line, const char* fmt, Params... args) { + return pros::c::lcd_print(line, fmt, convert_args(args)...); + } + + #ifndef LCD_BTN_LEFT + #define LCD_BTN_LEFT 4 + #endif + + #ifndef LCD_BTN_CENTER + #define LCD_BTN_CENTER 2 + #endif + + #ifndef LCD_BTN_RIGHT + #define LCD_BTN_RIGHT 1 + #endif + /// @} +} // namespace lcd +} // namespace pros + +#endif // _PROS_LLEMU_HPP_ diff --git a/include/pros/misc.h b/include/pros/misc.h new file mode 100644 index 0000000..d0ad676 --- /dev/null +++ b/include/pros/misc.h @@ -0,0 +1,756 @@ +/** + * \file pros/misc.h + * \ingroup c-misc + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reservered. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-misc Miscellaneous C API + * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) + */ + +#ifndef _PROS_MISC_H_ +#define _PROS_MISC_H_ + +#include + +#define NUM_V5_PORTS (22) + +/** + * \ingroup c-misc + */ + +/** + * \addtogroup c-misc + * @{ + */ + +/// \name V5 Competition +//@{ + +#define COMPETITION_DISABLED (1 << 0) +#define COMPETITION_AUTONOMOUS (1 << 1) +#define COMPETITION_CONNECTED (1 << 2) + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \fn competition_get_status(void) + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + * + * \b Example + * \code + * void initialize() { + * if (competition_get_status() & COMPETITION_CONNECTED == true) { + * // Field Control is Connected + * // Run LCD Selector code or similar + * } + * } + * \endcode + */ +uint8_t competition_get_status(void); + +#ifdef __cplusplus +} +} +} +#endif + +/** + * \fn competition_is_disabled() + * + * \return True if the V5 Brain is disabled, false otherwise. + * + * \b Example + * \code + * void my_task_fn(void* ignore) { + * while (!competition_is_disabled()) { + * // Run competition tasks (like Lift Control or similar) + * } + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * \endcode + */ +#define competition_is_disabled() ((competition_get_status() & COMPETITION_DISABLED) != 0) + +/** + * \return True if the V5 Brain is connected to competition control, false otherwise. + * + * \b Example + * \code + * void initialize() { + * if (competition_is_connected()) { + * // Field Control is Connected + * // Run LCD Selector code or similar + * } + * } + * \endcode + */ +#define competition_is_connected() ((competition_get_status() & COMPETITION_CONNECTED) != 0) + +/** + * \return True if the V5 Brain is in autonomous mode, false otherwise. + * + * \b Example + * \code + * void my_task_fn(void* ignore) { + * while (!competition_is_autonomous()) { + * // Wait to do anything until autonomous starts + * delay(2); + * } + * while (competition_is_autonomous()) { + * // Run whatever code is desired to just execute in autonomous + * } + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIO_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * \endcode + */ +#define competition_is_autonomous() ((competition_get_status() & COMPETITION_AUTONOMOUS) != 0) + +///@} + +/// \name V5 Controller +///@{ +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \enum + */ +typedef enum { + ///The master controller. + E_CONTROLLER_MASTER = 0, + ///The partner controller. + E_CONTROLLER_PARTNER } controller_id_e_t; + +/** + * \enum + */ +typedef enum { + ///The horizontal axis of the controller’s left analog stick. + E_CONTROLLER_ANALOG_LEFT_X = 0, + ///The vertical axis of the controller’s left analog stick. + E_CONTROLLER_ANALOG_LEFT_Y, + ///The horizontal axis of the controller’s right analog stick. + E_CONTROLLER_ANALOG_RIGHT_X, + ///The vertical axis of the controller’s right analog stick. + E_CONTROLLER_ANALOG_RIGHT_Y +} controller_analog_e_t; + +/** + * \enum + */ +typedef enum { + ///The first trigger on the left side of the controller. + E_CONTROLLER_DIGITAL_L1 = 6, + ///The second trigger on the left side of the controller. + E_CONTROLLER_DIGITAL_L2, + ///The first trigger on the right side of the controller. + E_CONTROLLER_DIGITAL_R1, + ///The second trigger on the right side of the controller. + E_CONTROLLER_DIGITAL_R2, + ///The up arrow on the left arrow pad of the controller. + E_CONTROLLER_DIGITAL_UP, + ///The down arrow on the left arrow pad of the controller. + E_CONTROLLER_DIGITAL_DOWN, + ///The left arrow on the left arrow pad of the controller. + E_CONTROLLER_DIGITAL_LEFT, + ///The right arrow on the left arrow pad of the controller. + E_CONTROLLER_DIGITAL_RIGHT, + ///The ‘X’ button on the right button pad of the controller. + E_CONTROLLER_DIGITAL_X, + ///The ‘B’ button on the right button pad of the controller. + E_CONTROLLER_DIGITAL_B, + ///The ‘Y’ button on the right button pad of the controller. + E_CONTROLLER_DIGITAL_Y, + ///The ‘A’ button on the right button pad of the controller. + E_CONTROLLER_DIGITAL_A +} controller_digital_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define CONTROLLER_MASTER pros::E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER pros::E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X pros::E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y pros::E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X pros::E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y pros::E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 pros::E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 pros::E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 pros::E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 pros::E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP pros::E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN pros::E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT pros::E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT pros::E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X pros::E_CONTROLLER_DIGITAL_X +#define DIGITAL_B pros::E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y pros::E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A pros::E_CONTROLLER_DIGITAL_A +#else +#define CONTROLLER_MASTER E_CONTROLLER_MASTER +#define CONTROLLER_PARTNER E_CONTROLLER_PARTNER +#define ANALOG_LEFT_X E_CONTROLLER_ANALOG_LEFT_X +#define ANALOG_LEFT_Y E_CONTROLLER_ANALOG_LEFT_Y +#define ANALOG_RIGHT_X E_CONTROLLER_ANALOG_RIGHT_X +#define ANALOG_RIGHT_Y E_CONTROLLER_ANALOG_RIGHT_Y +#define DIGITAL_L1 E_CONTROLLER_DIGITAL_L1 +#define DIGITAL_L2 E_CONTROLLER_DIGITAL_L2 +#define DIGITAL_R1 E_CONTROLLER_DIGITAL_R1 +#define DIGITAL_R2 E_CONTROLLER_DIGITAL_R2 +#define DIGITAL_UP E_CONTROLLER_DIGITAL_UP +#define DIGITAL_DOWN E_CONTROLLER_DIGITAL_DOWN +#define DIGITAL_LEFT E_CONTROLLER_DIGITAL_LEFT +#define DIGITAL_RIGHT E_CONTROLLER_DIGITAL_RIGHT +#define DIGITAL_X E_CONTROLLER_DIGITAL_X +#define DIGITAL_B E_CONTROLLER_DIGITAL_B +#define DIGITAL_Y E_CONTROLLER_DIGITAL_Y +#define DIGITAL_A E_CONTROLLER_DIGITAL_A +#endif +#endif + +/** + * \def Given an id and a port, this macro sets the port variable based on the id and allows the mutex to take that port. + * + * \returns error (in the function/scope it's in) if the controller failed to connect or an invalid id is given. +*/ +#define CONTROLLER_PORT_MUTEX_TAKE(id, port) \ + switch (id) { \ + case E_CONTROLLER_MASTER: \ + port = V5_PORT_CONTROLLER_1; \ + break; \ + case E_CONTROLLER_PARTNER: \ + port = V5_PORT_CONTROLLER_2; \ + break; \ + default: \ + errno = EINVAL; \ + return PROS_ERR; \ + } \ + if (!internal_port_mutex_take(port)) { \ + errno = EACCES; \ + return PROS_ERR; \ + } \ + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks if the controller is connected. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the controller is connected, 0 otherwise + * + * \b Example + * \code + * void initialize() { + * if (competition_is_connected()) { + * // Field Control is Connected + * // Run LCD Selector code or similar + * } + * } + * \endcode + */ +int32_t controller_is_connected(controller_id_e_t id); + +/** + * Gets the value of an analog channel (joystick) on a controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_get_analog(controller_id_e_t id, controller_analog_e_t channel); + +/** + * Gets the battery capacity of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery capacity + * + * \b Example + * \code + * void initialize() { + * printf("Battery Capacity: %d\n", controller_get_battery_capacity(E_CONTROLLER_MASTER)); + * } + * \endcode + */ +int32_t controller_get_battery_capacity(controller_id_e_t id); + +/** + * Gets the battery level of the given controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER + * + * \return The controller's battery level + * + * \b Example + * \code + * void initialize() { + * printf("Battery Level: %d\n", controller_get_battery_level(E_CONTROLLER_MASTER)); + * } + * \endcode + */ +int32_t controller_get_battery_level(controller_id_e_t id); + +/** + * Checks if a digital channel (button) on the controller is currently pressed. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param button + * The button to read. + * Must be one of DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is pressed. + * If the controller was not connected, then 0 is returned + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * if (controller_get_digital(E_CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_A)) { + * motor_set(1, 100); + * } + * else { + * motor_set(1, 0); + * } + * delay(2); + * } + * } + + * \endcode + */ +int32_t controller_get_digital(controller_id_e_t id, controller_digital_e_t button); + +/** + * Returns a rising-edge case for a controller button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under the + * same circumstances, so only one task should call this function for any given + * button. E.g., Task A calls this function for buttons 1 and 2. Task B may call + * this function for button 3, but should not for buttons 1 or 2. A typical + * use-case for this function is to call inside opcontrol to detect new button + * presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param button + * The button to read. Must be one of + * DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is pressed and had not been pressed + * the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * if (controller_get_digital_new_press(E_CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_A)) { + * // Toggle pneumatics or other similar actions + * } + * + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_get_digital_new_press(controller_id_e_t id, controller_digital_e_t button); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is a slow process, so updates faster than 10ms + * when on a wired connection or 50ms over Vexnet will not be applied to the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * EAGAIN - Could not send the text to the controller. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * while (true) { + * if (!(count % 25)) { + * // Only print every 50ms, the controller text update rate is slow + * controller_print(E_CONTROLLER_MASTER, 0, 0, "Counter: %d", count); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_print(controller_id_e_t id, uint8_t line, uint8_t col, const char* fmt, ...); + +/** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is a slow process, so updates faster than 10ms + * when on a wired connection or 50ms over Vexnet will not be applied to the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * EAGAIN - Could not send the text to the controller. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * while (true) { + * if (!(count % 25)) { + * // Only print every 50ms, the controller text update rate is slow + * controller_set_text(E_CONTROLLER_MASTER, 0, 0, "Example text"); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_set_text(controller_id_e_t id, uint8_t line, uint8_t col, const char* str); + +/** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * controller_set_text(E_CONTROLLER_MASTER, 0, 0, "Example"); + * delay(100); + * controller_clear_line(E_CONTROLLER_MASTER, 0); + * } + * \endcode + */ +int32_t controller_clear_line(controller_id_e_t id, uint8_t line); + +/** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is a slow process, so updates faster than 10ms + * when on a wired connection or 50ms over Vexnet will not be applied to the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * EAGAIN - Could not send the text to the controller. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * controller_set_text(E_CONTROLLER_MASTER, 0, 0, "Example"); + * delay(100); + * controller_clear(E_CONTROLLER_MASTER); + * } + * \endcode + */ +int32_t controller_clear(controller_id_e_t id); + +/** + * Rumble the controller. + * + * \note Controller rumble activation is a slow process, so updates faster than 10ms + * when on a wired connection or 50ms over Vexnet will not be applied to the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - A value other than E_CONTROLLER_MASTER or E_CONTROLLER_PARTNER is + * given. + * EACCES - Another resource is currently trying to access the controller port. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + * \param rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * while (true) { + * if (!(count % 25)) { + * // Only send every 50ms, the controller update rate is slow + * controller_rumble(E_CONTROLLER_MASTER, ". - . -"); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ +int32_t controller_rumble(controller_id_e_t id, const char* rumble_pattern); + +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery's Voltage: %d\n", battery_get_voltage()); + * } + * \endcode + */ +int32_t battery_get_voltage(void); + +/** + * Gets the current current of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery Current: %d\n", battery_get_current()); + * } + * \endcode + */ +int32_t battery_get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery's Temperature: %d\n", battery_get_temperature()); + * } + * \endcode + */ +double battery_get_temperature(void); + +/** + * Gets the current capacity of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery Level: %d\n", battery_get_capacity()); + * } + * \endcode + */ +double battery_get_capacity(void); + +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + * + * \b Example + * \code + * void opcontrol() { + * printf("%i", usd_is_installed()); + * } + * \endcode + */ +int32_t usd_is_installed(void); + +/******************************************************************************/ +/** Date and Time **/ +/******************************************************************************/ + +extern const char* baked_date; +extern const char* baked_time; + +typedef struct { + uint16_t year; // Year - 1980 + uint8_t day; + uint8_t month; // 1 = January +} date_s_t; + +typedef struct { + uint8_t hour; + uint8_t min; + uint8_t sec; + uint8_t sec_hund; // hundredths of a second +} time_s_t; + +///@} + +///@} + +#ifdef __cplusplus +} +} // namespace pros +} +#endif + +#endif // _PROS_MISC_H_ diff --git a/include/pros/misc.hpp b/include/pros/misc.hpp new file mode 100644 index 0000000..8ade055 --- /dev/null +++ b/include/pros/misc.hpp @@ -0,0 +1,532 @@ +/** + * \file pros/misc.hpp + * \ingroup cpp-pros + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reservered. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-misc Miscellaneous C++ API + * \note Additional example code for this module can be found in its [Tutorial.](@ref controller) + */ + +#ifndef _PROS_MISC_HPP_ +#define _PROS_MISC_HPP_ + +#include "pros/misc.h" + +#include +#include + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-misc + */ +class Controller { + /** + * \addtogroup cpp-misc + * ///@{ + */ + public: + /** + * Creates a controller object for the given controller id. + * + * \param id + * The ID of the controller (e.g. the master or partner controller). + * Must be one of CONTROLLER_MASTER or CONTROLLER_PARTNER + */ + explicit Controller(controller_id_e_t id); + + /** + * Checks if the controller is connected. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \return 1 if the controller is connected, 0 otherwise + * + * \b Example + * \code + * void status_display_controller(){ + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * if(!master.is_connected()) { + * pros::lcd::print(0, "Main controller is not connected!"); + * } + * } + * \endcode + */ + std::int32_t is_connected(void); + + /** + * Gets the value of an analog channel (joystick) on a controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param channel + * The analog channel to get. + * Must be one of ANALOG_LEFT_X, ANALOG_LEFT_Y, ANALOG_RIGHT_X, + * ANALOG_RIGHT_Y + * + * \return The current reading of the analog channel: [-127, 127]. + * If the controller was not connected, then 0 is returned + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * motor_move(1, master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * delay(2); + * } + * } + * \endcode + */ + std::int32_t get_analog(controller_analog_e_t channel); + + /** + * Gets the battery capacity of the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \return The controller's battery capacity + * + * \b Example + * \code + * void initialize() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * printf("Battery Capacity: %d\n", master.get_battery_capacity()); + * } + * \endcode + */ + std::int32_t get_battery_capacity(void); + + /** + * Gets the battery level of the controller. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \return The controller's battery level + * + * \b Example + * \code + * void initialize() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * printf("Battery Level: %d\n", master.get_battery_level()); + * } + * \endcode + */ + std::int32_t get_battery_level(void); + + /** + * Checks if a digital channel (button) on the controller is currently + * pressed. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param button + * The button to read. Must be one of + * DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is pressed. + * If the controller was not connected, then 0 is returned + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (master.get_digital(pros::E_CONTROLLER_DIGITAL_A)) { + * motor_set(1, 100); + * } + * else { + * motor_set(1, 0); + * } + * delay(2); + * } + * } + * \endcode + */ + std::int32_t get_digital(controller_digital_e_t button); + + /** + * Returns a rising-edge case for a controller button press. + * + * This function is not thread-safe. + * Multiple tasks polling a single button may return different results under + * the same circumstances, so only one task should call this function for any + * given button. E.g., Task A calls this function for buttons 1 and 2. + * Task B may call this function for button 3, but should not for buttons + * 1 or 2. A typical use-case for this function is to call inside opcontrol + * to detect new button presses, and not in any other tasks. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param button + * The button to read. Must be one of + * DIGITAL_{RIGHT,DOWN,LEFT,UP,A,B,Y,X,R1,R2,L1,L2} + * + * \return 1 if the button on the controller is pressed and had not been + * pressed the last time this function was called, 0 otherwise. + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (master.get_digital_new_press(pros::E_CONTROLLER_DIGITAL_A)) { + * // Toggle pneumatics or other similar actions + * } + * + * delay(2); + * } + * } + * \endcode + */ + std::int32_t get_digital_new_press(controller_digital_e_t button); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + template + T convert_args(T arg) { + return arg; + } + const char* convert_args(const std::string& arg) { + return arg.c_str(); + } +#pragma GCC diagnostic pop + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param fmt + * The format string to print to the controller + * \param ... + * The argument list for the format string + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (!(count % 25)) { + * // Only print every 50ms, the controller text update rate is slow + * master.print(0, 0, "Counter: %d", count); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ + template + std::int32_t print(std::uint8_t line, std::uint8_t col, const char* fmt, Params... args) { + return pros::c::controller_print(_id, line, col, fmt, convert_args(args)...); + } + + /** + * Sets text to the controller LCD screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param line + * The line number at which the text will be displayed [0-2] + * \param col + * The column number at which the text will be displayed [0-14] + * \param str + * The pre-formatted string to print to the controller + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (!(count % 25)) { + * // Only print every 50ms, the controller text update rate is slow + * master.set_text(0, 0, "Example text"); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ + std::int32_t set_text(std::uint8_t line, std::uint8_t col, const char* str); + std::int32_t set_text(std::uint8_t line, std::uint8_t col, const std::string& str); + + /** + * Clears an individual line of the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param line + * The line number to clear [0-2] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * master.set_text(0, 0, "Example"); + * delay(100); + * master.clear_line(0); + * } + * \endcode + */ + std::int32_t clear_line(std::uint8_t line); + + /** + * Rumble the controller. + * + * \note Controller rumble activation is currently in beta, so continuous, fast + * updates will not work well. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \param rumble_pattern + * A string consisting of the characters '.', '-', and ' ', where dots + * are short rumbles, dashes are long rumbles, and spaces are pauses. + * Maximum supported length is 8 characters. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * int count = 0; + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * while (true) { + * if (!(count % 25)) { + * // Only send every 50ms, the controller update rate is slow + * master.rumble(". - . -"); + * } + * count++; + * delay(2); + * } + * } + * \endcode + */ + std::int32_t rumble(const char* rumble_pattern); + + /** + * Clears all of the lines on the controller screen. + * + * \note Controller text setting is currently in beta, so continuous, fast + * updates will not work well. On vexOS version 1.0.0 this function will + * block for 110ms. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the controller + * port. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Controller master(pros::E_CONTROLLER_MASTER); + * master.set_text(0, 0, "Example"); + * delay(100); + * master.clear(); + * } + * \endcode + */ + std::int32_t clear(void); + + private: + controller_id_e_t _id; + ///@} +}; +} // namespace v5 + +namespace battery { +/** + * \addtogroup cpp-misc + * ///@{ + */ +/** + * Gets the current voltage of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current voltage of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery Level: %.2f\n", get_capacity()); + * } + * \endcode + */ +double get_capacity(void); + +/** + * Gets the current current of the battery in milliamps, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current current of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery Current: %d\n", get_current()); + * } + * \endcode + */ +int32_t get_current(void); + +/** + * Gets the current temperature of the battery, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current temperature of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery's Temperature: %.2f\n", get_temperature()); + * } + * \endcode + */ +double get_temperature(void); + +/** + * Gets the current capacity of the battery in millivolts, as reported by VEXos. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCES - Another resource is currently trying to access the battery port. + * + * \return The current capacity of the battery + * + * \b Example + * \code + * void initialize() { + * printf("Battery's Voltage: %d\n", get_voltage()); + * } + * \endcode + */ +int32_t get_voltage(void); +///@} +} // namespace battery + +namespace competition { +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + * + * \b Example + * \code + * void status_display_task(){ + * if(!is_connected()) { + * pros::lcd::print(0, "V5 Brain is not connected!"); + * } + * if(is_autonomous()) { + * pros::lcd::print(0, "V5 Brain is in autonomous mode!"); + * } + * if(!is_disabled()) { + * pros::lcd::print(0, "V5 Brain is disabled!"); + * } + * \endcode + */ +std::uint8_t get_status(void); +std::uint8_t is_autonomous(void); +std::uint8_t is_connected(void); +std::uint8_t is_disabled(void); +} // namespace competition + +namespace usd { +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + * + * \b Example + * \code + * void opcontrol() { + * printf("%i", is_installed()); + * } + * \endcode + */ +std::int32_t is_installed(void); +} // namespace usd + +} // namespace pros + +#endif // _PROS_MISC_HPP_ diff --git a/include/pros/motor_group.hpp b/include/pros/motor_group.hpp new file mode 100644 index 0000000..f99576e --- /dev/null +++ b/include/pros/motor_group.hpp @@ -0,0 +1,2341 @@ +/** + * \file pros/motor_group.hpp + * \ingroup cpp-motor-group + * + * Contains prototypes for the V5 Motor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html to learn + * more. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-motor-group Motor Groups C++ API + */ + +#ifndef _PROS_MOTOR_GROUP_HPP_ +#define _PROS_MOTOR_GROUP_HPP_ + +#include +#include + +#include "pros/abstract_motor.hpp" +#include "pros/colors.hpp" +#include "pros/device.hpp" +#include "pros/motors.h" +#include "pros/motors.hpp" +#include "rtos.hpp" + +namespace pros { +inline namespace v5 { +class MotorGroup : public virtual AbstractMotor { + /** + * \addtogroup cpp-motor-group + * @{ + */ + public: + + /** + * Constructs a new MotorGroup object. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. + * A reversed motor will reverse the input or output movement functions and movement related + * telemetry in order to produce consistant behavior with non-reversed motors + * + * \param gearset = pros::v5::MotorGears::green + * Optional parameter for the gearset for the motor. + * set to pros::v5::MotorGears::green if not specifed. + * + * \param encoder_units = pros::v5::MotorUnits::degrees + * Optional parameter for the encoder units of the motor + * set to pros::v5::MotorUnits::degrees if not specified by the user + * + * \b Example + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with + * with both motors using the green gearset and degrees as the encoder units + * MotorGroup rotations_mg({4, 5}, pros::v5::MotorGears::blue, pros::v5::MotorUnits::rotations); + * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units + * } + * \endcode + */ + explicit MotorGroup(const std::initializer_list, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); + /** + * Constructs a new MotorGroup object. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * \param port + * A initializer list of V5 port numbers from 1 to 21, or from -21 to -1 for reversed motors. + * A reversed motor will reverse the input or output movement functions and movement related + * telemetry in order to produce consistant behavior with non-reversed motors + * + * \param gearset = pros::v5::MotorGears::green + * Optional parameter for the gearset for the motor. + * set to pros::v5::MotorGears::green if not specifed. + * + * \param encoder_units = pros::v5::MotorUnits::degrees + * Optional parameter for the encoder units of the motor + * set to pros::v5::MotorUnits::degrees if not specified by the user + * + * \b Example + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with + * with both motors using the green gearset and degrees as the encoder units + * MotorGroup rotations_mg({4, 5}, pros::v5::MotorGears::blue, pros::v5::MotorUnits::rotations); + * //Creates a motor group on ports 4 and 5 with blue motors using rotaions as the encoder units + * } + * \endcode + */ + explicit MotorGroup(const std::vector& ports, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); + + /** + * Constructs a new MotorGroup object from an abstract motor. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * \param abstract_motor + * THe abstract motor to turn into a motor group + * Uses abstract_motor.get_port_all() to get the vector of ports + * + * + * \b Example + * \code + * void opcontrol() { + * MotorGroup first_mg({1, -2}); //Creates a motor on port 1 and a reversed motor on port 2 with + * with both motors using the green gearset and degrees as the encoder units + * AbstractMotor abs_mtr_group = first_mg; + * MotorGroup new_mg = (MotorGroup) abs_mtr_group; + * } + * \endcode + */ + + MotorGroup(AbstractMotor& abstract_motor); + /// \name Motor movement functions + /// These functions allow programmers to make motors move + ///@{ + + /** + * Sets the voltage for the motor group from -128 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of pros::Motor::move() + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - the motor group is empty + * + * \param voltage + * The new voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup MotorGroup ({1,3}, E_MOTOR_GEARSET_18); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t operator=(std::int32_t voltage) const; + + /** + * Sets the voltage for the motor group from -127 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of motor_move() + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param voltage + * The new voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup MotorGroup ({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg.move(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move(std::int32_t voltage) const; + + /** + * Sets the target absolute position for the motor group to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - the motor group has size 0 + * + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg ({1,3}); + * mg.move_absolute(100, 100); // Moves 100 units forward + * while (!((mg.get_position() < 105) && (mg.get_position() > 95))) { + * // Continue running this loop as long as the mg is not within +-5 units of its goal + * pros::delay(2); + * } + * mg.move_absolute(100, 100); // This does not cause a movement + * while (!((mg.get_position() < 105) && (mg.get_position() > 95))) { + * pros::delay(2); + * } + * mg.tare_position(); + * mg.move_absolute(100, 100); // Moves 100 units forward + * while (!((mg.get_position() < 105) && (mg.get_position() > 95))) { + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move_absolute(const double position, const std::int32_t velocity) const; + + /** + * Sets the relative target position for the motor group to move to. + * + * This movement is relative to the current position of each motor as given in + * pros::MotorGroup::get_position(). Providing 10.0 as the position parameter + * would result in the motor moving 10 units, no matter what the + * current position is. + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_relative(100, 100); // Moves 100 units forward + * while (!((mg.get_position() < 105) && (mg.get_position() > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * pros::delay(2); + * } + * mg.move_relative(100, 100); // Also moves 100 units forward + * while (!((mg.get_position() < 205) && (mg.get_position() > 195))) { + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move_relative(const double position, const std::int32_t velocity) const; + + /** + * Sets the velocity for the motor group. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param velocity + * The new velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_velocity(100); + * pros::delay(1000); // Move at 100 RPM for 1 second + * mg.move_velocity(0); + * } + * \endcode + */ + std::int32_t move_velocity(const std::int32_t velocity) const; + + /** + * Sets the output voltage for the motor group from -12000 to 12000 in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * mg.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * mg.move_voltage(0); + * } + * \endcode + */ + std::int32_t move_voltage(const std::int32_t voltage) const; + + + /** + * Stops the motor group using the currently configured brake mode. + * + * This function sets motor velocity to zero, which will cause it to act + * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, + * this function may behave differently than calling move_absolute(0) + * or motor_move_relative(0). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * Motor motor(1); + * mg.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * motor.brake(); + * } + * \endcode + */ + std::int32_t brake(void) const; + + /** + * Changes the output velocity for a profiled movement (move_absolute or + * move_relative). This will have no effect if the motor group is not following + * a profiled movement. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg ({1,3}); + * mg.move_absolute(100, 100); + * pros::delay(100); + * mg.modify_profiled_velocity(0); // Stop the motor group early + * } + * \endcode + */ + std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + + /** + * Gets the target position set for a motor in the motor group, with a parameter + * for the motor index. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); + * // get the target position from motor at index 1. (port 3) + * std::cout << "Motor Target: " << mg.get_target_position(1); + * // Prints 100 + * } + * \endcode + */ + double get_target_position(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the the target positions set for the motor group + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The Motor group is empty + * + * \return The a vector of the target positions in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); + * std::cout << "Motor Target: " << mg.get_target_position_all()[0]; + * // Prints 100 + * } + * \endcode + */ + std::vector get_target_position_all(void) const; + + /** + * Gets the velocity commanded to the motor by the user at the index specified. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * EDOM - The motor group was empty + * + * \param index Optional parameter. + * The zero indexed index of the motor in the motor group + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg ({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * // get the target velocity from motor at index 1. (port 3) + * std::cout << "Motor Velocity: " << mg.get_target_velocity(1); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_target_velocity(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the velocity commanded to the motor by the user + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - THe motor group is empty + * + * \return A vector of the commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg ({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * std::cout << "Motor Velocity: " << mg.get_target_velocity_all(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_target_velocity_all(void) const; + + ///@} + + /// \name Motor telemetry functions + /// These functions allow programmers to collect telemetry from motors + ///@{ + + /** + * Gets the actual velocity of a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - THe motor group is empty + * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter. + * The zero indexed index of the motor in the motor group + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * while (true) { + * mg = controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y); + * // get the actual velocity from motor at index 1. (port 3) + * printf("Actual velocity: %lf\n", mg.get_actual_velocity(1)); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_actual_velocity(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the the actual velocity of each motor the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - THe motor group is empty + * + * \return A vector of the each motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * while (true) { + * mg = controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y); + * // get the target velocity from motor at index 1. (port 3) + * printf("Actual velocity: %lf\n", mg.get_actual_velocity(1)); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_actual_velocity_all(void) const; + + /** + * Gets the current drawn by a motor in the motor group in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter. + * The zero indexed index of the motor in the motor group + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * //Print the current draw for the motor at index 1. (port 3) + * std::cout << "Motor Current Draw: " << mg.get_current_draw(1); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_current_draw(const std::uint8_t index = 0) const; + /** + * Gets a vector of the current drawn each motor in the motor group in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * + * \return A vector with each motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Current Draw: " << mg.get_current_draw_all(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_current_draw_all(void) const; + + /** + * Gets the direction of movement for a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * //Print the motor direction for the motor at index 1. (port 3) + * std::cout << "Motor Direction: " << mg.get_direction(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_direction(const std::uint8_t index = 0) const; + /** + * Gets a vector of the directions of movement for each motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Direction: " << mg.get_direction_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_direction_all(void) const; + + /** + * Gets the efficiency of a motor in the motor group in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * //Prints the efficiency of the motor at index 1 (port 3) + * std::cout << "Motor Efficiency: " << mg.get_efficiency(1); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_efficiency(const std::uint8_t index = 0) const; + /** + * Gets a vector of the efficiency of each motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - THe motor group is empty + * + * \return A vector containing each motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Efficiency: " << mg.get_efficiency_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_efficiency_all(void) const; + + /** + * Gets the faults experienced by a motor in the motor group. + * + * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return A bitfield containing the motor's faults. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << mg.get_faults(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::uint32_t get_faults(const std::uint8_t index = 0) const; + /** + * Gets a vector of the faults experienced by each motor in the motor group. + * + * Compare these bitfields to the bitmasks in pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * EDOM - The motor group is empty + * + * + * \return A vector containing the bitfields containing each motor's faults. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << mg.get_faults_all(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_faults_all(void) const; + /** + * Gets the flags set by a motor in the motor group's operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return A bitfield containing the motor's flags. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << mg.get_faults(1); + * pros::delay(2); + * } + * } + * \endcode + */ + std::uint32_t get_flags(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the flags set by each motor in the motor groups's operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A bitfield containing the motor's flags. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << mg.get_faults_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_flags_all(void) const; + + /** + * Gets the absolute position of a motor in the motor group in its encoder units. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << mg.get_position(1); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_position(const std::uint8_t index = 0) const; + /** + * Gets a vector of the absolute position of each motor in its encoder units. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector of the motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << mg.get_position_all(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_position_all(void) const; + + /** + * Gets the power drawn by a motor in the motor group in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Power: " << mg.get_power(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_power(const std::uint8_t index = 0) const; + /** + * Gets a vector of the power drawn by each motor in the motor group in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector of each motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Power: " << mg.get_power_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_power_all(void) const; + /** + * Gets the raw encoder count of a motor in the motor group at a given timestamp. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * + * \param timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + * + * \b Example + * \code + * void opcontrol() { + * std::uint32_t now = pros::millis(); + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << mg.get_raw_position(&now); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_raw_position(std::uint32_t* const timestamp, const std::uint8_t index = 0) const; + /** + * Gets the raw encoder count of each motor at a given timestamp. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \return A vector of each raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + * + * \b Example + * \code + * void opcontrol() { + * std::uint32_t now = pros::millis(); + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << mg.get_raw_position_all(&now)[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_raw_position_all(std::uint32_t* const timestamp) const; + + /** + * Gets the temperature of a motor in the motor group in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Temperature: " << mg.get_temperature(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_temperature(const std::uint8_t index = 0) const; + /** + * Gets the temperature of each motor in the motor group in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector of each motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Temperature: " << mg.get_temperature_all()[1]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_temperature_all(void) const; + /** + * Gets the torque generated by a motor in the motor groupin Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Torque: " << mg.get_torque(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_torque(const std::uint8_t index = 0) const; + /** + * Gets a vector of the torque generated by each motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector containing each motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Torque: " << mg.get_torque(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_torque_all(void) const; + /** + * Gets the voltage delivered to a motor in the motor group in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Voltage: " << mg.get_voltage(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_voltage(const std::uint8_t index = 0) const; + /** + * Gets a vector of the voltage delivered to each motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector of each motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Voltage: " << mg.get_voltage_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_voltage_all(void) const; + + /** + * Checks if a motor in the motor group is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its current limit?: " << mg.is_over_current(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t is_over_current(const std::uint8_t index = 0) const; + /** + * Checks if each motor in the motor group is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector containing the following for each motor: 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its current limit?: " << motor.is_over_current_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector is_over_current_all(void) const; + + /** + * Gets the temperature limit flag for a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its temperature limit?: " << motor.is_over_temp(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t is_over_temp(const std::uint8_t index = 0) const; + /** + * Gets a vector with the temperature limit flag for each motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its temperature limit?: " << motor.is_over_temp(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector is_over_temp_all(void) const; + + ///@} + + /// \name Motor configuration functions + /// These functions allow programmers to configure the behavior of motors + ///@{ + + /** + * Gets the brake mode that was set for a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return One of Motor_Brake, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << mg.get_brake_mode(); + * } + * \endcode + */ + MotorBrake get_brake_mode(const std::uint8_t index = 0) const; + /** + * Gets a vector with the brake mode that was set for each motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector with one of Motor_Brake for each motor in the motor group, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << mg.get_brake_mode_all()[0]; + * } + * \endcode + */ + std::vector get_brake_mode_all(void) const; + + /** + * Gets the current limit for a motor in the motor group in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * while (true) { + * std::cout << "Motor Current Limit: " << mg.get_current_limit(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_current_limit(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the current limit for each motor in the motor group in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector of each motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * while (true) { + * std::cout << "Motor Current Limit: " << mg.get_current_limit_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_current_limit_all(void) const; + + /** + * Gets the encoder units that were set for a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return One of Motor_Units according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Encoder Units: " << mg.get_encoder_units(); + * } + * \endcode + */ + MotorUnits get_encoder_units(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the encoder units that were set for each motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \return A vector with the following for each motor, One of Motor_Units according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Encoder Units: " << mg.get_encoder_units_all()[0]; + * } + * \endcode + */ + std::vector get_encoder_units_all(void) const; + + /** + * Gets the gearset that was set for a motor in the motor group. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + *\param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return One of Motor_Gears according to what is set for the motor, + * or pros::Motor_Gears::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Gearing: " << mg.get_gearing(); + * } + * \endcode + */ + MotorGears get_gearing(const std::uint8_t index = 0) const; + /** + * Gets a vector of the gearset that was set for each motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * + * \return A vector with one of Motor_Gears according to what is set for the motor, + * or pros::Motor_Gears::invalid if the operation failed for each motor. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg ({1,3}, E_MOTOR_GEARSET_06, false, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Gearing: " << mg.get_gearing_all()[0]; + * } + * \endcode + */ + std::vector get_gearing_all(void) const; + + /** + * Gets a vector with all the port numbers in the motor group. + * A port will be negative if the motor in the motor group is reversed + * + * @return a vector with all the port numbers for the motor group + */ + std::vector get_port_all(void) const; + + /** + * Gets the voltage limit of a motor in the motor group set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + *\param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * std::cout << "Motor Voltage Limit: " << mg.get_voltage_limit(1); + * } + * \endcode + */ + std::int32_t get_voltage_limit(const std::uint8_t index = 0) const; + + /** + * Gets a vector of the voltage limit of each motor in the motor group + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The Motor group is empty + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * std::cout << "Motor Voltage Limit: " << mg.get_voltage_limit_all()[0]; + * } + * \endcode + */ + std::vector get_voltage_limit_all(void) const; + + /** + * Gets the operation direction of a motor in the motor group as set by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + *\param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * std::cout << "Is the motor reversed? " << motor.is_reversed(); + * // Prints "0" + * } + * \endcode + */ + std::int32_t is_reversed(const std::uint8_t index = 0) const; + /** + * Gets a vector of the operation direction of each motor in the motor group as set by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - The motor group is empty + * + * \return A vector conatining the following for each motor: 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * std::cout << "Is the motor reversed? " << motor.is_reversed_all()[0]; + * // Prints "0" + * } + * \endcode + */ + std::vector is_reversed_all(void) const; + + /** + * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param mode + * The Motor_Brake to set for the motor + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode(pros::MotorBrake::brake, 1); + * std::cout << "Brake Mode: " << mg.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode(const MotorBrake mode, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param mode + * The Motor_Brake to set for the motor + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD, 1); + * std::cout << "Brake Mode: " << mg.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode(const pros::motor_brake_mode_e_t mode, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Brake all the motors in the motor group. Works with the C enum + * and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param mode + * The Motor_Brake to set for the motor + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode_all(pros::MotorBrake:brake); + * std::cout << "Brake Mode: " << mg.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode_all(const MotorBrake mode) const; + /** + * Sets one of Motor_Brake to a motor in the motor group. Works with the C enum + * and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param mode + * The Motor_Brake to set for the motor + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_brake_mode_all(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << mg.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode_all(const pros::motor_brake_mode_e_t mode) const; + /** + * Sets the current limit for one motor in the motor group in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param limit + * The new current limit in mA + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * mg.set_current_limit(1000); + * while (true) { + * mg = controller_get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will reduce its output at 1000 mA instead of the default 2500 mA + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_current_limit(const std::int32_t limit, const std::uint8_t index = 0) const; + /** + * Sets the current limit for every motor in the motor group in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group was empty + * + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * mg.set_current_limit_all(1000); + * while (true) { + * mg = controller_get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will reduce its output at 1000 mA instead of the default 2500 mA + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_current_limit_all(const std::int32_t limit) const; + /** + * Sets one of Motor_Units for one motor in the motor group's motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param units + * The new motor encoder units + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_encoder_units(E_MOTOR_ENCODER_DEGREES, 1); + * std::cout << "Encoder Units: " << mg.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units(const MotorUnits units, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Units for one motor in the motor group's motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param units + * The new motor encoder units + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_encoder_units(E_MOTOR_ENCODER_DEGREES, 1); + * std::cout << "Encoder Units: " << mg.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units(const pros::motor_encoder_units_e_t units, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Units for every motor in the motor group's motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_encoder_units_all(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << mg.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units_all(const MotorUnits units) const; + /** + * Sets one of Motor_Units for every motor in the motor group's motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_encoder_units_all(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << mg.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units_all(const pros::motor_encoder_units_e_t units) const; + /** + * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param gearset + * The new geatset of the motor + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing(pros::MotorGears::blue, 1); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const; + /** + * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param gearset + * The new geatset of the motor + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing(E_MOTOR_GEARSET_06, 1); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(const pros::motor_gearset_e_t gearset, const std::uint8_t index = 0) const; + /** + * Sets one of the gear cartridge (red, green, blue) for one motor in the motor group. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param gearset + * The new geatset of the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing_all(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing_all(const MotorGears gearset) const; + /** + * Sets one of the gear cartridge (red, green, blue) for every motor in the motor group. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param gearset + * The new geatset of the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_gearing_all(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << mg.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing_all(const pros::motor_gearset_e_t gearset) const; + + /** + * sets the reversal for a motor in the motor group. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * //reverse the motor at index 1 (port 3) + * mg.set_reversed(true, 1); + * std::cout << "Is this motor reversed? " << motor.is_reversed(1); + * pros::delay(100); + * // unreverse the motor at index 1 (port 3) + * mg.set_reversed(false, 1); + * std::cout << "Is this motor reversed? " << motor.is_reversed(1); + * } + * \endcode + */ + std::int32_t set_reversed(const bool reverse, const std::uint8_t index = 0); + /** + * Sets the reversal for all the motors in the motor group. + * + * This will invert its movements and the values returned for its position. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - The motor group is empty + * + * \param reverse + * True reverses the motor, false is default + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::MotorGroup mg({1,3}); + * mg.set_reversed_all(true); + * std::cout << "Is this motor reversed? " << motor.is_reversed(); + * } + * \endcode + */ + std::int32_t set_reversed_all(const bool reverse); + + /** + * Sets the voltage limit for a motor in the motor group in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param limit + * The new voltage limit in Volts + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * mg.set_voltage_limit(10000, 1); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor on at index 1 (port 3) will not output more than 10 V + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_voltage_limit(const std::int32_t limit, const std::uint8_t index = 0) const; + + /** + * Sets the voltage limit for every motor in the motor group in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * mg.set_voltage_limit_all(10000); + * while (true) { + * mg = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will not output more than 10 V + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_voltage_limit_all(const std::int32_t limit) const; + + /** + * Sets the position for a motor in the motor group in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param position + * The new reference position in its encoder units + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); // Moves 100 units forward + * mg.move_absolute(100, 100); // This does not cause a movement + * mg.set_zero_position(80); + * mg.set_zero_position(80, 1); + * mg.move_absolute(100, 100); // Moves 80 units forward + * } + * \endcode + * + */ + std::int32_t set_zero_position(const double position, const std::uint8_t index = 0) const; + /** + * Sets the position for every motor in the motor group in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); // Moves 100 units forward + * mg.move_absolute(100, 100); // This does not cause a movement + * + * mg.set_zero_position_all(80); + * mg.move_absolute(100, 100); // Moves 80 units forward + * } + * \endcode + * + */ + std::int32_t set_zero_position_all(const double position) const; + + /** + * Sets the "absolute" zero position of a motor in the motor group to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EDOM - The motor group is empty + * EOVERFLOW - The index is greater than or equal to MotorGroup::size() + * + * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); // Moves 100 units forward + * mg.move_absolute(100, 100); // This does not cause a movement + * + * mg.tare_position(); + * mg.tare_position(1); + * + * mg.move_absolute(100, 100); // Moves 100 units forward + * } + * \endcode + */ + std::int32_t tare_position(const std::uint8_t index = 0) const; + + /** + * Sets the "absolute" zero position of every motor in the motor group to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::MotorGroup mg({1,3}); + * mg.move_absolute(100, 100); // Moves 100 units forward + * mg.move_absolute(100, 100); // This does not cause a movement + * mg.tare_position_all(); + * mg.move_absolute(100, 100); // Moves 100 units forward + * } + * \endcode + */ + std::int32_t tare_position_all(void) const; + + /** + * Returns the number of motors in the motor group + * + * \return the number of motors in the motor group + */ + std::int8_t size(void) const; + + /** + * Gets the port of a motor in the motor group + * + * * \param index Optional parameter, 0 by default. + * The zero indexed index of the motor in the motor group + * + * \return The port of the motor at the specified index. + * The return value is negative if the corresponding motor is reversed + */ + std::int8_t get_port(const std::uint8_t index = 0) const; + + /** + * Appends all the motors in the other motor group reference to this motor group + * + * Maintains the order of the other motor group + * + */ + void operator+=(MotorGroup&); + + /** + * Appends all the motors in the other motor group reference to this motor group + * + * Maintains the order of the other motor group + * + */ + void append(MotorGroup&); + + /** + * Removes the all motors on the port (regardless of reversal) from the motor group + * + * \param port The port to remove from the motor group + * + */ + void erase_port(std::int8_t port); + + ///@} + private: + /** + * The ordered vector of ports used by the motor group + */ + std::vector _ports; + mutable pros::Mutex _MotorGroup_mutex; +}; +} // namespace v5 +} // namespace pros +#endif \ No newline at end of file diff --git a/include/pros/motors.h b/include/pros/motors.h new file mode 100644 index 0000000..ad6ef34 --- /dev/null +++ b/include/pros/motors.h @@ -0,0 +1,1341 @@ +/** + * \file pros/motors.h + * \ingroup c-motors + * + * Contains prototypes for the V5 Motor-related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-motors Motors C API + * \note Additional example code for this module can be found in its [Tutorial](@ref motors). + */ + +#ifndef _PROS_MOTORS_H_ +#define _PROS_MOTORS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \ingroup c-motors + */ + +/** + * \addtogroup c-motors + * @{ + */ + +/// \name Motor movement functions +/// These functions allow programmers to make motors move +///@{ + +/** + * Sets the voltage for the motor from -127 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is analogous + * to use of motor_move_voltage(). + * + * \note This function will not respect brake modes, and simply sets the voltage to the desired value. + * + * \note A negative port will negate the input voltage + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param voltage + * The new motor voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_move(int8_t port, int32_t voltage); + +/** + * Stops the motor using the currently configured brake mode. + * + * This function sets motor velocity to zero, which will cause it to act + * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, + * this function may behave differently than calling motor_move_absolute(port, 0) + * or motor_move_relative(port, 0). + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move(1, 127); + * delay(1000); + * motor_break(1); + * } + * \endcode + */ +int32_t motor_brake(int8_t port); + +/** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with motor_set_zero_position(). + * + * \note This function simply sets the target for the motor, it does not block program + * execution until the movement finishes. The example code shows how to block until a movement is finished. + * + * \note A negative port number will negate the target position + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_absolute(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) < 105) && (motor_get_position(1) > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * delay(2); + * } + * motor_move_absolute(1, 100, 100); // This will not cause a movement + * while(!((motor_get_position(1) < 105) && (motor_get_position(1) > 95))) { + * delay(2); + * } + * + * motor_tare_position(1); + * motor_move_absolute(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) < 105) && (motor_get_position(1) > 95))) { + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_move_absolute(int8_t port, double position, const int32_t velocity); + +/** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor as given in + * motor_get_position(). Providing 10.0 as the position parameter would result + * in the motor moving clockwise 10 units, no matter what the current position + * is. + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. The example code shows how to + * block until a movement is finished. + * + * \note A negative port will negate the target position + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_relative(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) < 105) && (motor_get_position(1) > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * delay(2); + * } + * + * motor_move_relative(1, 100, 100); // Also moves 100 units forward + * while (!((motor_get_position(1) < 205) && (motor_get_position(1) > 195))) { + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_move_relative(int8_t port, double position, const int32_t velocity); + +/** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the gearset + * used for the motor. This results in a range of +-100 for E_MOTOR_GEARSET_36, + * +-200 for E_MOTOR_GEARSET_18, and +-600 for E_MOTOR_GEARSET_6. The velocity + * is held with PID to ensure consistent speed, as opposed to setting the + * motor's voltage. + * + * \note A negative port will negate the velocity + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_velocity(1, 100); + * delay(1000); // Move at 100 RPM for 1 second + * motor_move_velocity(1, 0); + * } + * \endcode + */ +int32_t motor_move_velocity(int8_t port, const int32_t velocity); + +/** + * Sets the output voltage for the motor from -12000 to 12000 in millivolts + * + * \note A negative port negates the voltage + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \note This function will not respect brake modes, and simply sets the + * voltage to the desired value. + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_voltage(1, 12000); + * delay(1000); // Move at max voltage for 1 second + * motor_move_voltage(1, 0); + * } + * \endcode + */ +int32_t motor_move_voltage(int8_t port, const int32_t voltage); + +/** + * Changes the output velocity for a profiled movement (motor_move_absolute or + * motor_move_relative). This will have no effect if the motor is not following + * a profiled movement. + * + * \note A negative port negates the velocity + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_absolute(1, 100, 100); + * delay(100); + * motor_modify_profiled_velocity(1, 0); // Stop the motor early + * } + * \endcode + */ +int32_t motor_modify_profiled_velocity(int8_t port, const int32_t velocity); + +/** + * Gets the target position set for the motor by the user. + * + * \note A negative port negates the return value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_absolute(1, 100, 100); + * printf("Motor Target: %d\n", motor_get_target_position(1)); + * // Prints 100 + * } + * \endcode + */ +double motor_get_target_position(int8_t port); + +/** + * Gets the velocity commanded to the motor by the user. + * + * \note A negative port negates the return value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move_velocity(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Commanded Velocity: %d\n", motor_get_target_velocity(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_get_target_velocity(int8_t port); + +///@} + +/// \name Motor telemetry functions +/// These functions allow programmers to collect telemetry from motors +///@{ + +/** + * Gets the actual velocity of the motor. + * + * \note A negative port negates the return value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Actual velocity: %lf\n", motor_get_actual_velocity(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_actual_velocity(int8_t port); + +/** + * Gets the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Current Draw: %d\n", motor_get_current_draw(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_get_current_draw(int8_t port); + +/** + * Gets the direction of movement for the motor. + * + * \note A negative port number negates the return value. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Direction: %d\n", motor_get_direction(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_get_direction(int8_t port); + +/** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Efficiency: %d\n", motor_get_efficiency(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_efficiency(int8_t port); + +/** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return 1 if the motor's current limit is being exceeded and 0 if the current + * limit is not exceeded, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Current Limit Hit?: %d\n", motor_is_over_current(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_is_over_current(int8_t port); + +/** + * Checks if the motor's temperature is above its limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return 1 if the temperature limit is exceeded and 0 if the the temperature + * is below the limit, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Temp Limit: %d\n", motor_is_over_temp(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_is_over_temp(int8_t port); + + + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * \enum motor_fault_e_t + */ +typedef enum motor_fault_e { + /// No faults + E_MOTOR_FAULT_NO_FAULTS = 0x00, + /// Analogous to motor_is_over_temp() + E_MOTOR_FAULT_MOTOR_OVER_TEMP = 0x01, + /// Indicates a motor h-bridge fault + E_MOTOR_FAULT_DRIVER_FAULT = 0x02, + /// Analogous to motor_is_over_current() + E_MOTOR_FAULT_OVER_CURRENT = 0x04, + /// Indicates an h-bridge over current + E_MOTOR_FAULT_DRV_OVER_CURRENT = 0x08 +} motor_fault_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FAULT_NO_FAULTS pros::E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP pros::E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT pros::E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT pros::E_MOTOR_FAULT_DRV_OVER_CURRENT +#else +#define MOTOR_FAULT_NO_FAULTS E_MOTOR_FAULT_NO_FAULTS +#define MOTOR_FAULT_MOTOR_OVER_TEMP E_MOTOR_FAULT_MOTOR_OVER_TEMP +#define MOTOR_FAULT_DRIVER_FAULT E_MOTOR_FAULT_DRIVER_FAULT +#define MOTOR_FAULT_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#define MOTOR_FAULT_DRV_OVER_CURRENT E_MOTOR_FAULT_DRV_OVER_CURRENT +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's faults. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Faults: %d\n", motor_get_faults(1)); + * delay(2); + * } + * } + * \endcode + */ +uint32_t motor_get_faults(int8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * \enum motor_flag_e_t + * + */ +typedef enum motor_flag_e { + ///There are no flags raised + E_MOTOR_FLAGS_NONE = 0x00, + /// Cannot currently communicate to the motor + E_MOTOR_FLAGS_BUSY = 0x01, + /// Analogous to motor_is_stopped() + E_MOTOR_FLAGS_ZERO_VELOCITY = 0x02, + /// Analogous to motor_get_zero_position_flag() + E_MOTOR_FLAGS_ZERO_POSITION = 0x04 +} motor_flag_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_FLAGS_NONE pros::E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY pros::E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY pros::E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION pros::E_MOTOR_FLAGS_ZERO_POSITION +#else +#define MOTOR_FLAGS_NONE E_MOTOR_FLAGS_NONE +#define MOTOR_FLAGS_BUSY E_MOTOR_FLAGS_BUSY +#define MOTOR_FLAGS_ZERO_VELOCITY E_MOTOR_FLAGS_ZERO_VELOCITY +#define MOTOR_FLAGS_ZERO_POSITION E_MOTOR_FLAGS_ZERO_POSITION +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return A bitfield containing the motor's flags. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Flags: %d\n", motor_get_flags(1)); + * delay(2); + * } + * } + * \endcode + */ +uint32_t motor_get_flags(int8_t port); + +/** + * Gets the raw encoder count of the motor at a given timestamp. + * + * \note A negative port value negates the return value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param[in] timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \return The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + * + * \b Example + * \code + * void opcontrol() { + * uint32_t now = millis(); + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Encoder Count: %d\n", motor_get_raw_position(1, &now)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_get_raw_position(int8_t port, uint32_t* const timestamp); + +/** + * Gets the absolute position of the motor in its encoder units. + * + * \note A negative port value negates the return value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Position: %lf\n", motor_get_position(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_position(int8_t port); + +/** + * Gets the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * uint32_t now = millis(); + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Power: %lf\n", motor_get_power(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_power(int8_t port); + +/** + * Gets the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Temperature: %lf\n", motor_get_temperature(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_temperature(int8_t port); + +/** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Torque: %lf\n", motor_get_torque(1)); + * delay(2); + * } + * } + * \endcode + */ +double motor_get_torque(int8_t port); + +/** + * Gets the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * printf("Motor Voltage: %lf\n", motor_get_voltage(1)); + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_get_voltage(int8_t port); + +///@} + +/// \name Motor configuration functions +/// These functions allow programmers to configure the behavior of motors +///@{ + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * \enum motor_brake_mode_e_t + * Indicates the current 'brake mode' of a motor. + */ +typedef enum motor_brake_mode_e { + /// Motor coasts when stopped, traditional behavior + E_MOTOR_BRAKE_COAST = 0, + /// Motor brakes when stopped + E_MOTOR_BRAKE_BRAKE = 1, + /// Motor actively holds position when stopped + E_MOTOR_BRAKE_HOLD = 2, + /// Invalid brake mode + E_MOTOR_BRAKE_INVALID = INT32_MAX +} motor_brake_mode_e_t; + +/** + * \enum motor_encoder_units_e_t + * Indicates the units used by the motor encoders. + */ +typedef enum motor_encoder_units_e { + /// Position is recorded as angle in degrees as a floating point number + E_MOTOR_ENCODER_DEGREES = 0, + /// Position is recorded as angle in rotations as a floating point number + E_MOTOR_ENCODER_ROTATIONS = 1, + /// Position is recorded as raw encoder ticks as a whole number + E_MOTOR_ENCODER_COUNTS = 2, + ///Invalid motor encoder units + E_MOTOR_ENCODER_INVALID = INT32_MAX +} motor_encoder_units_e_t; + +/** + * \enum motor_gearset_e_t + * Indicates the current internal gear ratio of a motor. + */ +typedef enum motor_gearset_e { + E_MOTOR_GEARSET_36 = 0, // 36:1, 100 RPM, Red gear set + E_MOTOR_GEAR_RED = E_MOTOR_GEARSET_36, // 36:1, 100 RPM, Red gear set + E_MOTOR_GEAR_100 = E_MOTOR_GEARSET_36, // 36:1, 100 RPM, Red gear set + E_MOTOR_GEARSET_18 = 1, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEAR_GREEN = E_MOTOR_GEARSET_18, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEAR_200 = E_MOTOR_GEARSET_18, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEARSET_06 = 2, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEAR_BLUE = E_MOTOR_GEARSET_06, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEAR_600 = E_MOTOR_GEARSET_06, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEARSET_INVALID = INT32_MAX, // Error: Invalid Gearset +} motor_gearset_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define MOTOR_BRAKE_COAST pros::E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE pros::E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD pros::E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID pros::E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES pros::E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS pros::E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS pros::E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID pros::E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 pros::E_MOTOR_GEARSET_36 +#define MOTOR_GEAR_RED pros::E_MOTOR_GEAR_RED +#define MOTOR_GEAR_100 pros::E_MOTOR_GEAR_100 +#define MOTOR_GEARSET_18 pros::E_MOTOR_GEARSET_18 +#define MOTOR_GEAR_GREEN pros::E_MOTOR_GEAR_GREEN +#define MOTOR_GEAR_200 pros::E_MOTOR_GEAR_200 +#define MOTOR_GEARSET_06 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEAR_BLUE pros::E_MOTOR_GEAR_BLUE +#define MOTOR_GEAR_600 pros::E_MOTOR_GEAR_600 +#define MOTOR_GEARSET_INVALID pros::E_MOTOR_GEARSET_INVALID +#else +#define MOTOR_BRAKE_COAST E_MOTOR_BRAKE_COAST +#define MOTOR_BRAKE_BRAKE E_MOTOR_BRAKE_BRAKE +#define MOTOR_BRAKE_HOLD E_MOTOR_BRAKE_HOLD +#define MOTOR_BRAKE_INVALID E_MOTOR_BRAKE_INVALID +#define MOTOR_ENCODER_DEGREES E_MOTOR_ENCODER_DEGREES +#define MOTOR_ENCODER_ROTATIONS E_MOTOR_ENCODER_ROTATIONS +#define MOTOR_ENCODER_COUNTS E_MOTOR_ENCODER_COUNTS +#define MOTOR_ENCODER_INVALID E_MOTOR_ENCODER_INVALID +#define MOTOR_GEARSET_36 E_MOTOR_GEARSET_36 +#define MOTOR_GEAR_RED E_MOTOR_GEAR_RED +#define MOTOR_GEAR_100 E_MOTOR_GEAR_100 +#define MOTOR_GEARSET_18 E_MOTOR_GEARSET_18 +#define MOTOR_GEAR_GREEN E_MOTOR_GEAR_GREEN +#define MOTOR_GEAR_200 E_MOTOR_GEAR_200 +#define MOTOR_GEARSET_06 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 E_MOTOR_GEARSET_06 +#define MOTOR_GEAR_BLUE E_MOTOR_GEAR_BLUE +#define MOTOR_GEAR_600 E_MOTOR_GEAR_600 +#define MOTOR_GEARSET_INVALID E_MOTOR_GEARSET_INVALID +#endif +#endif + +/** + * \struct motor_pid_full_s_t + * + * Holds the information about a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_full_s { + /// The feedforward constant + uint8_t kf; + /// The proportional constant + uint8_t kp; + /// The integral constants + uint8_t ki; + /// The derivative constant + uint8_t kd; + /// A constant used for filtering the profile acceleration + uint8_t filter; + /// The integral limit + uint16_t limit; + /// The threshold for determining if a position movement hasreached its goa l. This has no effect for velocity PID calculations. + uint8_t threshold; + /// The rate at which the PID computation is run in ms + uint8_t loopspeed; +} motor_pid_full_s_t; + +/** + * \struct motor_pid_s_t + * + * Holds just the constants for a Motor's position or velocity PID controls. + * + * These values are in 4.4 format, meaning that a value of 0x20 represents 2.0, + * 0x21 represents 2.0625, 0x22 represents 2.125, etc. + */ +typedef struct motor_pid_s { + /// The feedforward constant + uint8_t kf; + /// The proportional constant + uint8_t kp; + /// The integral constants + uint8_t ki; + /// The derivative constant + uint8_t kd; +} motor_pid_s_t; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * + * \code + * void autonomous() { + * motor_move_absolute(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * delay(2); + * } + * motor_move_absolute(1, 100, 100); // This does not cause a movement + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * delay(2); + * } + * + * motor_set_zero_position(1, 80); + * motor_move_absolute(1, 100, 100); // Moves 80 units forward + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_set_zero_position(int8_t port, const double position); + +/** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_move_absolute(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * delay(2); + * } + * motor_move_absolute(1, 100, 100); // This does not cause a movement + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * delay(2); + * } + * + * motor_tare_position(1); + * motor_move_absolute(1, 100, 100); // Moves 100 units forward + * while (!((motor_get_position(1) - 100 < 105) && (motor_get_position(1) - 100 > 95))) { + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_tare_position(int8_t port); + +/** + * Sets one of motor_brake_mode_e_t to the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param mode + * The motor_brake_mode_e_t to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * motor_set_brake_mode(1, E_MOTOR_BRAKE_HOLD); + * printf("Brake Mode: %d\n", motor_get_brake_mode(1)); + * } + * \endcode + */ +int32_t motor_set_brake_mode(int8_t port, const motor_brake_mode_e_t mode); + +/** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * motor_set_current_limit(1, 1000); + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * // The motor will reduce its output at 1000 mA instead of the default 2500 mA + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_set_current_limit(int8_t port, const int32_t limit); + +/** + * Sets one of motor_encoder_units_e_t for the motor encoder. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * motor_set_encoder_units(1, E_MOTOR_ENCODER_DEGREES); + * printf("Encoder Units: %d\n", motor_get_encoder_units(1)); + * } + * \endcode + */ +int32_t motor_set_encoder_units(int8_t port, const motor_encoder_units_e_t units); + +/** + * Sets one of motor_gearset_e_t for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * motor_set_gearing(1, E_MOTOR_GEARSET_06); + * printf("Brake Mode: %d\n", motor_get_gearing(1)); + * } + * \endcode + */ +int32_t motor_set_gearing(int8_t port, const motor_gearset_e_t gearset); + +/** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor_set_voltage_limit(1, 10000); + * while (true) { + * motor_move(1, controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y)); + * // The motor will not output more than 10 V + * delay(2); + * } + * } + * \endcode + */ +int32_t motor_set_voltage_limit(int8_t port, const int32_t limit); + +/** + * Gets the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return One of motor_brake_mode_e_t, according to what was set for the motor, + * or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * motor_set_brake_mode(1, E_MOTOR_BRAKE_HOLD); + * printf("Brake Mode: %d\n", motor_get_brake_mode(1)); + * } + * \endcode + */ +motor_brake_mode_e_t motor_get_brake_mode(int8_t port); + +/** + * Gets the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void initialize() { + * printf("Motor Current Limit: %d\n", motor_get_current_limit(1)); + * // Prints "Motor Current Limit: 2500" + * } + * \endcode + */ +int32_t motor_get_current_limit(int8_t port); + +/** + * Gets the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return One of motor_encoder_units_e_t according to what is set for the motor + * or E_MOTOR_ENCODER_INVALID if the operation failed. + */ +motor_encoder_units_e_t motor_get_encoder_units(int8_t port); + +/** + * Gets the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * printf("Motor Encoder Units: %d\n", motor_get_encoder_units(1)); + * // Prints E_MOTOR_ENCODER_DEGREES by default + * } + * \endcode + */ +motor_gearset_e_t motor_get_gearing(int8_t port); + +/** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation imposed + * on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void initialize() { + * printf("Motor Voltage Limit: %d\n", motor_get_voltage_limit(1)); + * // Prints 0 by default, indicating no limit + * } + * \endcode + */ +int32_t motor_get_voltage_limit(int8_t port); + +///@} + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_MOTORS_H_ diff --git a/include/pros/motors.hpp b/include/pros/motors.hpp new file mode 100644 index 0000000..f0de7eb --- /dev/null +++ b/include/pros/motors.hpp @@ -0,0 +1,2443 @@ +/** + * \file pros/motors.hpp + * \ingroup cpp-motors + * + * Contains prototypes for the V5 Motor-related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-motors Motors C++ API + * \note Additional example code for this module can be found in its [Tutorial](@ref motors). + */ + +#ifndef _PROS_MOTORS_HPP_ +#define _PROS_MOTORS_HPP_ + +#include +#include + +#include "pros/abstract_motor.hpp" +#include "pros/device.hpp" +#include "pros/motors.h" +#include "rtos.hpp" + +namespace pros { +inline namespace v5 { + +class Motor : public AbstractMotor, public Device { + public: + /** + * \addtogroup cpp-motors + * @{ + */ + + /** + * Constructs a new Motor object. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed motors. + * A reversed motor will reverse the input or output movement functions and movement related + * telemetry in order to produce consistant behavior with non-reversed motors + * + * \param gearset = pros::v5::MotorGears::green + * Optional parameter for the gearset for the motor. + * set to pros::v5::MotorGears::green if not specifed. + * + * \param encoder_units = pros::v5::MotorUnits::degrees + * Optional parameter for the encoder units of the motor + * set to pros::v5::MotorUnits::degrees if not specified by the user + * + * \b Example + * \code + * void opcontrol() { + * Motor first_motor(1); //Creates a motor on port 1 with green gearset and degrees as the encoder units + * Motor reversed_motor(-2); //Creates a reversed motor on port 1 with standard gearset and encoder units + * Motor blue_motor(3, pros::v5::MotorGears::blue); //Creates a motor on port 3 with blue gear set and degrees + * Motor rotations_motor(4, pros::v5::MotorGears::green, pros::v5::MotorUnits::rotations); port 4 w/ rotations + * + * } + * \endcode + * + */ + explicit Motor(const std::int8_t port, const pros::v5::MotorGears gearset = pros::v5::MotorGears::green, + const pros::v5::MotorUnits encoder_units = pros::v5::MotorUnits::degrees); + + + + /** + * Constructs a new Motor object. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a motor + * + * \param The abstract motor to create into a motor + * Creates a new motor on the port of abstract_motor.get_port(), maintaining it's reversal status. + * + * + * \b Example + * \code + * void opcontrol() { + * Motor first_motor(1); //Creates a motor on port 1 with green gearset and degrees as the encoder units + * AbstractMotor abs_motor = first_motor; + * Motor new_motor = (Motor) abs_motor; + * + * } + * \endcode + * + */ + Motor(AbstractMotor& abstract_motor); + + + /// \name Motor movement functions + /// These functions allow programmers to make motors move + ///@{ + + /** + * Sets the voltage for the motor from -128 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of pros::Motor::move(). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param voltage + * The new motor voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1, E_MOTOR_GEARSET_18); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t operator=(std::int32_t voltage) const; + + /** + * Sets the voltage for the motor from -127 to 127. + * + * This is designed to map easily to the input from the controller's analog + * stick for simple opcontrol use. The actual behavior of the motor is + * analogous to use of motor_move(). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param voltage + * The new motor voltage from -127 to 127 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor Motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor.move(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move(std::int32_t voltage) const; + + /** + * Sets the target absolute position for the motor to move to. + * + * This movement is relative to the position of the motor when initialized or + * the position when it was most recently reset with + * pros::Motor::set_zero_position(). + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The absolute position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); // Moves 100 units forward + * while (!((motor.get_position() < 105) && (motor.get_position() > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * pros::delay(2); + * } + * motor.move_absolute(100, 100); // This does not cause a movement + * while (!((motor.get_position() < 105) && (motor.get_position() > 95))) { + * pros::delay(2); + * } + * motor.tare_position(); + * motor.move_absolute(100, 100); // Moves 100 units forward + * while (!((motor.get_position() < 105) && (motor.get_position() > 95))) { + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move_absolute(const double position, const std::int32_t velocity) const; + + /** + * Sets the relative target position for the motor to move to. + * + * This movement is relative to the current position of the motor as given in + * pros::Motor::motor_get_position(). Providing 10.0 as the position parameter + * would result in the motor moving clockwise 10 units (counter clockwise if reversed), + * no matter what the current position is. + * + * \note This function simply sets the target for the motor, it does not block + * program execution until the movement finishes. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The relative position to move to in the motor's encoder units + * \param velocity + * The maximum allowable velocity for the movement in RPM + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_relative(100, 100); // Moves 100 units forward + * while (!((motor.get_position() < 105) && (motor.get_position() > 95))) { + * // Continue running this loop as long as the motor is not within +-5 units of its goal + * pros::delay(2); + * } + * motor.move_relative(100, 100); // Also moves 100 units forward + * while (!((motor.get_position() < 205) && (motor.get_position() > 195))) { + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t move_relative(const double position, const std::int32_t velocity) const; + + /** + * Sets the velocity for the motor. + * + * This velocity corresponds to different actual speeds depending on the + * gearset used for the motor. This results in a range of +-100 for + * E_MOTOR_GEARSET_36, +-200 for E_MOTOR_GEARSET_18, and +-600 for + * E_MOTOR_GEARSET_6. The velocity is held with PID to ensure consistent + * speed, as opposed to setting the motor's voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from -+-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_velocity(100); + * pros::delay(1000); // Move at 100 RPM for 1 second + * motor.move_velocity(0); + * } + * \endcode + */ + std::int32_t move_velocity(const std::int32_t velocity) const; + + /** + * Sets the output voltage for the motor from -12000 to 12000 in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param port + * The V5 port number from 1-21 + * \param voltage + * The new voltage value from -12000 to 12000 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * motor.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * motor.move_voltage(0); + * } + * \endcode + */ + std::int32_t move_voltage(const std::int32_t voltage) const; + + /** + * Stops the motor using the currently configured brake mode. + * + * This function sets motor velocity to zero, which will cause it to act + * according to the set brake mode. If brake mode is set to MOTOR_BRAKE_HOLD, + * this function may behave differently than calling move_absolute(0) + * or motor_move_relative(0). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * Motor motor(1); + * motor.move_voltage(12000); + * pros::delay(1000); // Move at max voltage for 1 second + * motor.brake(); + * } + * \endcode + */ + std::int32_t brake(void) const; + + /** + * Changes the output velocity for a profiled movement (motor_move_absolute or + * motor_move_relative). This will have no effect if the motor is not following + * a profiled movement. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param velocity + * The new motor velocity from +-100, +-200, or +-600 depending on the + * motor's gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); + * pros::delay(100); + * motor.modify_profiled_velocity(0); // Stop the motor early + * } + * \endcode + */ + std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + + /** + * Gets the target position set for the motor by the user + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); + * std::cout << "Motor Target: " << motor.get_target_position(); + * // Prints 100 + * } + * \endcode + */ + double get_target_position(const std::uint8_t index = 0) const; + + /** + * Gets the velocity commanded to the motor by the user at the index specified. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The commanded motor velocity from +-100, +-200, or +-600, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * std::cout << "Motor Velocity: " << motor.get_target_velocity(); + * // Prints the value of E_CONTROLLER_ANALOG_LEFT_Y + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_target_velocity(const std::uint8_t index = 0) const; + + ///@} + + /// \name Motor telemetry functions + /// These functions allow programmers to collect telemetry from motors + ///@{ + + /** + * Gets the actual velocity of the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * while (true) { + * motor = controller_get_analog(E_CONTROLLER_MASTER, E_CONTROLLER_ANALOG_LEFT_Y); + * printf("Actual velocity: %lf\n", motor.get_actual_velocity()); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_actual_velocity(const std::uint8_t index = 0) const; + + /** + * Gets the current drawn by the motor in mA. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Current Draw: " << motor.get_current_draw(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_current_draw(const std::uint8_t index = 0) const; + + /** + * Gets the direction of movement for the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Direction: " << motor.get_direction(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_direction(const std::uint8_t index = 0) const; + + /** + * Gets the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Efficiency: " << motor.get_efficiency(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_efficiency(const std::uint8_t index = 0) const; + + /** + * Gets the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * + * \return A bitfield containing the motor's faults. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << motor.get_faults();pros::delay(2); + * } + * } + * \endcode + */ + std::uint32_t get_faults(const std::uint8_t index = 0) const; + + /** + * Gets the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return A bitfield containing the motor's flags. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << motor.get_faults(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::uint32_t get_flags(const std::uint8_t index = 0) const; + + /** + * Gets the absolute position of the motor in its encoder units. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << motor.get_position(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_position(const std::uint8_t index = 0) const; + + /** + * Gets the power drawn by the motor in Watts. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Power: " << motor.get_power(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_power(const std::uint8_t index = 0) const; + + /** + * Gets the raw encoder count of the motor at a given timestamp. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * + * \param timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * + * + * \return The raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + * + * \b Example + * \code + * void opcontrol() { + * std::uint32_t now = pros::millis(); + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << motor.get_raw_position(&now); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_raw_position(std::uint32_t* const timestamp, const std::uint8_t index = 0) const; + + /** + * Gets the temperature of the motor in degrees Celsius. + + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Temperature: " << motor.get_temperature(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_temperature(const std::uint8_t index = 0) const; + + /** + * Gets the torque generated by the motor in Newton Meters (Nm). + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Torque: " << motor.get_torque(); + * pros::delay(2); + * } + * } + * \endcode + */ + double get_torque(const std::uint8_t index = 0) const; + + /** + * Gets the voltage delivered to the motor in millivolts. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Voltage: " << motor.get_voltage(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_voltage(const std::uint8_t index = 0) const; + + /** + * Checks if the motor is drawing over its current limit. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its current limit?: " << motor.is_over_current(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t is_over_current(const std::uint8_t index = 0) const; + + /** + * Gets the temperature limit flag for the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its temperature limit?: " << motor.is_over_temp(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t is_over_temp(const std::uint8_t index = 0) const; + + ///@} + + /// \name Motor configuration functions + /// These functions allow programmers to configure the behavior of motors + ///@{ + + /** + * Gets the brake mode that was set for the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return One of Motor_Brake, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + MotorBrake get_brake_mode(const std::uint8_t index = 0) const; + + /** + * Gets the current limit for the motor in mA. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * while (true) { + * std::cout << "Motor Current Limit: " << motor.get_current_limit(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t get_current_limit(const std::uint8_t index = 0) const; + + /** + * Gets the encoder units that were set for the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return One of Motor_Units according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Encoder Units: " << motor.get_encoder_units(); + * } + * \endcode + */ + MotorUnits get_encoder_units(const std::uint8_t index = 0) const; + + /** + * Gets the gearset that was set for the motor. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return One of Motor_Gears according to what is set for the motor, + * or pros::Motor_Gears::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Gearing: " << motor.get_gearing(); + * } + * \endcode + */ + MotorGears get_gearing(const std::uint8_t index = 0) const; + + /** + * Gets the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * std::cout << "Motor Voltage Limit: " << motor.get_voltage_limit(); + * } + * \endcode + */ + std::int32_t get_voltage_limit(const std::uint8_t index = 0) const; + + /** + * Gets whether the motor is reversed or not + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * std::cout << "Is the motor reversed? " << motor.is_reversed(); + * // Prints "0" + * } + * \endcode + */ + std::int32_t is_reversed(const std::uint8_t index = 0) const; + + /** + * Sets one of Motor_Brake to the motor. + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * + * \param mode + * The Motor_Brake to set for the motor + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode(const MotorBrake mode, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Brake to the motor. + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * + * \param mode + * The Motor_Brake to set for the motor + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode(const pros::motor_brake_mode_e_t mode, const std::uint8_t index = 0) const; + + /** + * Sets the current limit for the motor in mA. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * * \param limit + * The new current limit in mA + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * motor.set_current_limit(1000); + * while (true) { + * motor = controller_get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will reduce its output at 1000 mA instead of the default 2500 mA + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_current_limit(const std::int32_t limit, const std::uint8_t index = 0) const; + + /** + * Sets one of Motor_Units for the motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_encoder_units(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << motor.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units(const MotorUnits units, const std::uint8_t index = 0) const; + /** + * Sets one of Motor_Units for the motor encoder. Works with the C + * enum and the C++ enum class. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_encoder_units(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << motor.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units(const pros::motor_encoder_units_e_t units, const std::uint8_t index = 0) const; + + /** + * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with + * the C++ enum class and the C enum. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_gearing(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << motor.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(const MotorGears gearset, const std::uint8_t index = 0) const; + + /** + * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with + * the C++ enum class and the C enum. + + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param gearset + * The new motor gearset + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_gearing(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << motor.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing(const pros::motor_gearset_e_t gearset, const std::uint8_t index = 0) const; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * EOVERFLOW - The index is non 0 + * + * \param reverse + * True reverses the motor, false is default direction + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_reversed(true); + * std::cout << "Is this motor reversed? " << motor.is_reversed(); + * } + * \endcode + */ + std::int32_t set_reversed(const bool reverse, const std::uint8_t index = 0); + + /** + * Sets the voltage limit for the motor in Volts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * motor.set_voltage_limit(10000); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will not output more than 10 V + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_voltage_limit(const std::int32_t limit, const std::uint8_t index = 0) const; + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param position + * The new reference position in its encoder units + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); // Moves 100 units forward + * motor.move_absolute(100, 100); // This does not cause a movement + * + * motor.set_zero_position(80); + * motor.move_absolute(100, 100); // Moves 80 units forward + * } + * \endcode + * + */ + std::int32_t set_zero_position(const double position, const std::uint8_t index = 0) const; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); // Moves 100 units forward + * motor.move_absolute(100, 100); // This does not cause a movement + * + * motor.tare_position(); + * motor.move_absolute(100, 100); // Moves 100 units forward + * } + * \endcode + */ + std::int32_t tare_position(const std::uint8_t index = 0) const; + + /** + * Gets the number of motors. + * + * \return Always returns 1 + * + */ + std::int8_t size(void) const; + + /** + * gets the port number of the motor + * + * \return The signed port of the motor. (negative if the motor is reversed) + * + */ + std::int8_t get_port(const std::uint8_t index = 0) const; + + ///@} + + /// \name Additional motor functions + /// These functions allow for motors and motor groups to be used interchangeably + ///@{ + /** + * Gets a vector containing the target position set for the motor by the user + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing the target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); + * std::cout << "Motor Target: " << motor.get_target_position_all()[0]; + * // Prints 100 + * } + * \endcode + */ + std::vector get_target_position_all(void) const; + + /** + * Gets a vector containing the velocity commanded to the motor by the user + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the commanded motor velocity from +-100, + * +-200, or +-600, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * std::cout << "Motor Velocity: " << motor.get_target_velocity_all()[0]; + * // Prints the value of E_CONTROLLER_ANALOG_LEFT_Y + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_target_velocity_all(void) const; + + /** + * Gets a vector containing the actual velocity commanded of the motor + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's actual velocity in RPM or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor.move_velocity(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); + * std::cout << "Motor Velocity: " << motor.get_actual_velocity_all()[0]; + * // Prints the value of E_CONTROLLER_ANALOG_LEFT_Y + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_actual_velocity_all(void) const; + + /** + * Gets a vector containing the current drawn by the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing the motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Current Draw: " << motor.get_current_draw_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_current_draw_all(void) const; + + /** + * Gets a vector containing the direction of movement for the motor. + * + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing 1 for moving in the positive direction, -1 for moving in the + * negative direction, and PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Direction: " << motor.get_direction_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_direction_all(void) const; + + /** + * Gets a vector containing the efficiency of the motor in percent. + * + * An efficiency of 100% means that the motor is moving electrically while + * drawing no electrical power, and an efficiency of 0% means that the motor + * is drawing power but not moving. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector containing The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Efficiency: " << motor.get_efficiency(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_efficiency_all(void) const; + + /** + * Gets a vector of the faults experienced by the motor. + * + * Compare this bitfield to the bitmasks in pros::motor_fault_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \return A bitfield containing the motor's faults. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << motor.get_faults_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_faults_all(void) const; + + /** + * Gets a vector of the flags set by the motor's operation. + * + * Compare this bitfield to the bitmasks in pros::motor_flag_e_t. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * + * \return A bitfield containing the motor's flags. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Faults: " << motor.get_faults_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_flags_all(void) const; + + /** + * Gets a vector containing the absolute position of the motor in its encoder units. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + + * + * \return A vector containing the motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << motor.get_position_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_position_all(void) const; + + /** + * Gets a vector containing the power drawn by the motor in Watts. + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Power: " << motor.get_power_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_power_all(void) const; + + /** + * Gets a vector of the raw encoder count of the motor at a given timestamp. + * + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * \param timestamp + * A pointer to a time in milliseconds for which the encoder count + * will be returned. If NULL, the timestamp at which the encoder + * count was read will not be supplied + * + * \return A vector containing the raw encoder count at the given timestamp or PROS_ERR if the + * operation failed. + * + * \b Example + * \code + * void opcontrol() { + * std::uint32_t now = pros::millis(); + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Position: " << motor.get_raw_position(&now); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_raw_position_all(std::uint32_t* const timestamp) const; + + /** + * Gets a vector of the temperature of the motor in degrees Celsius. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector contaioning the motor's temperature in degrees Celsius + * or PROS_ERR_F if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Temperature: " << motor.get_temperature_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_temperature_all(void) const; + + /** + * Gets a vector of the torque generated by the motor in Newton Meters (Nm). + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Torque: " << motor.get_torque(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_torque_all(void) const; + + /** + * Gets a vector of the voltage delivered to the motor in millivolts. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * + * \return A vector of the motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Motor Voltage: " << motor.get_voltage_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_voltage_all(void) const; + + /** + * Checks if the motor is drawing over its current limit. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing 1 if the motor's current limit is being exceeded and 0 if the + * current limit is not exceeded, or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its current limit?: " << motor.is_over_current_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector is_over_current_all(void) const; + + /** + * Gets the temperature limit flag for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing 1 if the temperature limit is exceeded and 0 if the temperature is + * below the limit, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * std::cout << "Is the motor over its temperature limit?: " << motor.is_over_temp_all(); + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector is_over_temp_all(void) const; + + /** + * Gets a vector containing the brake mode that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return One of Motor_Brake, according to what was set for the + * motor, or E_MOTOR_BRAKE_INVALID if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + std::vector get_brake_mode_all(void) const; + + /** + * Gets a vector containing the current limit for the motor in mA. + * + * The default value is 2500 mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * while (true) { + * std::cout << "Motor Current Limit: " << motor.get_current_limit_all()[0]; + * pros::delay(2); + * } + * } + * \endcode + */ + std::vector get_current_limit_all(void) const; + + /** + * Gets a vector containing the encoder units that were set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing One of Motor_Units according to what is set for the + * motor or E_MOTOR_ENCODER_INVALID if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Encoder Units: " << motor.get_encoder_units_all()[0]; + * } + * \endcode + */ + std::vector get_encoder_units_all(void) const; + + /** + * Gets a vector containing the gearset that was set for the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing one of Motor_Gears according to what is set for the motor, + * or pros::Motor_Gears::invalid if the operation failed. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1, E_MOTOR_GEARSET_06, E_MOTOR_ENCODER_COUNTS); + * std::cout << "Motor Gearing: " << motor.get_gearing_all()[0]; + * } + * \endcode + */ + std::vector get_gearing_all(void) const; + + /** + * Gets returns a vector with all the port numbers in the motor group. + * + * \return A vector containing the signed port of the motor. (negative if the motor is reversed) + */ + std::vector get_port_all(void) const; + + /** + * Gets a vector of the voltage limit set by the user. + * + * Default value is 0V, which means that there is no software limitation + * imposed on the voltage. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return A vector containing the motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * std::cout << "Motor Voltage Limit: " << motor.get_voltage_limit_all()[0]; + * } + * \endcode + */ + std::vector get_voltage_limit_all(void) const; + + /** + * Gets a vector containg whether the motor is reversed or not + * + * \return A vector containing 1 if the motor has been reversed and 0 if the motor was not + * reversed, or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * std::cout << "Is the motor reversed? " << motor.is_reversed_all()[0]; + * // Prints "0" + * } + * \endcode + */ + std::vector is_reversed_all(void) const; + + /** + * Sets one of Motor_Brake to the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param mode + * The Motor_Brake to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode_all(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode_all(const MotorBrake mode) const; + + /** + * Sets one of Motor_Brake to the motor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param mode + * The Motor_Brake to set for the motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_brake_mode_all(pros::E_MOTOR_BRAKE_HOLD); + * std::cout << "Brake Mode: " << motor.get_brake_mode(); + * } + * \endcode + */ + std::int32_t set_brake_mode_all(const pros::motor_brake_mode_e_t mode) const; + + /** + * Sets the current limit for the motor in mA. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * motor.set_current_limit_all(1000); + * while (true) { + * motor = controller_get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will reduce its output at 1000 mA instead of the default 2500 mA + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_current_limit_all(const std::int32_t limit) const; + + /** + * Sets one of Motor_Units for the motor encoder. Works with the C + * enum and the C++ enum class. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * * \param units + * The new motor encoder units + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_encoder_units_all(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << motor.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units_all(const MotorUnits units) const; + + /** + * Sets one of Motor_Units for the motor encoder. Works with the C + * enum and the C++ enum class. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_encoder_units_all(E_MOTOR_ENCODER_DEGREES); + * std::cout << "Encoder Units: " << motor.get_encoder_units(); + * } + * \endcode + */ + std::int32_t set_encoder_units_all(const pros::motor_encoder_units_e_t units) const; + + + /** + * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_gearing_all(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << motor.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing_all(const MotorGears gearset) const; + + /** + * Sets one of the gear cartridge (red, green, blue) for the motor. Usable with + * the C++ enum class and the C enum. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_gearing_all(E_MOTOR_GEARSET_06); + * std::cout << "Gearset: " << motor.get_gearing(); + * } + * \endcode + */ + std::int32_t set_gearing_all(const pros::motor_gearset_e_t gearset) const; + + /** + * Sets the reverse flag for the motor. + * + * This will invert its movements and the values returned for its position. + * + * + * \param reverse + * True reverses the motor, false is default direction + * + * \return 1 + * + * \b Example + * \code + * void initialize() { + * pros::Motor motor (1); + * motor.set_reversed_all(true); + * std::cout << "Is this motor reversed? " << motor.is_reversed(); + * } + * \endcode + */ + std::int32_t set_reversed_all(const bool reverse); + + /** + * Sets the voltage limit for the motor in Volts. + * + * \note This is one of many Motor functions that takes in an optional index parameter. + * This parameter can be ignored by most users but exists to give a shared base class + * for motors and motor groups + * + * This function uses the following values of errno when an error state is + * reached: + * + * ENODEV - The port cannot be configured as a motor + * + * EOVERFLOW - The index is non 0 + * + * \param limit + * The new voltage limit in Volts + * + * \param index Optional parameter. + * The zero-indexed index of the motor to get the target position of. + * By default index is 0, and will return an error for a non-zero index + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * pros::Controller master (E_CONTROLLER_MASTER); + * + * motor.set_voltage_limit_all(10000); + * while (true) { + * motor = master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y); + * // The motor will not output more than 10 V + * pros::delay(2); + * } + * } + * \endcode + */ + std::int32_t set_voltage_limit_all(const std::int32_t limit) const; + + /** + * Sets the position for the motor in its encoder units. + * + * This will be the future reference point for the motor's "absolute" + * position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param position + * The new reference position in its encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); // Moves 100 units forward + * motor.move_absolute(100, 100); // This does not cause a movement + * + * motor.set_zero_position_all(80); + * motor.move_absolute(100, 100); // Moves 80 units forward + * } + * \endcode + * + */ + std::int32_t set_zero_position_all(const double position) const; + + /** + * Sets the "absolute" zero position of the motor to its current position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void autonomous() { + * pros::Motor motor (1); + * motor.move_absolute(100, 100); // Moves 100 units forward + * motor.move_absolute(100, 100); // This does not cause a movement + * + * motor.tare_position_all(); + * motor.move_absolute(100, 100); // Moves 100 units forward + * } + * \endcode + */ + std::int32_t tare_position_all(void) const; + + ///@} + + private: + std::int8_t _port; +}; +namespace literals { +const pros::Motor operator"" _mtr(const unsigned long long int m); +const pros::Motor operator"" _rmtr(const unsigned long long int m); +} // namespace literals +} // namespace v5 +} // namespace pros +#endif // _PROS_MOTORS_HPP_ diff --git a/include/pros/optical.h b/include/pros/optical.h new file mode 100644 index 0000000..049c395 --- /dev/null +++ b/include/pros/optical.h @@ -0,0 +1,473 @@ +/** + * \file pros/optical.h + * \ingroup c-optical + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-optical VEX Optical Sensor C API + */ + +#ifndef _PROS_OPTICAL_H_ +#define _PROS_OPTICAL_H_ + +#include +#include +#include "error.h" + +#define OPT_GESTURE_ERR (INT8_MAX) +#define OPT_COUNT_ERR (INT16_MAX) +#define OPT_TIME_ERR PROS_ERR + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \ingroup c-optical + */ + +/** + * \addtogroup c-optical + * @{ + */ + +/** + * \enum optical_direction_e_t + */ +typedef enum optical_direction_e { NO_GESTURE = 0, + /// The direction indicating an upward gesture. + UP = 1, + /// The direction indicating a downward gesture. + DOWN = 2, + /// The direction indicating a rightward gesture. + RIGHT = 3, + /// The direction indicating a leftward gesture. + LEFT = 4, + ERROR = PROS_ERR +} optical_direction_e_t; + +/** + * \struct optical_rgb_s_t + * The RGB and Brightness values for the optical sensor. + */ +typedef struct optical_rgb_s { + double red; + double green; + double blue; + double brightness; +} optical_rgb_s_t; + +/** + * \struct optical_raw_s_t + * The RGB and clear values for the optical sensor. + */ +typedef struct optical_raw_s { + uint32_t clear; + uint32_t red; + uint32_t green; + uint32_t blue; +} optical_raw_s_t; + +/** + * \struct optical_gesture_s_t + * This structure contains the raw gesture data. + */ +typedef struct optical_gesture_s { + uint8_t udata; ///Up data + uint8_t ddata; ///Down data + uint8_t ldata; ///Left data + uint8_t rdata; ///Right data + uint8_t type; ///Type of gesture + uint8_t pad; ///Padding + uint16_t count; ///Number of gestures + uint32_t time; ///Time since gesture recognized +} optical_gesture_s_t; + +/** + * \name Functions + * @{ + */ + +/** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Hue value: %lf \n", optical_get_hue(OPTICAL_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double optical_get_hue(uint8_t port); + +/** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Saturation value: %lf \n", optical_get_saturation(OPTICAL_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double optical_get_saturation(uint8_t port); + +/** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Brightness value: %lf \n", optical_get_brightness(OPTICAL_PORT)); + * delay(20); + * } + * } + * \endcode + */ +double optical_get_brightness(uint8_t port); + +/** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Proximity value: %d \n", optical_get_proximity(OPTICAL_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t optical_get_proximity(uint8_t port); + +/** + * Set the pwm value of the White LED + * + * value that ranges from 0 to 100 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * optical_set_led_pwm(OPTICAL_PORT, 50); + * delay(20); + * } + * } + * \endcode + */ +int32_t optical_set_led_pwm(uint8_t port, uint8_t value); + +/** + * Get the pwm value of the White LED + * + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return LED pwm value that ranges from 0 to 100 if the operation was + * successful or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("PWM Value: %d \n", optical_get_led_pwm(OPTICAL_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t optical_get_led_pwm(uint8_t port); + +/** + * Get the processed RGBC data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return rgb value if the operation was successful or an optical_rgb_s_t with + * all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * optical_rgb_s_t RGB_values; + * void opcontrol() { + * while (true) { + * RGB_values = optical_get_rgb(OPTICAL_PORT); + * printf("Red value: %lf \n", RGB_values.red); + * printf("Green value: %lf \n", RGB_values.green); + * printf("Blue value: %lf \n", RGB_values.blue); + * printf("Brightness value: %lf \n", RGB_values.brightness); + * delay(20); + * } + * } + * \endcode + */ +optical_rgb_s_t optical_get_rgb(uint8_t port); + +/** + * Get the raw, unprocessed RGBC data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return raw rgb value if the operation was successful or an optical_raw_s_t + * with all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * optical_raw_s_t raw_values; + * void opcontrol() { + * while (true) { + * raw_values = optical_get_raw(OPTICAL_PORT); + * printf("Red value: %ld \n", raw_values.red); + * printf("Green value: %ld \n", raw_values.green); + * printf("Blue value: %ld \n", raw_values.blue); + * printf("Clear value: %ld \n", raw_values.clear); + * delay(20); + * } + * } + * \endcode + */ +optical_raw_s_t optical_get_raw(uint8_t port); + +/** + * Get the most recent gesture data from the sensor + * + * Gestures will be cleared after 500mS + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * optical_direction_e_t gesture; + * void opcontrol() { + * while (true) { + * gesture = optical_get_gesture(OPTICAL_PORT); + * printf("Gesture value: %d \n", gesture); + * delay(20); + * } + * } + * \endcode + */ +optical_direction_e_t optical_get_gesture(uint8_t port); + +/** + * Get the most recent raw gesture data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return gesture value if the operation was successful or an optical_gesture_s_t + * with all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * optical_gesture_s_t raw_gesture; + * void opcontrol() { + * while (true) { + * raw_gesture = optical_get_gesture_raw(OPTICAL_PORT); + * printf("Up data: %u \n", raw_gesture.udata); + * printf("Down data: %u \n", raw_gesture.ddata); + * printf("Left data: %u \n", raw_gesture.ldata); + * printf("Right data: %u \n", raw_gesture.rdata); + * printf("Type: %u \n", raw_gesture.type); + * printf("Count: %u \n", raw_gesture.count); + * printf("Time: %lu \n", raw_gesture.time); + * delay(20); + * } + * } + * \endcode + */ +optical_gesture_s_t optical_get_gesture_raw(uint8_t port); + +/** + * Enable gesture detection on the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * optical_enable_gesture(OPTICAL_PORT); + * delay(20); + * } + * } + * \endcode + */ +int32_t optical_enable_gesture(uint8_t port); + +/** + * Disable gesture detection on the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 Optical Sensor port number from 1-21 + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example + * \code + * #define OPTICAL_PORT 1 + * + * void opcontrol() { + * while (true) { + * optical_disable_gesture(OPTICAL_PORT); + * delay(20); + * } + * } + * \endcode + */ +int32_t optical_disable_gesture(uint8_t port); + +///@} + +///@} + +#ifdef __cplusplus +} +} +} +#endif + +#endif diff --git a/include/pros/optical.hpp b/include/pros/optical.hpp new file mode 100644 index 0000000..3f700d4 --- /dev/null +++ b/include/pros/optical.hpp @@ -0,0 +1,391 @@ +/** + * \file pros/optical.hpp + * \ingroup cpp-optical + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-optical VEX Optical Sensor C++ API + */ + +#ifndef _PROS_OPTICAL_HPP_ +#define _PROS_OPTICAL_HPP_ + +#include + +#include +#include + +#include "pros/optical.h" +#include "pros/device.hpp" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-optical + */ +class Optical : public Device { + /** + * \addtogroup cpp-optical + * @{ + */ + public: + /** + * Creates an Optical Sensor object for the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \param port + * The V5 port number from 1-21 + * + * \b Example: + * \code{.cpp} + * pros::Optical optical(1); + * \endcode + */ + explicit Optical(const std::uint8_t port); + + /** + * Get the detected color hue + * + * This is not available if gestures are being detected. Hue has a + * range of 0 to 359.999 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return hue value if the operation was successful or PROS_ERR_F if the operation + * failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * std::cout << "Hue: " << optical.get_hue() << std::endl; + * } + * \endcode + */ + virtual double get_hue(); + + /** + * Get the detected color saturation + * + * This is not available if gestures are being detected. Saturation has a + * range of 0 to 1.0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return saturation value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * std::cout << "Saturation: " << optical.get_saturation() << std::endl; + * } + * \endcode + */ + virtual double get_saturation(); + + /** + * Get the detected color brightness + * + * This is not available if gestures are being detected. Brightness has a + * range of 0 to 1.0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return brightness value if the operation was successful or PROS_ERR_F if + * the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * std::cout << "Brightness: " << optical.get_brightness() << std::endl; + * } + */ + virtual double get_brightness(); + + /** + * Get the detected proximity value + * + * This is not available if gestures are being detected. proximity has + * a range of 0 to 255. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return Proximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * std::cout << "Proximity: " << optical.get_proximity() << std::endl; + * } + * \endcode + */ + virtual std::int32_t get_proximity(); + + /** + * Set the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return The Error code encountered or PROS_SUCCESS. + * + * \b Example: + * \code{.cpp} + * void initialize() { + * pros::Optical optical(1); + * optical.set_led_pwm(100); + * } + * \endcode + */ + virtual std::int32_t set_led_pwm(uint8_t value); + + /** + * Get the pwm value of the White LED on the sensor + * + * value that ranges from 0 to 100 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return LED pwm value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * optical.set_led_pwm(100); + * std::cout << "LED PWM: " << optical.get_led_pwm() << std::endl; + * } + * \endcode + */ + virtual std::int32_t get_led_pwm(); + + /** + * Get the processed RGBC data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return rgb value if the operation was successful or an optical_rgb_s_t + * with all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * pros::c::optical_rgb_s_t rgb = optical.get_rgb(); + * while(1) { + * std::cout << "Red: " << rgb.red << std::endl; + * std::cout << "Green: " << rgb.green << std::endl; + * std::cout << "Blue: " << rgb.blue << std::endl; + * std::cout << "Brightness: " << rgb.brightness << std::endl; + * pros::delay(20); + * } + * } + * \endcode + */ + virtual pros::c::optical_rgb_s_t get_rgb(); + + /** + * Get the raw un-processed RGBC data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return raw rgb value if the operation was successful or an optical_raw_s_t + * with all fields set to PROS_ERR if the operation failed, setting errno. + */ + virtual pros::c::optical_raw_s_t get_raw(); + + /** + * Get the most recent gesture data from the sensor + * + * Gestures will be cleared after 500mS + * 0 = no gesture + * 1 = up (towards cable) + * 2 = down + * 3 = right + * 4 = left + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return gesture value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * while(1) { + * std::cout << "Gesture: " << optical.get_gesture() << std::endl; + * pros::delay(20); + * } + * } + * \endcode + */ + virtual pros::c::optical_direction_e_t get_gesture(); + + /** + * Get the most recent raw gesture data from the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return gesture value if the operation was successful or an optical_gesture_s_t + * with all fields set to PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * optical.enable_gesture(); + * while(1) { + * pros::c::optical_gesture_s_t gesture = optical.get_gesture_raw(); + * std::cout << "Gesture raw data: " << std::endl; + * std::cout << "Up data: " << gesture.udata << std::endl; + * std::cout << "Down data: " << gesture.ddata << std::endl; + * std::cout << "Left data: " << gesture.ldata << std::endl; + * std::cout << "Right data: " << gesture.rdata << std::endl; + * std::cout << "Type: " << gesture.type << std::endl; + * std::cout << "Count: " << gesture.count << std::endl; + * std::cout << "Time: " << gesture.time << std::endl; + * pros::delay(20); + * } + * } + * \endcode + */ + virtual pros::c::optical_gesture_s_t get_gesture_raw(); + + /** + * Enable gesture detection on the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * optical.enable_gesture(); + * while(1) { + * pros::c::optical_gesture_s_t gesture = optical.get_gesture_raw(); + * std::cout << "Gesture raw data: " << std::endl; + * std::cout << "Up data: " << gesture.udata << std::endl; + * std::cout << "Down data: " << gesture.ddata << std::endl; + * std::cout << "Left data: " << gesture.ldata << std::endl; + * std::cout << "Right data: " << gesture.rdata << std::endl; + * std::cout << "Type: " << gesture.type << std::endl; + * std::cout << "Count: " << gesture.count << std::endl; + * std::cout << "Time: " << gesture.time << std::endl; + * pros::delay(20); + * } + * } + */ + virtual std::int32_t enable_gesture(); + + /** + * Disable gesture detection on the sensor + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Optical Sensor + * + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code{.cpp} + * void opcontrol() { + * pros::Optical optical(1); + * optical.enable_gesture(); + * while(1) { + * if(optical.get_gesture() != 0) { + * std::cout << "Gesture detected!"<< std::endl; + * optical.disable_gesture(); + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t disable_gesture(); + + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * Optical [port: (port number), hue: (hue), saturation: (saturation), + * brightness: (brightness), proximity: (proximity), rgb: {red, green, blue}] + * + * \b Example: + * \code{.cpp} + * pros::Optical optical(1); + * std::cout << optical << std::endl; + * \endcode + */ + friend std::ostream& operator<<(std::ostream& os, pros::Optical& optical); + + private: + ///@} +}; + +namespace literals { +const pros::Optical operator"" _opt(const unsigned long long int o); +} // namespace literals +} +} // namespace pros + +#endif diff --git a/include/pros/rotation.h b/include/pros/rotation.h new file mode 100644 index 0000000..1c1c731 --- /dev/null +++ b/include/pros/rotation.h @@ -0,0 +1,390 @@ +/** + * \file pros/rotation.h + * \ingroup c-rotation + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-rotation VEX Rotation Sensor C API + */ + +#ifndef _PROS_ROTATION_H_ +#define _PROS_ROTATION_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \ingroup c-rotation + */ + +/** + * \addtogroup c-rotation + * @{ + */ + +#define ROTATION_MINIMUM_DATA_RATE 5 + +/** + * Reset Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_reset(ROTATION_PORT); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_reset(uint8_t port); + +/** + * Set the Rotation Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void initialize() { + * pros::Rotation rotation_sensor(ROTATION_PORT); + * rotation_set_data_rate(ROTATION_PORT, 5); + * } + * \endcode + */ +int32_t rotation_set_data_rate(uint8_t port, uint32_t rate); + +/** + * Set the Rotation Sensor position reading to a desired rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_set_position(ROTATION_PORT, 600); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_set_position(uint8_t port, uint32_t position); + +/** + * Reset the Rotation Sensor position to 0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_reset_position(ROTATION_PORT); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_reset_position(uint8_t port); + +/** + * Get the Rotation Sensor's current position in centidegrees + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The position value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Position: %d centidegrees \n", rotation_get_position(ROTATION_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_get_position(uint8_t port); + +/** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The velocity value or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Velocity: %d centidegrees per second \n", rotation_get_velocity(ROTATION_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_get_velocity(uint8_t port); + +/** + * Get the Rotation Sensor's current angle in centidegrees (0-36000) + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The angle value (0-36000) or PROS_ERR_F if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Angle: %d centidegrees \n", rotation_get_angle(ROTATION_PORT)); + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_get_angle(uint8_t port); + +/** + * Set the Rotation Sensor's direction reversed flag + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param value + * Determines if the direction of the Rotation Sensor is reversed or not. + * + * \return 1 if operation succeeded or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * Rotation rotation_sensor(ROTATION_PORT); + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_set_reversed(ROTATION_PORT, true); // Reverses the Rotation Sensor on ROTATION_PORT + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_set_reversed(uint8_t port, bool value); + +/** + * Reverse the Rotation Sensor's direction + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * Rotation rotation_sensor(ROTATION_PORT); + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_reverse(ROTATION_PORT); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_reverse(uint8_t port); + +/** + * Initialize the Rotation Sensor with a reverse flag + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \param reverse_flag + * Determines if the Rotation Sensor is reversed or not. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * Rotation rotation_sensor(ROTATION_PORT); + * bool reverse_flag = true; + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_init_reverse(ROTATION_PORT, reverse_flag); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_init_reverse(uint8_t port, bool reverse_flag); + +/** + * Get the Rotation Sensor's reversed flag + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * + * \return Boolean value of if the Rotation Sensor's direction is reversed or not + * or PROS_ERR if the operation failed, setting errno. + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * Rotation rotation_sensor(ROTATION_PORT); + * while (true) { + * + * if(controller_get_digital(CONTROLLER_MASTER, E_CONTROLLER_DIGITAL_X)){ + * rotation_get_reversed(ROTATION_PORT); + * } + * delay(20); + * } + * } + * \endcode + */ +int32_t rotation_get_reversed(uint8_t port); + +///@} + +#ifdef __cplusplus +} //namespace C +} //namespace pros +} //extern "C" +#endif + +#endif diff --git a/include/pros/rotation.hpp b/include/pros/rotation.hpp new file mode 100644 index 0000000..25806c3 --- /dev/null +++ b/include/pros/rotation.hpp @@ -0,0 +1,364 @@ +/** + * \file pros/rotation.hpp + * \ingroup cpp-rotation + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-rotation VEX Rotation Sensor C++ API + */ +#ifndef _PROS_ROTATION_HPP_ +#define _PROS_ROTATION_HPP_ + +#include +#include + +#include "pros/rotation.h" +#include "pros/device.hpp" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-rotation + */ +class Rotation : public Device { + /** + * \addtogroup cpp-rotation + * @{ + */ + + public: + /** + * Constructs a new Rotation Sensor object + * + * ENXIO - The given value is not within the range of V5 ports |1-21|. + * ENODEV - The port cannot be configured as a Rotation Sensor + * + * \param port + * The V5 port number from 1 to 21, or from -21 to -1 for reversed Rotation Sensors. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); //Creates a Rotation Sensor on port 1 + * pros::Rotation reversed_rotation_sensor(-2); //Creates a reversed Rotation Sensor on port 2 + * } + * \endcode + */ + explicit Rotation(const std::int8_t port); + + /** + * Reset the Rotation Sensor + * + * Reset the current absolute position to be the same as the + * Rotation Sensor angle. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { + * rotation_sensor.reset(); + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t reset(); + + /** + * Set the Rotation Sensor's refresh interval in milliseconds. + * + * The rate may be specified in increments of 5ms, and will be rounded down to + * the nearest increment. The minimum allowable refresh rate is 5ms. The default + * rate is 10ms. + * + * As values are copied into the shared memory buffer only at 10ms intervals, + * setting this value to less than 10ms does not mean that you can poll the + * sensor's values any faster. However, it will guarantee that the data is as + * recent as possible. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param rate The data refresh interval in milliseconds + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Rotation rotation_sensor(1); + * rotation_sensor.set_data_rate(5); + * } + * \endcode + */ + virtual std::int32_t set_data_rate(std::uint32_t rate) const; + + /** + * Set the Rotation Sensor position reading to a desired rotation value + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { + * rotation_sensor.set_position(600); + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t set_position(std::uint32_t position) const; + + /** + * Reset the Rotation Sensor position to 0 + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param position + * The position in terms of ticks + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { + * rotation_sensor.reset_position(); + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t reset_position(void) const; + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \return The position value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * while (true) { + * printf("Position: %d Ticks \n", rotation_sensor.get_position()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_position() const; + + /** + * Get the Rotation Sensor's current velocity in centidegrees per second + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param port + * The V5 Rotation Sensor port number from 1-21 + * \return The velocity value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * while (true) { + * printf("Velocity: %d centidegrees per second \n", rotation_sensor.get_velocity)); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_velocity() const; + + /** + * Get the Rotation Sensor's current position in centidegrees + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \return The angle value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * while (true) { + * printf("Angle: %d centidegrees \n", rotation_sensor.get_angle()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_angle() const; + + /** + * Set the Rotation Sensor's direction reversed flag + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \param value + * Determines if the direction of the rotational sensor is + * reversed or not. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { + * rotation_sensor.set_reversed(true); // Reverses the Rotation Sensor + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t set_reversed(bool value) const; + + /** + * Reverse the Rotation Sensor's direction. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * pros::Controller master (E_CONTROLLER_MASTER); + * while (true) { + * if(master.get_analog(E_CONTROLLER_DIGITAL_X) { + * rotation_sensor.reverse(); + * } + * pros::delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t reverse() const; + + /** + * Get the Rotation Sensor's reversed flag + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as an Rotation Sensor + * + * \return Reversed value or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example + * \code + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * while (true) { + * printf("Reversed: %d \n", rotation_sensor.get_reversed()); + * delay(20); + * } + * } + * \endcode + */ + virtual std::int32_t get_reversed() const; + + /** + * This is the overload for the << operator for printing to streams + * + * Prints in format(this below is all in one line with no new line): + * Rotation [port: rotation._port, position: (rotation position), velocity: (rotation velocity), + * angle: (rotation angle), reversed: (reversed boolean)] + * + * \b Example + * \code + * #define ROTATION_PORT 1 + * + * void opcontrol() { + * pros::Rotation rotation_sensor(1); + * while(true) { + * std::cout << rotation_sensor << std::endl; + * pros::delay(20); + * } + * } + * \endcode + */ + friend std::ostream& operator<<(std::ostream& os, const pros::Rotation& rotation); + +///@} +}; + +namespace literals { +const pros::Rotation operator"" _rot(const unsigned long long int r); +} // namespace literals +} +} // namespace pros + +#endif diff --git a/include/pros/rtos.h b/include/pros/rtos.h new file mode 100644 index 0000000..d6b9be4 --- /dev/null +++ b/include/pros/rtos.h @@ -0,0 +1,1108 @@ +/** + * \file pros/rtos.h + * \ingroup c-rtos + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-rtos RTOS Facilities C API + * \note Additional example code for this module can be found in its [Tutorial.](@ref multitasking) + */ + +#ifndef _PROS_RTOS_H_ +#define _PROS_RTOS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/// \ingroup c-rtos + +/// \addtogroup c-rtos +/// @{ + +/// \name Macros +/// @{ + +/** + * The highest priority that can be assigned to a task. + * + * A task with this priority will always run if it is available to. Beware of + * deadlocks when using this priority. + */ +#define TASK_PRIORITY_MAX 16 + +/** + * The lowest priority that can be assigned to a task. + * + * This can cause severe performance problems and is generally not recommended + * that users use this priority. + */ +#define TASK_PRIORITY_MIN 1 + +/** + * The default task priority, which should be used for most tasks unless you + * have a specific need for a higher or lower priority task. + * + * The default tasks, such as autonomous(), are run with this priority + */ +#define TASK_PRIORITY_DEFAULT 8 + +/** + * The recommended stack size for a new task. + * + * This stack size is used for the default tasks such as autonomous(). This + * size is 8,192 words, or 32,768 bytes. This should be enough for the majority + * of tasks + */ +#define TASK_STACK_DEPTH_DEFAULT 0x2000 + +/** + * The minimal stack size for a task. + * + * This equates to 512 words, or 2,048 bytes. + */ +#define TASK_STACK_DEPTH_MIN 0x200 + +/** + * The maximum number of characters allowed in a task's name. + */ +#define TASK_NAME_MAX_LEN 32 + +/** + * The maximum timeout value that can be given to, for instance, a mutex grab. + */ +#define TIMEOUT_MAX ((uint32_t)0xffffffffUL) + +/// @} Name: Macros + +/// \name Typedefs +/// @{ + +/** + * An opaque type that pontis to a task handle. This is used for referencing a + * task. + */ +typedef void* task_t; + +/** + * A pointer to a task's function. + * + * Such a function is called when a task starts, and exiting said function will + * terminate the task. + */ +typedef void (*task_fn_t)(void*); + +/// @} Name: Typedefs + + +/// \name Enumerations +/// @{ + +/** + * The state of a task. + */ +typedef enum { + E_TASK_STATE_RUNNING = 0, /**< The task is actively executing. */ + E_TASK_STATE_READY, /**< The task exists and is available to run, but is not currently running. */ + E_TASK_STATE_BLOCKED, /**< The task is delayed or blocked by a mutex, semaphore, or I/O operation. */ + E_TASK_STATE_SUSPENDED, /**< The task is supended using task_suspend. */ + E_TASK_STATE_DELETED, /**< The task has been deleted using task_delete. */ + E_TASK_STATE_INVALID /**< The task handle does not point to a current or past task.*/ +} task_state_e_t; + +/** + * brief The action to take when a task is notified. + */ +typedef enum { + E_NOTIFY_ACTION_NONE, /**< The task’s notification value will not be touched.*/ + E_NOTIFY_ACTION_BITS, /**< The task’s notification value will be bitwise ORed with the new value.*/ + E_NOTIFY_ACTION_INCR, /**< The task’s notification value will be incremented by one, effectively using it as a notification counter.*/ + E_NOTIFY_ACTION_OWRITE, /**< The task’s notification value will be unconditionally set to the new value.*/ + E_NOTIFY_ACTION_NO_OWRITE /**< The task’s notification value will be set to the new value if the task does not already have a pending notification.*/ +} notify_action_e_t; + +/// @} Name: Enumerations + +/// \name Simple enum names +/// @{ + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define TASK_STATE_RUNNING pros::E_TASK_STATE_RUNNING +#define TASK_STATE_READY pros::E_TASK_STATE_READY +#define TASK_STATE_BLOCKED pros::E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED pros::E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED pros::E_TASK_STATE_DELETED +#define TASK_STATE_INVALID pros::E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE pros::E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS pros::E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR pros::E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE pros::E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE pros::E_NOTIFY_ACTION_NO_OWRITE +#else +#define TASK_STATE_RUNNING E_TASK_STATE_RUNNING +#define TASK_STATE_READY E_TASK_STATE_READY +#define TASK_STATE_BLOCKED E_TASK_STATE_BLOCKED +#define TASK_STATE_SUSPENDED E_TASK_STATE_SUSPENDED +#define TASK_STATE_DELETED E_TASK_STATE_DELETED +#define TASK_STATE_INVALID E_TASK_STATE_INVALID +#define NOTIFY_ACTION_NONE E_NOTIFY_ACTION_NONE +#define NOTIFY_ACTION_BITS E_NOTIFY_ACTION_BITS +#define NOTIFY_ACTION_INCR E_NOTIFY_ACTION_INCR +#define NOTIFY_ACTION_OWRITE E_NOTIFY_ACTION_OWRITE +#define NOTIFY_ACTION_NO_OWRITE E_NOTIFY_ACTION_NO_OWRITE +#endif +#endif + +/// @} Name: Simple enum names + +/// \name Typedefs + +/** + * A [mutex.](@ref multitasking) + * + * A mutex is a synchronization object that can be used to protect a shared + * resource from being accessed by multiple tasks at the same time. A mutex can + * be claimed by a task, which will prevent other tasks from claiming it until + * that task releases it. + */ +typedef void* mutex_t; + +/// @} Name: Typedefs + +/** + * The task handle of the currently running task. + */ +#ifdef __cplusplus +#define CURRENT_TASK ((pros::task_t)NULL) +#else +#define CURRENT_TASK ((task_t)NULL) +#endif + +/// @} (add to group: c-rtos) + +#ifdef __cplusplus +namespace c { +#endif + +/// \ingroup c-rtos +/// \addtogroup c-rtos +/// @{ + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + * + * \b Example + * \code + * void opcontrol() { + * uint32_t now = millis(); + * while (true) { + * // Do opcontrol things + * task_delay_until(&now, 2); + * } + * } + * \endcode + */ +uint32_t millis(void); + +/** + * Gets the number of microseconds since PROS initialized, + * + * \return The number of microseconds since PROS initialized + * + * \b Example + * \code + * void opcontrol() { + * uint64_t now = micros(); + * while (true) { + * // Do opcontrol things + * task_delay_until(&now, 2000); + * } + * } + * \endcode + */ +uint64_t micros(void); + +/** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task being + * created. This memory should not typically come from stack, but rather + * from dynamically (i.e., malloc'd) or statically allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \return A handle by which the newly created task can be referenced. If an + * error occurred, NULL will be returned and errno can be checked for hints as + * to why task_create failed. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * \endcode + */ +task_t task_create(task_fn_t function, void* const parameters, uint32_t prio, const uint16_t stack_depth, + const char* const name); + +/** + * Removes a task from the RTOS real time kernel's management. The task being + * deleted will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + * + * \param task + * The handle of the task to be deleted. Passing NULL will cause the + * calling task to be deleted. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * // Do other things + * task_delete(my_task); + * } + * \endcode + */ +void task_delete(task_t task); + +/** + * Delays the current task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * // Do opcontrol things + * task_delay(2); + * } + * } + * \endcode + */ +void task_delay(const uint32_t milliseconds); + +/** + * Delays the current task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * // Do opcontrol things + * delay(2); + * } + * } + * \endcode + */ +void delay(const uint32_t milliseconds); + +/** + * Delays the current task until a specified time. This function can be used + * by periodic tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time will + * be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value of millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + * + * \b Example + * \code + * void opcontrol() { + * uint32_t now = millis(); + * while (true) { + * // Do opcontrol things + * task_delay_until(&now, 2); + * } + * } + * \endcode + */ +void task_delay_until(uint32_t* const prev_time, const uint32_t delta); + +/** + * Gets the priority of the specified task. + * + * \param task + * The task to check + * + * \return The priority of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * printf("Task Priority: %d\n", task_get_priority(my_task)); + * } + * \endcode + */ +uint32_t task_get_priority(task_t task); + +/** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not blocked) + * and new priority is higher than the currently running task, a context switch + * may occur. + * + * \param task + * The task to set + * \param prio + * The new priority of the task + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * // Do things + * } + * + * void opcontrol() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "Example Task"); + * task_set_priority(my_task, TASK_PRIORITY_DEFAULT + 1); + * } + * \endcode + */ +void task_set_priority(task_t task, uint32_t prio); + +/** + * Gets the state of the specified task. + * + * \param task + * The task to check + * + * \return The state of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * printf("Task's State: %d\n", task_get_state(my_task)); + * } + * \endcode + */ +task_state_e_t task_get_state(task_t task); + +/** + * Suspends the specified task, making it ineligible to be scheduled. + * + * \param task + * The task to suspend + * + * \b Example + * \code + * mutex_t counter_mutex; + * int counter = 0; + * + * void my_task_fn(void* param) { + * while(true) { + * mutex_take(counter_mutex, TIMEOUT_MAX);// Mutexes are used for protecting shared resources + * counter++; + * mutex_give(counter_mutex); + * pros::delay(10); + * } + * } + * + * void opcontrol() { + * task_t task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT,; + * + * while(true) { + * mutex_take(counter_mutex, TIMEOUT_MAX); + * if(counter > 100) { + * task_suspepend(task); + * } + * mutex_give(counter_mutex); + * pros::delay(10); + * } + * } + * \endcode + */ +void task_suspend(task_t task); + +/** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while(true) { + * // Do stuff + * delay(10); + * } + * } + * + * task_t task; + * + * void initialize() { + * task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * + * void autonomous() { + * task_resume(task); + * + * // Run autonomous , then suspend the task so it doesn't interfere run + * + * // outside of autonomous or opcontrol + * task_suspend(task); + * } + * + * void opcontrol() { + * task_resume(task); + * // Opctonrol code here + * task_suspend(task); + * } + * + * \endcode + */ +void task_resume(task_t task); + +/** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not yet + * reaped by the idle task will also be included in the count. Tasks recently + * created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * printf("Number of Running Tasks: %d\n", task_get_count()); + * } + * \endcode + */ +uint32_t task_get_count(void); + +/** + * Gets the name of the specified task. + * + * \param task + * The task to check + * + * \return A pointer to the name of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * printf("Task Name: %d\n", task_get_name(my_task)); + * } + * \endcode + */ +char* task_get_name(task_t task); + +/** + * Gets a task handle from the specified name + * + * The operation takes a relatively long time and should be used sparingly. + * + * \param name + * The name to query + * + * \return A task handle with a matching name, or NULL if none were found. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * // Do other things + * task_delete(task_get_by_name("My Task")); + * } + * \endcode + */ +task_t task_get_by_name(const char* name); + +/** + * Get the currently running task handle. This could be useful if a task + * wants to tell another task about itself. + * + * \return The currently running task handle. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * task_t this_task = task_get_current(); + * if (task_get_state(this_take) == E_TASK_STATE_RUNNING) { + * printf("This task is currently running\n"); + * } + * // ... + * } + * + * void initialize() { + * task_t my_task = task_create(my_task_fn, (void*)"PROS", TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * \endcode + */ +task_t task_get_current(); + +/** + * Sends a simple notification to task and increments the notification counter. + * + * \param task + * The task to notify + * + * \return Always returns true. + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * while(task_notify_take(true) == 0) { + * // Code while waiting + * } + * puts("I was unblocked!"); + * } + * + * void opcontrol() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "Notify me! Task"); + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task_notify(my_task); + * } + * } + * } + * \endcode + */ +uint32_t task_notify(task_t task); + +/** + * + * Utilizes task notifications to wait until specified task is complete and deleted, + * then continues to execute the program. Analogous to std::thread::join in C++. + * + * \param task + * The handle of the task to wait on. + * + * \return void + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * lcd_print(1, "%s running", task_get_name(NULL)); + * task_delay(1000); + * lcd_print(2, "End of %s", task_get_name(NULL)); + * } + * + * void opcontrol() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "Example Task"); + * lcd_set_text(0, "Running task."); + * task_join(my_task); + * lcd_set_text(3, "Task completed."); + * } + * \endcode + */ +void task_join(task_t task); + +/** + * Sends a notification to a task, optionally performing some action. Will also + * retrieve the value of the notification in the target task before modifying + * the notification value. + * + * \param task + * The task to notify + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while(true) { + * // Wait until we have been notified 20 times before running the code + * if(task_notify_take(false, TIMEOUT_MAX) == 20) { + * // ... Code to do stuff here ... + * + * // Reset the notification counter + * task_notify_take(true, TIMEOUT_MAX); + * } + * delay(10); + * } + * } + * + * void opcontrol() { + * task_t task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * + * int count = 0; + * + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task_notify_ext(task, 1, NOTIFY_ACTION_INCREMENT, &count); + * } + * + * delay(20); + * } + * } + * \endcode + */ +uint32_t task_notify_ext(task_t task, uint32_t value, notify_action_e_t action, uint32_t* prev_value); + +/** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * task_t current_task = task_get_current(); + * while(task_notify_take(current_task, true, TIMEOUT_MAX)) { + * puts("I was unblocked!"); + * } + * } + * + * void opcontrol() { + * task_t my_task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "Notify me! Task"); + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task_notify(my_task); + * } + * } + * } + * \endcode + */ +uint32_t task_notify_take(bool clear_on_exit, uint32_t timeout); + +/** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to clear + * + * \return False if there was not a notification waiting, true if there was + * + * \b Example + * \code + * void my_task_fn(void* param) { + * task_t task = task_get_current(); + * while(true) { + * printf("Waiting for notification...\n"); + * printf("Got a notification: %d\n", task_notify_take(task, false, TIMEOUT_MAX)); + * + * task_notify_clear(task); + * delay(10): + * } + * } + * + * void opcontrol() { + * task_t task = task_create(my_task_fn, NULL, TASK_PRIORITY_DEFAULT, + * TASK_STACK_DEPTH_DEFAULT, "My Task"); + * + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task_notify(task); + * } + * delay(10); + * } + * } + * \endcode + */ +bool task_notify_clear(task_t task); + +/** + * Creates a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return A handle to a newly created mutex. If an error occurred, NULL will be + * returned and errno can be checked for hints as to why mutex_create failed. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * mutex_t odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * mutex_take(odom_mutex, MAX_DELAY); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * mutex_give(odom_mutex); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * mutex_take(odom_mutex, MAX_DELAY); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * mutex_give(odom_mutex); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * mutex_take(odom_mutex, MAX_DELAY); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * mutex_give(odom_mutex); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = mutex_create(); + * + * task_create(odom_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Odometry Task"); + * task_create(chassis_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Chassis Task"); + * } + * \endcode + */ +mutex_t mutex_create(void); + +/** + * Takes and locks a mutex, waiting for up to a certain number of milliseconds + * before timing out. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param mutex + * Mutex to attempt to lock. + * \param timeout + * Time to wait before the mutex becomes available. A timeout of 0 can + * be used to poll the mutex. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the mutex was successfully taken, false otherwise. If false + * is returned, then errno is set with a hint about why the the mutex + * couldn't be taken. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * mutex_t odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * mutex_take(odom_mutex, MAX_DELAY); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * mutex_give(odom_mutex); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * mutex_take(odom_mutex, MAX_DELAY); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * mutex_give(odom_mutex); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * mutex_take(odom_mutex, MAX_DELAY); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * mutex_give(odom_mutex); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = mutex_create(); + * + * task_create(odom_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Odometry Task"); + * task_create(chassis_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Chassis Task"); + * } + * \endcode + */ +bool mutex_take(mutex_t mutex, uint32_t timeout); + +/** + * Unlocks a mutex. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param mutex + * Mutex to unlock. + * + * \return True if the mutex was successfully returned, false otherwise. If + * false is returned, then errno is set with a hint about why the mutex + * couldn't be returned. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * mutex_t odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * mutex_take(odom_mutex, MAX_DELAY); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * mutex_give(odom_mutex); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * mutex_take(odom_mutex, MAX_DELAY); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * mutex_give(odom_mutex); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * mutex_take(odom_mutex, MAX_DELAY); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * mutex_give(odom_mutex); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = mutex_create(); + * + * task_create(odom_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Odometry Task"); + * task_create(chassis_task, NULL, TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "Chassis Task"); + * } + * \endcode + */ +bool mutex_give(mutex_t mutex); + +/** + * Deletes a mutex + * + * \param mutex + * Mutex to unlock. + * + * \b Example + * \code + * mutex_t mutex = mutex_create(); + * // Acquire the mutex; other tasks using this command will wait until the mutex is released + * // timeout can specify the maximum time to wait, or MAX_DELAY to wait forever + * // If the timeout expires, "false" will be returned, otherwise "true" + * mutex_take(mutex, MAX_DELAY); + * // do some work + * // Release the mutex for other tasks + * mutex_give(mutex); + * // Delete the mutex + * mutex_delete(mutex); + * \endcode + */ +void mutex_delete(mutex_t mutex); + +/// @} Add to group: c-rtos + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_RTOS_H_ diff --git a/include/pros/rtos.hpp b/include/pros/rtos.hpp new file mode 100644 index 0000000..f02495c --- /dev/null +++ b/include/pros/rtos.hpp @@ -0,0 +1,1580 @@ +/** + * \file pros/rtos.hpp + * \ingroup cpp-rtos + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-rtos RTOS Facilities C++ API + * \note Additional example code for this module can be found in its [Tutorial.](@ref multitasking) + */ + +#ifndef _PROS_RTOS_HPP_ +#define _PROS_RTOS_HPP_ + +#include "pros/rtos.h" +#undef delay +#include +#include +#include +#include +#include +#include +#include + +namespace pros { +inline namespace rtos { +/** + * \ingroup cpp-rtos + */ +class Task { + /** + * \addtogroup cpp-rtos + * @{ + */ + public: + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, (void*)"PROS"); + * } + * \endcode + */ + Task(task_fn_t function, void* parameters = nullptr, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = ""); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Pointer to the task entry function + * \param parameters + * Pointer to memory that will be used as a parameter for the task + * being created. This memory should not typically come from stack, + * but rather from dynamically (i.e., malloc'd) or statically + * allocated memory. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, (void*)"PROS", "My Task"); + * } + * \endcode + */ + Task(task_fn_t function, void* parameters, const char* name); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficienct. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::c::task_t my_task = pros::Task::create(my_task_fn, (void*)"PROS"); + * } + * \endcode + */ + template + static task_t create(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") { + static_assert(std::is_invocable_r_v); + return pros::c::task_create( + [](void* parameters) { + std::unique_ptr> ptr{static_cast*>(parameters)}; + (*ptr)(); + }, + new std::function(std::forward(function)), prio, stack_depth, name); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task"); + * } + * \endcode + */ + template + static task_t create(F&& function, const char* name) { + return Task::create(std::forward(function), TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param prio + * The priority at which the task should run. + * TASK_PRIO_DEFAULT plus/minus 1 or 2 is typically used. + * \param stack_depth + * The number of words (i.e. 4 * stack_depth) available on the task's + * stack. TASK_STACK_DEPTH_DEFAULT is typically sufficient. + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * + * void initialize() { + * // Create a task function using lambdas + * auto task_fn = [](void* param) { + * printf("Hello %s\n", (char*)param); + * } + * + * pros::Task my_task(task_fn, (void*)"PROS", "My Task"); + * } + * \endcode + */ + template + explicit Task(F&& function, std::uint32_t prio = TASK_PRIORITY_DEFAULT, + std::uint16_t stack_depth = TASK_STACK_DEPTH_DEFAULT, const char* name = "") + : Task( + [](void* parameters) { + std::unique_ptr> ptr{static_cast*>(parameters)}; + (*ptr)(); + }, + new std::function(std::forward(function)), prio, stack_depth, name) { + static_assert(std::is_invocable_r_v); + } + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * This function uses the following values of errno when an error state is + * reached: + * ENOMEM - The stack cannot be used as the TCB was not created. + * + * \param function + * Callable object to use as entry function + * \param name + * A descriptive name for the task. This is mainly used to facilitate + * debugging. The name may be up to 32 characters long. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task( + * [](void* param) { + * printf("Inside the task!\n"); + * }, + * "My Task" + * ); + * } + * \endcode + */ + template + Task(F&& function, const char* name) + : Task(std::forward(function), TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, name) {} + + /** + * Create a C++ task object from a task handle + * + * \param task + * A task handle from task_create() for which to create a pros::Task + * object. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task"); + * + * pros::Task my_task_cpp(my_task); + * } + * \endcode + */ + explicit Task(task_t task); + + /** + * Get the currently running Task + * + * @return The currently running Task. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("The name of this task is \"%s\"\n", pros::Task::current().get_name() + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, pros::TASK_PRIORITY_DEFAULT, TASK_STACK_DEPTH_DEFAULT, "My Task"); + * } + * \endcode + */ + static Task current(); + + /** + * Creates a task object from the passed task handle. + * + * \param in + * A task handle from task_create() for which to create a pros::Task + * object. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("The name of this task is \"%s\"\n", pros::Task::current().get_name() + * } + * + * void initialize() { + * pros::c::task_t my_task = pros::Task::create(my_task_fn, "My Task"); + * + * pros::Task my_task_cpp = my_task; + * } + * \endcode + */ + Task& operator=(task_t in); + + /** + * Removes the Task from the RTOS real time kernel's management. This task + * will be removed from all ready, blocked, suspended and event lists. + * + * Memory dynamically allocated by the task is not automatically freed, and + * should be freed before the task is deleted. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * + * my_task.remove(); + * } + * \endcode + */ + void remove(); + + /** + * Gets the priority of the specified task. + * + * \return The priority of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * + * printf("Task Priority: %d\n", my_task.get_priority()); + * } + * \endcode + */ + std::uint32_t get_priority(); + + /** + * Sets the priority of the specified task. + * + * If the specified task's state is available to be scheduled (e.g. not + * blocked) and new priority is higher than the currently running task, + * a context switch may occur. + * + * \param prio + * The new priority of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * + * Task.set_priority(pros::DEFAULT_PRIORITY + 1); + * } + * \endcode + */ + void set_priority(std::uint32_t prio); + + /** + * Gets the state of the specified task. + * + * \return The state of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * + * printf("Task State: %d\n", my_task.get_state()); + * } + * \endcode + */ + std::uint32_t get_state(); + + /** + * Suspends the specified task, making it ineligible to be scheduled. + * + * \b Example + * \code + * pros::Mutex counter_mutex; + * int counter = 0; + * + * void my_task_fn(void* param) { + * while(true) { + * counter_mutex.take(); // Mutexes are used for protecting shared resources + * counter++; + * counter_mutex.give(); + * pros::delay(10); + * } + * } + * + * void opcontrol() { + * pros::Task task(my_task_fn, "My Task"); + * + * while(true) { + * counter_mutex.take(); + * if(counter > 100) { + * task_suspepend(task); + * } + * counter_mutex.give(); + * pros::delay(10); + * } + * } + * \endcode + */ + void suspend(); + + /** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while(true) { + * // Do stuff + * pros::delay(10); + * } + * } + * + * pros::Task task(my_task_fn); + * + * void autonomous() { + * task.resume(); + * + * // Run autonomous , then suspend the task so it doesn't interfere run + * // outside of autonomous or opcontrol + * task.suspend(); + * } + * + * void opcontrol() { + * task.resume(); + * // Opctonrol code here + * task.suspend(); + * } + * + * \endcode + */ + void resume(); + + /** + * Gets the name of the specified task. + * + * \return A pointer to the name of the task + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * printf("Number of Running Tasks: %d\n", my_task.get_name()); + * } + * \endcode + */ + const char* get_name(); + + /** + * Convert this object to a C task_t handle + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void initialize() { + * pros::Task my_task(my_task_fn, "My Task"); + * + * pros::c::task_t my_task_c = (pros::c::task_t)my_task; + * } + * \endcode + */ + explicit operator task_t() { + return task; + } + + /** + * Sends a simple notification to task and increments the notification + * counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return Always returns true. + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * while(pros::Task::current_task().notify_take(true) == 0) { + * // Code while waiting + * } + * puts("I was unblocked!"); + * } + * + * void opcontrol() { + * pros::Task my_task(my_task_fn); + * + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * my_task.notify(); + * } + * } + * } + * \endcode + */ + std::uint32_t notify(); + + /** + * Utilizes task notifications to wait until specified task is complete and deleted, + * then continues to execute the program. Analogous to std::thread::join in C++. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return void + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * lcd_print(1, "%s running", pros::Task::current_task().get_name()); + * task_delay(1000); + * lcd_print(2, "End of %s", pros::Task::current_task().get_name()); + * } + * + * void opcontrol() { + * pros::Task my_task(my_task_fn); + * pros::lcd::set_text(0, "Running task."); + * my_task.join(); + * pros::lcd::lcd_set_text(3, "Task completed."); + * } + * \endcode + */ + void join(); + + /** + * Sends a notification to a task, optionally performing some action. Will + * also retrieve the value of the notification in the target task before + * modifying the notification value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param value + * The value used in performing the action + * \param action + * An action to optionally perform on the receiving task's notification + * value + * \param prev_value + * A pointer to store the previous value of the target task's + * notification, may be NULL + * + * \return Dependent on the notification action. + * For NOTIFY_ACTION_NO_WRITE: return 0 if the value could be written without + * needing to overwrite, 1 otherwise. + * For all other NOTIFY_ACTION values: always return 0 + * + * \b Example + * \code + * void my_task_fn(void* param) { + * pros::Task task = pros::Task::current(); + * + * while(true) { + * // Wait until we have been notified 20 times before running the code + * if(task.notify_take(false, TIMEOUT_MAX) == 20) { + * // ... Code to do stuff here ... + * + * // Reset the notification counter + * task.notify_clear(); + * } + * delay(10); + * } + * } + * + * void opcontrol() { + * pros::Task task(my_task_fn); + * + * int count = 0; + * + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task.notify_ext(1, NOTIFY_ACTION_INCREMENT, &count); + * } + * + * delay(20); + * } + * } + * \endcode + */ + std::uint32_t notify_ext(std::uint32_t value, notify_action_e_t action, std::uint32_t* prev_value); + + /** + * Waits for a notification to be nonzero. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param clear_on_exit + * If true (1), then the notification value is cleared. + * If false (0), then the notification value is decremented. + * \param timeout + * Specifies the amount of time to be spent waiting for a notification + * to occur. + * + * \return The value of the task's notification value before it is decremented + * or cleared + * + * \b Example + * \code + * void my_task_fn(void* ign) { + * pros::Task task = pros::task::current(); + * while(task.notify_take(true, TIMEOUT_MAX)) { + * puts("I was unblocked!"); + * } + * } + * + * void opcontrol() { + * pros::Task task(my_task_fn); + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task.notify(my_task); + * } + * } + * } + * \endcode + */ + static std::uint32_t notify_take(bool clear_on_exit, std::uint32_t timeout); + + /** + * Clears the notification for a task. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \return False if there was not a notification waiting, true if there was + * \b Example + * \code + * void my_task_fn(void* param) { + * pros::Task task = pros::Task::current(); + * while(true) { + * printf("Waiting for notification...\n"); + * printf("Got a notification: %d\n", task.notify_take(false, TIMEOUT_MAX)); + * + * tasK_notify(task); + * delay(10): + * } + * } + * + * void opcontrol() { + * pros::Task task(my_task_fn); + * while(true) { + * if(controller_get_digital(CONTROLLER_MASTER, DIGITAL_L1)) { + * task.notify(); + * } + * delay(10); + * } + * } + * \endcode + */ + bool notify_clear(); + + /** + * Delays the current task for a specified number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * // Do opcontrol things + * pros::Task::delay(2); + * } + * \endcode + */ + static void delay(const std::uint32_t milliseconds); + + /** + * Delays the current Task until a specified time. This function can be used by + * periodic tasks to ensure a constant execution frequency. + * + * The task will be woken up at the time *prev_time + delta, and *prev_time + * will be updated to reflect the time at which the task will unblock. + * + * \param prev_time + * A pointer to the location storing the setpoint time. This should + * typically be initialized to the return value from pros::millis(). + * \param delta + * The number of milliseconds to wait (1000 milliseconds per second) + * + * \b Example + * \code + * void opcontrol() { + * while (true) { + * // Do opcontrol things + * pros::Task::delay(2); + * } + * } + * \endcode + */ + static void delay_until(std::uint32_t* const prev_time, const std::uint32_t delta); + + /** + * Gets the number of tasks the kernel is currently managing, including all + * ready, blocked, or suspended tasks. A task that has been deleted, but not + * yet reaped by the idle task will also be included in the count. + * Tasks recently created may take one context switch to be counted. + * + * \return The number of tasks that are currently being managed by the kernel. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * printf("Hello %s\n", (char*)param); + * // ... + * } + * + * void opcontrol() { + * pros::Task my_task(my_task_fn); + * printf("There are %d tasks running\n", pros::Task::get_count()); + * } + * \endcode + */ + static std::uint32_t get_count(); + + private: + task_t task{}; +}; + +// STL Clock compliant clock +struct Clock { + using rep = std::uint32_t; + using period = std::milli; + using duration = std::chrono::duration; + using time_point = std::chrono::time_point; + const bool is_steady = true; + + /** + * Gets the current time. + * + * Effectively a wrapper around pros::millis() + * + * \return The current time + * + * \b Example + * \code + * void opcontrol() { + * pros::Clock::time_point start = pros::Clock::now(); + * pros::Clock::time_point end = pros::Clock::now(); + * pros::Clock::duration duration = end - start; + * printf("Duration: %d\n", duration.count()); + * + * if(duration.count() == 500) { + * // If you see this comment in the DOCS, ping @pros in VTOW. + * // If you are the first person to do so, you will receive a free PROS + * // holo! + * printf("Duration is 500 milliseconds\n"); + * } + * } + * \endcode + */ + static time_point now(); +}; + +class Mutex { + std::shared_ptr> mutex; + + public: + Mutex(); + + // disable copy and move construction and assignment per Mutex requirements + // (see https://en.cppreference.com/w/cpp/named_req/Mutex) + Mutex(const Mutex&) = delete; + Mutex(Mutex&&) = delete; + + Mutex& operator=(const Mutex&) = delete; + Mutex& operator=(Mutex&&) = delete; + + /** + * Takes and locks a mutex indefinetly. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return True if the mutex was successfully taken, false otherwise. If false + * is returned, then errno is set with a hint about why the the mutex + * couldn't be taken + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::Mutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool take(); + + /** + * Takes and locks a mutex, waiting for up to a certain number of milliseconds + * before timing out. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \param timeout + * Time to wait before the mutex becomes available. A timeout of 0 can + * be used to poll the mutex. TIMEOUT_MAX can be used to block + * indefinitely. + * + * \return True if the mutex was successfully taken, false otherwise. If false + * is returned, then errno is set with a hint about why the the mutex + * couldn't be taken. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::Mutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool take(std::uint32_t timeout); + + /** + * Unlocks a mutex. + * + * See + * https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html#mutexes + * for details. + * + * \return True if the mutex was successfully returned, false otherwise. If + * false is returned, then errno is set with a hint about why the mutex + * couldn't be returned. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::Mutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.take(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.give(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.take(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.give(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.take(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.give(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + bool give(); + + /** + * Takes and locks a mutex, waiting for up to TIMEOUT_MAX milliseconds. + * + * Effectively equivalent to calling pros::Mutex::take with TIMEOUT_MAX as + * the parameter. + * + * Conforms to named requirment BasicLockable + * \see https://en.cppreference.com/w/cpp/named_req/BasicLockable + * + * \note Consider using a std::unique_lock, std::lock_guard, or + * std::scoped_lock instead of interacting with the Mutex directly. + * + * \exception std::system_error Mutex could not be locked within TIMEOUT_MAX + * milliseconds. see errno for details. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::Mutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.lock(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.unlock(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.lock(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.unlock(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.lock(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.unlock(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + void lock(); + + /** + * Unlocks a mutex. + * + * Equivalent to calling pros::Mutex::give. + * + * Conforms to named requirement BasicLockable + * \see https://en.cppreference.com/w/cpp/named_req/BasicLockable + * + * \note Consider using a std::unique_lock, std::lock_guard, or + * std::scoped_lock instead of interacting with the Mutex direcly. + * + * \b Example + * \code + * // Global variables for the robot's odometry, which the rest of the robot's + * // subsystems will utilize + * double odom_x = 0.0; + * double odom_y = 0.0; + * double odom_heading = 0.0; + * + * // This mutex protects the odometry data. Whenever we read or write to the + * // odometry data, we should make copies into the local variables, and read + * // all 3 values at once to avoid errors. + * pros::Mutex odom_mutex; + * + * void odom_task(void* param) { + * while(true) { + * // First we fetch the odom coordinates from the previous iteration of the + * // odometry task. These are put into local variables so that we can + * // keep the size of the critical section as small as possible. This lets + * // other tasks that need to use the odometry data run until we need to + * // update it again. + * odom_mutex.lock(); + * double x_old = odom_x; + * double y_old = odom_y; + * double heading_old = odom_heading; + * odom_mutex.unlock(); + * + * double x_new = 0.0; + * double y_new = 0.0; + * double heading_new = 0.0; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * odom_mutex.lock(); + * odom_x = x_new; + * odom_y = y_new; + * odom_heading = heading_new; + * odom_mutex.unlock(); + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * // Here we copy the current odom values into local variables so that + * // we can use them without worrying about the odometry task changing say, + * // the y value right after we've read the x. This ensures our values are + * // sound. + * odom_mutex.lock(); + * double current_x = odom_x; + * double current_y = odom_y; + * double current_heading = odom_heading; + * odom_mutex.unlock(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * \endcode. + */ + void unlock(); + + /** + * Try to lock a mutex. + * + * Returns immediately if unsucessful. + * + * Conforms to named requirement Lockable + * \see https://en.cppreference.com/w/cpp/named_req/Lockable + * + * \return True when lock was acquired succesfully, or false otherwise. + * + * pros::Mutex mutex; + * + * void my_task_fn(void* param) { + * while (true) { + * if(mutex.try_lock()) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired!\n"); + * } + * } + * } + */ + bool try_lock(); + + /** + * Takes and locks a mutex, waiting for a specified duration. + * + * Equivalent to calling pros::Mutex::take with a duration specified in + * milliseconds. + * + * Conforms to named requirement TimedLockable + * \see https://en.cppreference.com/w/cpp/named_req/TimedLockable + * + * \param rel_time Time to wait before the mutex becomes available. + * \return True if the lock was acquired succesfully, otherwise false. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while (true) { + * if(mutex.try_lock_for(std::chrono::milliseconds(100))) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired after 100 milliseconds!\n"); + * } + * } + * } + * \endcode + */ + template + bool try_lock_for(const std::chrono::duration& rel_time) { + return take(std::chrono::duration_cast(rel_time).count()); + } + + /** + * Takes and locks a mutex, waiting until a specified time. + * + * Conforms to named requirement TimedLockable + * \see https://en.cppreference.com/w/cpp/named_req/TimedLockable + * + * \param abs_time Time point until which to wait for the mutex. + * \return True if the lock was acquired succesfully, otherwise false. + * + * \b Example + * \code + * void my_task_fn(void* param) { + * while (true) { + * // Get the current time point + * auto now = std::chrono::system_clock::now(); + * + * // Calculate the time point 100 milliseconds from now + * auto abs_time = now + std::chrono::milliseconds(100); + * + * if(mutex.try_lock_until(abs_time)) { + * printf("Mutex aquired successfully!\n"); + * // Do stuff that requires the protected resource here + * } + * else { + * printf("Mutex not aquired after 100 milliseconds!\n"); + * } + * } + * } + * \endcode + */ + template + bool try_lock_until(const std::chrono::time_point& abs_time) { + return take(std::max(static_cast(0), (abs_time - Clock::now()).count())); + } + ///@} +}; + +template +class MutexVar; + +template +class MutexVarLock { + Mutex& mutex; + Var& var; + + friend class MutexVar; + + constexpr MutexVarLock(Mutex& mutex, Var& var) : mutex(mutex), var(var) {} + + public: + /** + * Accesses the value of the mutex-protected variable. + */ + constexpr Var& operator*() const { + return var; + } + + /** + * Accesses the value of the mutex-protected variable. + */ + constexpr Var* operator->() const { + return &var; + } + + ~MutexVarLock() { + mutex.unlock(); + } +}; + +template +class MutexVar { + Mutex mutex; + Var var; + + public: + /** + * Creates a mutex-protected variable which is initialized with the given + * constructor arguments. + * + * \param args + * The arguments to provide to the Var constructor. + * + * \b Example + * \code + * // We create a pose class to contain all our odometry data in a single + * // variable that can be protected by a MutexVar. Otherwise, we would have + * // three seperate variables which could not be protected in a single + * // MutexVar + * struct Pose { + * double x; + * double y; + * double heading; + * } + * + * pros::MutexVar odom_pose(0.0, 0.0, 0.0); + * + * void odom_task(void* param) { + * while(true) { + * Pose old_pose = *odom_pose.lock(); + * + * Pose new_pose{0.0, 0.0, 0.0}; + * + * // --- Calculate new pose for the robot here --- + * + * // Now that we have the new pose, we can update the global variables + * + * *odom_pose.take() = new_pose; + * + * delay(10); + * } + * } + * + * void chassis_task(void* param) { + * while(true) { + * + * Pose cur_pose = *odom_pose.take(); + * + * // ---- Move the robot using the current locations goes here ---- + * + * delay(10); + * } + * } + * + * void initialize() { + * odom_mutex = pros::Mutex(); + * + * pros::Task odom_task(odom_task, "Odometry Task"); + * pros::Task chassis_task(odom_task, "Chassis Control Task"); + * } + * + * \endcode + */ + template + MutexVar(Args&&... args) : mutex(), var(std::forward(args)...) {} + + /** + * Try to lock the mutex-protected variable. + * + * \param timeout + * Time to wait before the mutex becomes available, in milliseconds. A + * timeout of 0 can be used to poll the mutex. + * + * \return A std::optional which contains a MutexVarLock providing access to + * the protected variable if locking is successful. + * + * \b Example + * \code + * pros::MutexVar odom_pose; + * + * void my_task(void* param) { + * while(true) { + * std::optional> cur_pose_opt = odom_pose.try_lock(100); + * + * if(cur_pose_opt.has_value()) { + * Pose* cur_pose = **cur_pose_opt; + * } + * else { + * printf("Could not lock the mutex var!"); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + std::optional> try_lock(std::uint32_t timeout) { + if (mutex.take(timeout)) { + return {{mutex, var}}; + } else { + return {}; + } + } + + /** + * Try to lock the mutex-protected variable. + * + * \param timeout + * Time to wait before the mutex becomes available. A timeout of 0 can + * be used to poll the mutex. + * + * \return A std::optional which contains a MutexVarLock providing access to + * the protected variable if locking is successful. + * + * \b Example + * \code + * pros::MutexVar odom_pose; + * + * void my_task(void* param) { + * while(true) { + * std::chrono::duration timeout(100); + * std::optional> cur_pose_opt = odom_pose.try_lock(timeout); + * + * if(cur_pose_opt.has_value()) { + * Pose* cur_pose = **cur_pose_opt; + * } + * else { + * printf("Could not lock the mutex var!"); + * } + * + * pros::delay(10); + * } + * } + * \endcode + */ + template + std::optional> try_lock(const std::chrono::duration& rel_time) { + try_lock(std::chrono::duration_cast(rel_time).count()); + } + + /** + * Lock the mutex-protected variable, waiting indefinitely. + * + * \return A MutexVarLock providing access to the protected variable. + * + * \b Example + * \code + * pros::MutexVar odom_pose; + * + * void my_task(void* param) { + * while(true) { + * pros::delay(10); + * + * pros::MutexVarLock cur_pose = odom_pose.lock(); + * Pose cur_pose = *cur_pose; + * + * // do stuff with cur_pose + * } + * } + * \endcode + */ + MutexVarLock lock() { + while (!mutex.take(TIMEOUT_MAX)) + ; + return {mutex, var}; + } +}; + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +using pros::c::millis; + +/** + * Gets the number of microseconds since PROS initialized. + * + * \return The number of microseconds since PROS initialized + */ +using pros::c::micros; + +/** + * Delays a task for a given number of milliseconds. + * + * This is not the best method to have a task execute code at predefined + * intervals, as the delay time is measured from when the delay is requested. + * To delay cyclically, use task_delay_until(). + * + * \param milliseconds + * The number of milliseconds to wait (1000 milliseconds per second) + */ +using pros::c::delay; +} // namespace rtos +} // namespace pros + +#endif // _PROS_RTOS_HPP_ diff --git a/include/pros/screen.h b/include/pros/screen.h new file mode 100644 index 0000000..2e1592b --- /dev/null +++ b/include/pros/screen.h @@ -0,0 +1,796 @@ +/** + * \file screen.h + * \ingroup c-screen + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-screen Simplified Brain Screen C API + * + */ + +#ifndef _PROS_SCREEN_H_ +#define _PROS_SCREEN_H_ + +#include +#include +#define _GNU_SOURCE +#include +#undef _GNU_SOURCE +#include + +#include "pros/colors.h" // c color macros + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \ingroup c-screen + */ + +/** + * \addtogroup c-screen + * @{ + */ + +/** + * \enum text_format_e_t + * Different font sizes that can be used in printing text. + */ +typedef enum { + /// Small text font size + E_TEXT_SMALL = 0, + /// Normal/Medium text font size + E_TEXT_MEDIUM, + /// Large text font size + E_TEXT_LARGE, + /// Medium centered text + E_TEXT_MEDIUM_CENTER, + /// Large centered text + E_TEXT_LARGE_CENTER +} text_format_e_t; + +/** + * \enum last_touch_e_t + * Enum indicating what the current touch status is for the touchscreen. + */ +typedef enum { + /// Last interaction with screen was a quick press + E_TOUCH_RELEASED = 0, + /// Last interaction with screen was a release + E_TOUCH_PRESSED, + /// User is holding screen down + E_TOUCH_HELD, + /// An error occured while taking/returning the mutex + E_TOUCH_ERROR +} last_touch_e_t; + +/** + * \struct screen_touch_status_s_t + * Struct representing screen touch status, screen last x, screen last y, press count, release count. + */ +typedef struct screen_touch_status_s { + /// Represents if the screen is being held, released, or pressed. + last_touch_e_t touch_status; + /// Represents the x value of the location of the touch. + int16_t x; + /// Represents the y value of the location of the touch. + int16_t y; + /// Represents how many times the screen has be pressed. + int32_t press_count; + /// Represents how many times the user released after a touch on the screen. + int32_t release_count; +} screen_touch_status_s_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define TEXT_SMALL pros::E_TEXT_SMALL +#define TEXT_MEDIUM pros::E_TEXT_MEDIUM +#define TEXT_LARGE pros::E_TEXT_LARGE +#define TEXT_MEDIUM_CENTER pros::E_TEXT_MEDIUM_CENTER +#define TEXT_LARGE_CENTER pros::E_LARGE_CENTER +#define TOUCH_RELEASED pros::E_TOUCH_RELEASED +#define TOUCH_PRESSED pros::E_TOUCH_PRESSED +#define TOUCH_HELD pros::E_TOUCH_HELD +#else +#define TEXT_SMALL E_TEXT_SMALL +#define TEXT_MEDIUM E_TEXT_MEDIUM +#define TEXT_LARGE E_TEXT_LARGE +#define TEXT_MEDIUM_CENTER E_TEXT_MEDIUM_CENTER +#define TEXT_LARGE_CENTER E_TEXT_LARGE_CENTER +#define TOUCH_RELEASED E_TOUCH_RELEASED +#define TOUCH_PRESSED E_TOUCH_PRESSED +#define TOUCH_HELD E_TOUCH_HELD +#endif +#endif + +typedef void (*touch_event_cb_fn_t)(); + +#ifdef __cplusplus +namespace c { +#endif + +/// \name Screen Graphical Display Functions +/// These functions allow programmers to display shapes on the v5 screen +///@{ + +/** + * Set the pen color for subsequent graphics operations + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The pen color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if + * there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * screen_set_pen(COLOR_RED); + * } + * + * void opcontrol() { + * int iter = 0; + * while(1){ + * // This should print in red. + * screen_print(TEXT_MEDIUM, 1, "%d", iter++); + * } + * } + * \endcode + */ +uint32_t screen_set_pen(uint32_t color); + +/** + * Set the eraser color for erasing and the current background. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The background color to set (it is recommended to use values + * from the enum defined in colors.h) + * + * \return Returns 1 if the mutex was successfully returned, or + * PROS_ERR if there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * screen_set_eraser(COLOR_RED); + * } + * + * void opcontrol() { + * while(1){ + * // This should turn the screen red. + * screen_erase(); + * } + * } + * \endcode + */ +uint32_t screen_set_eraser(uint32_t color); + +/** + * Get the current pen color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current pen color in the form of a value from the enum defined + * in colors.h, or PROS_ERR if there was an error taking or returning + * the screen mutex. + * + * \b Example + * \code + * void initialize() { + * screen_set_pen(COLOR_RED); + * } + * + * void opcontrol() { + * while(1){ + * // Should print number equivalent to COLOR_RED defined in colors.h. + * screen_print(TEXT_MEDIUM, 1, "%d", screen_get_pen()); + * } + * } + * \endcode + */ +uint32_t screen_get_pen(void); + +/** + * Get the current eraser color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current eraser color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * screen_set_eraser(COLOR_RED); + * } + * + * void opcontrol() { + * while(1){ + * // Should print number equivalent to COLOR_RED defined in colors.h. + * screen_print(TEXT_MEDIUM, 1, "%d", screen_get_eraser()); + * } + * } + * \endcode + */ +uint32_t screen_get_eraser(void); + +/** + * Clear display with eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * screen_set_eraser(COLOR_RED); + * } + * + * void opcontrol() { + * while(1){ + * // This should turn the screen red. + * screen_erase(); + * } + * } + * \endcode + */ +uint32_t screen_erase(void); + +/** + * Scroll lines on the display upwards. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param start_line The line from which scrolling will start + * \param lines The number of lines to scroll up + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_print(TEXT_MEDIUM, 4, "Line Here"); + * // Scroll 3 lines + * screen_scroll(4, 3); + * } + * \endcode + */ +uint32_t screen_scroll(int16_t start_line, int16_t lines); + +/** + * Scroll lines within a region on the display + * + * This function behaves in the same way as `screen_scroll`, except that you + * specify a rectangular region within which to scroll lines instead of a start + * line. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region + * \param lines The number of lines to scroll upwards + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_print(TEXT_MEDIUM, 1, "Line Here"); + * // Scrolls area of screen upwards slightly. including line of text + * screen_scroll_area(0,0, 400, 200, 3); + * } + * \endcode + */ +uint32_t screen_scroll_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t lines); + +/** + * Copy a screen region (designated by a rectangle) from an off-screen buffer + * to the screen + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region of the screen + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region of the screen + * \param buf Off-screen buffer containing screen data + * \param stride Off-screen buffer width in pixels, such that image size + * is stride-padding + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * uint32_t* buf = malloc(sizeof(uint32_t) * 400 * 200); + * screen_print(TEXT_MEDIUM, 1, "Line Here"); + * // Copies area of the screen including text + * screen_copy_area(0, 0, 400, 200, (uint32_t*)buf, 400 + 1); + * // Equation for stride is x2 - x1 + 1 + * } + * \endcode + */ +uint32_t screen_copy_area(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint32_t* buf, int32_t stride); + +/** + * Draw a single pixel on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the pixel + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * int i = 0; + * void opcontrol() { + * while(i < 200){ + * screen_draw_pixel(100,i++); + * // Draws a line at x = 100 gradually down the screen, pixel by pixel + * delay(200); + * } + * } + * \endcode + */ +uint32_t screen_draw_pixel(int16_t x, int16_t y); + +/** + * Erase a pixel from the screen (Sets the location) + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the erased + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Color the Screen in Red + * screen_set_pen(COLOR_RED); + * screen_fill_rect(0,0,400,200); + * int i = 0; + * while(i < 200){ + * screen_erase_pixel(100,i++); + * // Erases a line at x = 100 gradually down the screen, pixel by pixel + * delay(200); + * } + * } + * \endcode + */ +uint32_t screen_erase_pixel(int16_t x, int16_t y); + +/** + * Draw a line on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_set_pen(COLOR_RED); + * // Draw line down the screen at x = 100 + * screen_draw_line(100,0,100,200); + * } + * \endcode + */ +uint32_t screen_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Erase a line on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Color the Screen in Red + * screen_set_pen(COLOR_RED); + * screen_fill_rect(0,0,400,200); + * // Erase line down the screen at x = 100 + * screen_erase_line(100,0,100,200); + * } + * \endcode + */ +uint32_t screen_erase_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Draw a rectangle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_set_pen(COLOR_RED); + * screen_draw_rect(1,1,480,200); + * } + * \endcode + */ +uint32_t screen_draw_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Erase a rectangle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Draw Box Around Half the Screen in Red + * screen_set_eraser(COLOR_RED); + * screen_erase_rect(5,5,240,200); + * } + * \endcode + */ +uint32_t screen_erase_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Fill a rectangular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Fill Around Half the Screen in Red + * screen_set_pen(COLOR_RED); + * screen_fill_rect(5,5,240,200); + * } + * \endcode + */ +uint32_t screen_fill_rect(int16_t x0, int16_t y0, int16_t x1, int16_t y1); + +/** + * Draw a circle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Draw a circle with radius of 100 in red + * screen_set_pen(COLOR_RED); + * screen_draw_circle(240, 200, 100); + * } + * \endcode + */ +uint32_t screen_draw_circle(int16_t x, int16_t y, int16_t radius); + +/** + * Erase a circle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_set_pen(COLOR_RED); + * screen_fill_rect(5,5,240,200); + * // Erase a circle with radius of 100 in COLOR_BLUE + * screen_set_pen(COLOR_BLUE); + * screen_erase_circle(240, 200, 100); + * } + * \endcode + */ +uint32_t screen_erase_circle(int16_t x, int16_t y, int16_t radius); + +/** + * Fill a circular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * screen_set_pen(COLOR_RED); + * screen_fill_rect(5,5,240,200); + * // Fill a circlular area with radius of 100 in COLOR_BLUE + * screen_set_pen(COLOR_BLUE); + * screen_fill_circle(240, 200, 100); + * } + * \endcode + */ +uint32_t screen_fill_circle(int16_t x, int16_t y, int16_t radius); + +///@} + +/// \name Screen Text Display Functions +/// These functions allow programmers to display text on the v5 screen +///@{ + +/** + * Print a formatted string to the screen on the specified line + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES + * NOT SUPPORT SMALL) \param line The line number on which to print \param text Format string \param ... Optional list + * of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * int i = 0; + * + * screen_set_pen(COLOR_BLUE); + * while(1){ + * // Will print seconds started since program started on line 3 + * screen_print(TEXT_MEDIUM, 3, "Seconds Passed: %3d", i++); + * delay(1000); + * } + * } + * \endcode + */ +uint32_t screen_print(text_format_e_t txt_fmt, const int16_t line, const char* text, ...); + +/** + * Print a formatted string to the screen at the specified point + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * Text formats medium_center and large_center will default to medium and large respectively. + * + * \param txt_fmt Text format enum that determines if the text is small, medium, or large. + * \param x The y coordinate of the top left corner of the string + * \param y The x coordinate of the top left corner of the string + * \param text Format string + * \param ... Optional list of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * int i = 0; + * + * screen_set_pen(COLOR_BLUE); + * while(1){ + * // Will print seconds started since program started. + * screen_print_at(TEXT_SMALL, 3, "Seconds Passed: %3d", i++); + * delay(1000); + * } + * } + * \endcode + */ +uint32_t screen_print_at(text_format_e_t txt_fmt, const int16_t x, const int16_t y, const char* text, ...); + +/** + * Print a formatted string to the screen on the specified line + * + * Same as `display_printf` except that this uses a `va_list` instead of the + * ellipsis operator so this can be used by other functions. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * Exposed mostly for writing libraries and custom functions. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES + * NOT SUPPORT SMALL) \param line The line number on which to print \param text Format string \param args List of + * arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + * + * + */ +uint32_t screen_vprintf(text_format_e_t txt_fmt, const int16_t line, const char* text, va_list args); + +/** + * Print a formatted string to the screen at the specified coordinates + * + * Same as `display_printf_at` except that this uses a `va_list` instead of the + * ellipsis operator so this can be used by other functions. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * Text formats medium_center and large_center will default to medium and large respectively. + * Exposed mostly for writing libraries and custom functions. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param txt_fmt Text format enum that determines if the text is small, medium, or large. + * \param x, y The (x,y) coordinates of the top left corner of the string + * \param text Format string + * \param args List of arguments for the format string + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + * + */ +uint32_t screen_vprintf_at(text_format_e_t txt_fmt, const int16_t x, const int16_t y, const char* text, va_list args); + +///@} + +/// \name Screen Touch Functions +/// These functions allow programmers to access information about screen touches +///@{ + +/** + * Gets the touch status of the last touch of the screen. + * + * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen (E_TOUCH_EVENT_RELEASE, + * E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). This will be released by default if no action was taken. If an + * error occured, the screen_touch_status_s_t will have its last_touch_e_t enum specifier set to E_TOUCH_ERR, and other + * values set to -1. + * + * \b Example + * \code + * void opcontrol() { + * int i = 0; + * screen_touch_status_s_t status; + * while(1){ + * status = screen_touch_status(); + * + * // Will print various information about the last touch + * screen_print(TEXT_MEDIUM, 1, "Touch Status (Type): %d", status.touch_status); + * screen_print(TEXT_MEDIUM, 2, "Last X: %d", status.x); + * screen_print(TEXT_MEDIUM, 3, "Last Y: %d", status.y); + * screen_print(TEXT_MEDIUM, 4, "Press Count: %d", status.press_count); + * screen_print(TEXT_MEDIUM, 5, "Release Count: %d", status.release_count); + * delay(20); + * } + * } + * \endcode + */ +screen_touch_status_s_t screen_touch_status(void); + +/** + * Assigns a callback function to be called when a certain touch event happens. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param cb Function pointer to callback when event type happens + * \param event_type Touch event that will trigger the callback. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + * + * \b Example + * \code + * touch_event_cb_fn_t changePixel(){ + * screen_touch_status_s_t status = screen_touch_status(); + * screen_draw_pixel(status.x,status.y); + * return NULL; + * } + * + * void opcontrol() { + * screen_touch_callback(changePixel(), TOUCH_PRESSED); + * while(1) delay(20); + * } + * \endcode + */ +uint32_t screen_touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); + +///@} + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif diff --git a/include/pros/screen.hpp b/include/pros/screen.hpp new file mode 100644 index 0000000..c3980e1 --- /dev/null +++ b/include/pros/screen.hpp @@ -0,0 +1,717 @@ +/** + * \file screen.hpp + * \ingroup cpp-screen + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-screen Simplified Brain Screen C++ API + */ + +#ifndef _PROS_SCREEN_HPP_ +#define _PROS_SCREEN_HPP_ + +#include "pros/screen.h" +#include "pros/colors.hpp" +#include +#include + +namespace pros { +namespace screen { + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" + +namespace { +template +T convert_args(T arg) { + return arg; +} +const char* convert_args(const std::string& arg) { + return arg.c_str(); +} +} // namespace + +#pragma GCC diagnostic pop + +/** + * \ingroup cpp-screen + */ + +/** + * \addtogroup cpp-screen + * @{ + */ + + /******************************************************************************/ + /** Screen Graphical Display Functions **/ + /** **/ + /** These functions allow programmers to display shapes on the v5 screen **/ + /******************************************************************************/ + + /** + * Set the pen color for subsequent graphics operations + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The pen color to set (it is recommended to use values + * from the enum defined in colors.hpp) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if + * there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * pros::screen::set_pen(red); + * } + * + * void opcontrol() { + * int iter = 0; + * while(1){ + * // This should print in red. + * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); + * } + * } + * + * \endcode + */ + std::uint32_t set_pen(pros::Color color); + + /** + * Set the pen color for subsequent graphics operations + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The pen color to set (in hex form) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR if + * there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * //set pen color to red + * pros::screen::set_pen(0x00FF0000); + * } + * + * void opcontrol() { + * int iter = 0; + * while(1){ + * // This should print in red. + * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); + * } + * } + * + * \endcode + */ + std::uint32_t set_pen(std::uint32_t color); + + /** + * Set the eraser color for erasing and the current background. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The background color to set (it is recommended to use values + * from the enum defined in colors.hpp) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR + * if there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * //set eraser color to red + * set_eraser(red); + * } + * + * void opcontrol() { + * int iter = 0; + * while(1){ + * // This should print in red. + * pros::screen::print(TEXT_MEDIUM, 1, "%d", iter++); + * } + * } + * + * \endcode + */ + std::uint32_t set_eraser(pros::Color color); + + /** + * Set the eraser color for erasing and the current background. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param color The background color to set to set (in hex form) + * + * \return Returns 1 if the mutex was successfully returned, or PROS_ERR + * if there was an error either taking or returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * //set eraser color to red + * pros::screen::set_eraser(0x00FF0000); + * } + * + * void opcontrol() { + * while(1){ + * // This should turn the screen red. + * pros::screen::erase(); + * } + * } + * \endcode + */ + std::uint32_t set_eraser(std::uint32_t color); + + /** + * Get the current pen color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current pen color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * pros::screen::set_pen(red); + * } + * + * void opcontrol() { + * while(1){ + * // Should print number equivalent to red defined in colors.hpp. + * pros::screen::print(TEXT_MEDIUM, 1, "%d", get_pen()); + * } + * } + * \endcode + */ + std::uint32_t get_pen(); + + /** + * Get the current eraser color. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return The current eraser color in the form of a value from the enum + * defined in colors.h, or PROS_ERR if there was an error taking or + * returning the screen mutex. + * + * \b Example + * \code + * void initialize() { + * pros::screen::set_eraser(red); + * } + * + * void opcontrol() { + * while(1){ + * // Should print number equivalent to red defined in colors.h. + * pros::screen::print(TEXT_MEDIUM, 1, "%d", get_eraser()); + * } + * } + * \endcode + */ + std::uint32_t get_eraser(); + + /** + * Clear display with eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * * \b Example + * \code + * void initialize() { + * pros::screen::set_eraser(red); + * } + * + * void opcontrol() { + * while(1){ + * // This should turn the screen red. + * pros::screen::erase(); + * } + * } + * \endcode + */ + std::uint32_t erase(); + + /** + * Scroll lines on the display upwards. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param start_line The line from which scrolling will start + * \param lines The number of lines to scroll up + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::print(TEXT_MEDIUM, 4, "Line Here"); + * // Scroll 3 lines + * pros::screen::scroll(4, 3); + * } + * \endcode + */ + std::uint32_t scroll(const std::int16_t start_line, const std::int16_t lines); + + /** + * Scroll lines within a region on the display + * + * This function behaves in the same way as `screen_scroll`, except that you + * specify a rectangular region within which to scroll lines instead of a start + * line. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region + * \param lines The number of lines to scroll upwards + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::print(TEXT_MEDIUM, 1, "Line Here"); + * // Scrolls area of screen upwards slightly. including line of text + * pros::screen::scroll_area(0,0, 400, 200, 3); + * } + * \endcode + */ + std::uint32_t scroll_area(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1, std::int16_t lines); + + /** + * Copy a screen region (designated by a rectangle) from an off-screen buffer + * to the screen + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first corner of the + * rectangular region of the screen + * \param x1, y1 The (x,y) coordinates of the second corner of the + * rectangular region of the screen + * \param buf Off-screen buffer containing screen data + * \param stride Off-screen buffer width in pixels, such that image size + * is stride-padding + * + * \return 1 if there were no errors, or PROS_ERR if an error occured taking + * or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * uint32_t* buf = malloc(sizeof(uint32_t) * 400 * 200); + * pros::screen::print(TEXT_MEDIUM, 1, "Line Here"); + * // Copies area of the screen including text + * pros::screen::copy_area(0, 0, 400, 200, (uint32_t*)buf, 400 + 1); + * // Equation for stride is x2 - x1 + 1 + * } + * \endcode + */ + std::uint32_t copy_area(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1, uint32_t* buf, const std::int32_t stride); + + /** + * Draw a single pixel on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the pixel + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * int i = 0; + * void opcontrol() { + * while(i < 200){ + * pros::screen::draw_pixel(100,i++); + * // Draws a line at x = 100 gradually down the screen, pixel by pixel + * pros::delay(200); + * } + * } + * \endcode + */ + std::uint32_t draw_pixel(const std::int16_t x, const std::int16_t y); + + /** + * Erase a pixel from the screen (Sets the location) + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the erased + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Color the Screen in Red + * pros::screen::set_pen(red); + * pros::screen::fill_rect(0,0,400,200); + * int i = 0; + * while(i < 200){ + * pros::screen::erase_pixel(100,i++); + * // Erases a line at x = 100 gradually down the screen, pixel by pixel + * pros::delay(200); + * } + * } + * \endcode + */ + std::uint32_t erase_pixel(const std::int16_t x, const std::int16_t y); + + /** + * Draw a line on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::set_pen(red); + * // Draw line down the screen at x = 100 + * pros::screen::draw_line(100,0,100,200); + * } + * \endcode + */ + std::uint32_t draw_line(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Erase a line on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x, y) coordinates of the first point of the line + * \param x1, y1 The (x, y) coordinates of the second point of the line + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Color the Screen in Red + * pros::screen::set_pen(red); + * pros::screen::fill_rect(0,0,400,200); + * // Erase line down the screen at x = 100 + * pros::screen::erase_line(100,0,100,200); + * } + * \endcode + */ + std::uint32_t erase_line(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Draw a rectangle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::set_pen(red); + * pros::screen::draw_rect(1,1,480,200); + * } + * \endcode + */ + std::uint32_t draw_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Erase a rectangle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Draw Box Around Half the Screen in Red + * pros::screen::set_eraser(red); + * pros::screen::erase_rect(5,5,240,200); + * } + * \endcode + */ + std::uint32_t erase_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Fill a rectangular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x0, y0 The (x,y) coordinates of the first point of the rectangle + * \param x1, y1 The (x,y) coordinates of the second point of the rectangle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Fill Around Half the Screen in Red + * pros::screen::set_pen(red); + * pros::screen::fill_rect(5,5,240,200); + * } + * \endcode + */ + std::uint32_t fill_rect(const std::int16_t x0, const std::int16_t y0, const std::int16_t x1, const std::int16_t y1); + + /** + * Draw a circle on the screen using the current pen color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * // Draw a circle with radius of 100 in red + * pros::screen::set_pen(red); + * pros::screen::draw_circle(240, 200, 100); + * } + * \endcode + */ + std::uint32_t draw_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /** + * Erase a circle on the screen using the current eraser color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::set_pen(red); + * pros::screen::fill_rect(5,5,240,200); + * // Erase a circle with radius of 100 in blue + * pros::screen::set_pen(blue); + * pros::screen::erase_circle(240, 200, 100); + * } + * \endcode + */ + std::uint32_t erase_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /** + * Fill a circular region of the screen using the current pen + * color + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param x, y The (x,y) coordinates of the center of the circle + * \param r The radius of the circle + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * taking or returning the screen mutex. + * + * \b Example + * \code + * void opcontrol() { + * pros::screen::set_pen(red); + * pros::screen::fill_rect(5,5,240,200); + * // Fill a circlular area with radius of 100 in blue + * pros::screen::set_pen(blue); + * pros::screen::fill_circle(240, 200, 100); + * } + * \endcode + */ + std::uint32_t fill_circle(const std::int16_t x, const std::int16_t y, const std::int16_t radius); + + /******************************************************************************/ + /** Screen Text Display Functions **/ + /** **/ + /** These functions allow programmers to display text on the v5 screen **/ + /******************************************************************************/ + + /** + * Print a formatted string to the screen, overwrite available for printing at location too. + * + * Will default to a medium sized font by default if invalid txt_fmt is given. + * + * \param txt_fmt Text format enum that determines if the text is medium, large, medium_center, or large_center. (DOES NOT SUPPORT SMALL) + * \param line The line number on which to print + * \param x The (x,y) coordinates of the top left corner of the string + * \param y The (x,y) coordinates of the top left corner of the string + * \param fmt Format string + * \param ... Optional list of arguments for the format string + * + * \b Example + * \code + * void opcontrol() { + * int i = 0; + * pros::screen::set_pen(blue); + * while(1){ + * // Will print seconds started since program started on line 3 + * pros::screen::print(pros::TEXT_MEDIUM, 3, "Seconds Passed: %3d", i++); + * pros::delay(1000); + * } + * } + */ + template + void print(pros::text_format_e_t txt_fmt, const std::int16_t line, const char* text, Params... args){ + pros::c::screen_print(txt_fmt, line, text, convert_args(args)...); + } + + template + void print(pros::text_format_e_t txt_fmt, const std::int16_t x, const std::int16_t y, const char* text, Params... args){ + pros::c::screen_print_at(txt_fmt, x, y, text, convert_args(args)...); + } + + /******************************************************************************/ + /** Screen Touch Functions **/ + /** **/ + /** These functions allow programmers to access **/ + /** information about screen touches **/ + /******************************************************************************/ + + /** + * Gets the touch status of the last touch of the screen. + * + * \return The last_touch_e_t enum specifier that indicates the last touch status of the screen (E_TOUCH_EVENT_RELEASE, E_TOUCH_EVENT_PRESS, or E_TOUCH_EVENT_PRESS_AND_HOLD). + * This will be released by default if no action was taken. + * If an error occured, the screen_touch_status_s_t will have its + * last_touch_e_t enum specifier set to E_TOUCH_ERR, and other values set to -1. + * + * \b Example + * \code + * void opcontrol() { + * int i = 0; + * pros::screen_touch_status_s_t status; + * while(1){ + * status = pros::touch_status(); + * + * // Will print various information about the last touch + * pros::screen::print(TEXT_MEDIUM, 1, "Touch Status (Type): %d", status.touch_status); + * pros::screen::print(TEXT_MEDIUM, 2, "Last X: %d", status.x); + * pros::screen::print(TEXT_MEDIUM, 3, "Last Y: %d", status.y); + * pros::screen::print(TEXT_MEDIUM, 4, "Press Count: %d", status.press_count); + * pros::screen::print(TEXT_MEDIUM, 5, "Release Count: %d", status.release_count); + * pros::delay(20); + * } + * } + * \endcode + */ + screen_touch_status_s_t touch_status(); + + /** + * Assigns a callback function to be called when a certain touch event happens. + * + * This function uses the following values of errno when an error state is + * reached: + * EACCESS - Another resource is currently trying to access the screen mutex. + * + * \param cb Function pointer to callback when event type happens + * \param event_type Touch event that will trigger the callback. + * + * \return 1 if there were no errors, or PROS_ERR if an error occured + * while taking or returning the screen mutex. + * + * \b Example + * \code + * touch_event_cb_fn_t changePixel(){ + * pros::screen_touch_status_s_t status = pros::screen::touch_status(); + * pros::screen::draw_pixel(status.x,status.y); + * return NULL; + * } + * + * void opcontrol() { + * pros::screen::touch_callback(changePixel(), TOUCH_PRESSED); + * while(1) { + * pros::delay(20); + * } + * } + * \endcode + */ + std::uint32_t touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); + +} // namespace screen + + +} // namespace pros + +extern __attribute__((weak)) void lvgl_init() {} +///@} +#endif //header guard diff --git a/include/pros/serial.h b/include/pros/serial.h new file mode 100644 index 0000000..dc9ead5 --- /dev/null +++ b/include/pros/serial.h @@ -0,0 +1,410 @@ +/** + * \file pros/serial.h + * \ingroup c-serial + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-serial Generic Serial C API + */ + +#ifndef _PROS_SERIAL_H_ +#define _PROS_SERIAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * \ingroup c-serial + */ + +/** + * \addtogroup c-serial + * @{ + */ + +/// \name Serial communication functions +/// These functions allow programmers to communicate using UART over RS485 +///@{ + +/** + * Enables generic serial on the given port. + * + * \note This function must be called before any of the generic serial + * functions will work. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * } + * \endcode + */ +int32_t serial_enable(uint8_t port); + +/** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * serial_write(1, "Hello World!", 12); + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_set_baudrate(uint8_t port, int32_t baudrate); + +/** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * serial_flush(1); + * serial_write(1, "Hello World!", 12); + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_flush(uint8_t port); + +/** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_get_read_avail(1) >= 12) { + * char buffer[12]; + * serial_read(1, buffer, 12); + * printf("%s", buffer); + * } + * delay(100); + * } + * } + * \endcode + + */ +int32_t serial_get_read_avail(uint8_t port); + +/** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_get_write_free(1) >= 12) { + * serial_write(1, "Hello World!", 12); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_get_write_free(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_peek_byte(1) == 'H') { + * char buffer[12]; + * serial_read(1, buffer, 12); + * printf("%s", buffer); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_peek_byte(uint8_t port); + +/** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_read_byte(1) == 'H') { + * char buffer[12]; + * serial_read(1, buffer, 12); + * printf("%s", buffer); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_read_byte(uint8_t port); + +/** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_get_read_avail(1) >= 12) { + * char buffer[12]; + * serial_read(1, buffer, 12); + * printf("%s", buffer); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_read(uint8_t port, uint8_t* buffer, int32_t length); + +/** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_get_write_free(1) >= 12) { + * serial_write_byte(1, 'H'); + * serial_write_byte(1, 'e'); + * serial_write_byte(1, 'l'); + * serial_write_byte(1, 'l'); + * serial_write_byte(1, 'o'); + * serial_write_byte(1, ' '); + * serial_write_byte(1, 'W'); + * serial_write_byte(1, 'o'); + * serial_write_byte(1, 'r'); + * serial_write_byte(1, 'l'); + * serial_write_byte(1, 'd'); + * serial_write_byte(1, '!'); + * serial_write_byte(1, '\n'); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_write_byte(uint8_t port, uint8_t buffer); + +/** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param port + * The V5 port number from 1-21 + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code{.c} + * void opcontrol() { + * serial_enable(1); + * serial_set_baudrate(1, 9600); + * while (true) { + * if (serial_get_write_free(1) >= 12) { + * serial_write(1, "Hello World!\n", 12); + * } + * delay(100); + * } + * } + * \endcode + */ +int32_t serial_write(uint8_t port, uint8_t* buffer, int32_t length); + +///@} + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_SERIAL_H_ \ No newline at end of file diff --git a/include/pros/serial.hpp b/include/pros/serial.hpp new file mode 100644 index 0000000..a2490e2 --- /dev/null +++ b/include/pros/serial.hpp @@ -0,0 +1,330 @@ +/** + * \file pros/serial.hpp + * \ingroup cpp-serial + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-serial Generic Serial C++ API + */ + +#ifndef _PROS_SERIAL_HPP_ +#define _PROS_SERIAL_HPP_ + +#include +#include "pros/serial.h" +#include "pros/device.hpp" + +namespace pros { +/** + * \ingroup cpp-serial + * @{ + */ +class Serial : public Device { + /** + * \addtogroup cpp-serial + * @{ + */ + public: + /** + * Creates a Serial object for the given port and specifications. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * \param baudrate + * The baudrate to run the port at + * + * \b Example: + * \code + * pros::Serial serial(1, 9600); + * \endcode + */ + explicit Serial(std::uint8_t port, std::int32_t baudrate); + + /** + * Creates a Serial object for the given port without a set baudrate. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param port + * The V5 port number from 1-21 + * + * \b Example: + * \code + * pros::Serial serial(1); + * \endcode + */ + explicit Serial(std::uint8_t port); + + /******************************************************************************/ + /** Serial communication functions **/ + /** **/ + /** These functions allow programmers to communicate using UART over RS485 **/ + /******************************************************************************/ + + /** + * Sets the baudrate for the serial port to operate at. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param baudrate + * The baudrate to operate at + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code + * pros::Serial serial(1); + * serial.set_baudrate(9600); + * \endcode + */ + virtual std::int32_t set_baudrate(std::int32_t baudrate) const; + + /** + * Clears the internal input and output FIFO buffers. + * + * This can be useful to reset state and remove old, potentially unneeded data + * from the input FIFO buffer or to cancel sending any data in the output FIFO + * buffer. + * + * \note This function does not cause the data in the output buffer to be + * written, it simply clears the internal buffers. Unlike stdout, generic + * serial does not use buffered IO (the FIFO buffers are written as soon + * as possible). + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code + * pros::Serial serial(1); + * serial.flush(); + * \endcode + */ + virtual std::int32_t flush() const; + + /** + * Returns the number of bytes available to be read in the the port's FIFO + * input buffer. + * + * \note This function does not actually read any bytes, is simply returns the + * number of bytes available to be read. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes avaliable to be read or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * if(serial.get_read_avail() > 0) { + * std::uint8_t byte = serial.read_byte(); + * } + * } + * \endcode + */ + virtual std::int32_t get_read_avail() const; + + /** + * Returns the number of bytes free in the port's FIFO output buffer. + * + * \note This function does not actually write any bytes, is simply returns the + * number of bytes free in the port's buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The number of bytes free or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * if(serial.get_write_free() > 0) { + * serial.write_byte(0x01); + * pros::delay(10); + * } + * } + * \endcode + */ + virtual std::int32_t get_write_free() const; + + /** + * Reads the next byte avaliable in the port's input buffer without removing it. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * if(serial.peek_byte() == 0x01) { + * serial.read_byte(); + * } + * } + * \endcode + */ + virtual std::int32_t peek_byte() const; + + /** + * Reads the next byte avaliable in the port's input buffer. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \return The next byte avaliable to be read, -1 if none are available, or + * PROS_ERR if the operation failed, setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * if(serial.read_byte() == 0x01) { + * // Do something + * } + * } + * \endcode + */ + virtual std::int32_t read_byte() const; + + /** + * Reads up to the next length bytes from the port's input buffer and places + * them in the user supplied buffer. + * + * \note This function will only return bytes that are currently avaliable to be + * read and will not block waiting for any to arrive. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * + * \param buffer + * The location to place the data read + * \param length + * The maximum number of bytes to read + * + * \return The number of bytes read or PROS_ERR if the operation failed, setting + * errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * std::uint8_t buffer[10]; + * serial.read(buffer, 10); + * } + * \endcode + */ + virtual std::int32_t read(std::uint8_t* buffer, std::int32_t length) const; + + /** + * Write the given byte to the port's output buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The byte to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * serial.write_byte(0x01); + * } + * \endcode + */ + virtual std::int32_t write_byte(std::uint8_t buffer) const; + + /** + * Writes up to length bytes from the user supplied buffer to the port's output + * buffer. + * + * \note Data in the port's output buffer is written to the serial port as soon + * as possible on a FIFO basis and can not be done manually by the user. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - The given value is not within the range of V5 ports (1-21). + * EACCES - Another resource is currently trying to access the port. + * EIO - Serious internal write error. + * + * \param buffer + * The data to write + * \param length + * The maximum number of bytes to write + * + * \return The number of bytes written or PROS_ERR if the operation failed, + * setting errno. + * + * \b Example: + * \code + * void opcontrol() { + * pros::Serial serial(1); + * std::uint8_t buffer[10]; + * serial.write(buffer, 10); + * } + * \endcode + */ + virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; + + private: + ///@} +}; + +namespace literals { +const pros::Serial operator"" _ser(const unsigned long long int m); +} // namespace literals +} // namespace pros +#endif // _PROS_SERIAL_HPP_ diff --git a/include/pros/vision.h b/include/pros/vision.h new file mode 100644 index 0000000..dbda3fc --- /dev/null +++ b/include/pros/vision.h @@ -0,0 +1,851 @@ +/** + * \file pros/vision.h + * \ingroup c-vision + * + * Contains prototypes for the VEX Vision Sensor-related functions. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup c-vision Vision Sensor C API + * \note Additional example code for this module can be found in its [Tutorial.](@ref vision) + */ + +#ifndef _PROS_VISION_H_ +#define _PROS_VISION_H_ + +/** + * \ingroup c-vision + */ + +/** + * \addtogroup c-vision + * @{ + */ + +/// \name Macros +///Parameters given by VEX +///@{ + +#define VISION_OBJECT_ERR_SIG 255 + +/** + * The width of the Vision Sensor’s field of view. + */ +#define VISION_FOV_WIDTH 316 + +/** + * The height of the Vision Sensor’s field of view. + */ +#define VISION_FOV_HEIGHT 212 + +///@} + +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +/** + * \enum vision_object_type_e_t + * This enumeration defines the different types of objects that can be detected by the Vision Sensor + */ +typedef enum vision_object_type { + E_VISION_OBJECT_NORMAL = 0, + E_VISION_OBJECT_COLOR_CODE = 1, + E_VISION_OBJECT_LINE = 2 +} vision_object_type_e_t; + +/** + * \struct vision_signature_s_t + * This structure contains the parameters used by the Vision Sensor to detect objects. + */ +typedef struct __attribute__((__packed__)) vision_signature { + uint8_t id; + uint8_t _pad[3]; + float range; + int32_t u_min; + int32_t u_max; + int32_t u_mean; + int32_t v_min; + int32_t v_max; + int32_t v_mean; + uint32_t rgb; + uint32_t type; +} vision_signature_s_t; + +/** + * \typedef vision_color_code_t + * Color codes are just signatures with multiple IDs and a different type. + */ +typedef uint16_t vision_color_code_t; + +/** + * \struct vision_object_s_t + * This structure contains a descriptor of an object detected by the Vision Sensor + */ +typedef struct __attribute__((__packed__)) vision_object { + /// Object signature + uint16_t signature; + /// Object type, e.g. normal, color code, or line detection + vision_object_type_e_t type; + /// Left boundary coordinate of the object + int16_t left_coord; + /// Top boundary coordinate of the object + int16_t top_coord; + /// Width of the object + int16_t width; + /// Height of the object + int16_t height; + /// Angle of a color code object in 0.1 degree units (e.g. 10 -> 1 degree, 155 -> 15.5 degrees) + uint16_t angle; + /// Coordinates of the middle of the object (computed from the values above) + int16_t x_middle_coord; + /// Coordinates of the middle of the object (computed from the values above) + int16_t y_middle_coord; +} vision_object_s_t; + +/** + * \enum vision_zero + * This enumeration defines different zero points for returned vision objects. + */ +typedef enum vision_zero { + /// (0,0) coordinate is the top left of the FOV + E_VISION_ZERO_TOPLEFT = 0, + /// (0,0) coordinate is the center of the FOV + E_VISION_ZERO_CENTER = 1 +} vision_zero_e_t; + +#ifdef PROS_USE_SIMPLE_NAMES +#ifdef __cplusplus +#define VISION_OBJECT_NORMAL pros::E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE pros::E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE pros::E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT pros::E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER pros::E_VISION_ZERO_CENTER +#else +#define VISION_OBJECT_NORMAL E_VISION_OBJECT_NORMAL +#define VISION_OBJECT_COLOR_CODE E_VISION_OBJECT_COLOR_CODE +#define VISION_OBJECT_LINE E_VISION_OBJECT_LINE +#define VISION_ZERO_TOPLEFT E_VISION_ZERO_TOPLEFT +#define VISION_ZERO_CENTER E_VISION_ZERO_CENTER +#endif +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/// \name Functions +///@{ + +/** + * Clears the vision sensor LED color, reseting it back to its default behavior, + * displaying the most prominent object signature color. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * void initialize() { + * vision_clear_led(VISION_PORT); + * } + * \endcode + */ +int32_t vision_clear_led(uint8_t port); + +/** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param range + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using vision_set_signature + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * // values acquired from the vision utility + * vision_signature_s_t RED_SIG = + * vision_signature_from_utility(EXAMPLE_SIG, 8973, 11143, 10058, -2119, -1053, -1586, 5.4, 0); + * vision_set_signature(VISION_PORT, EXAMPLE_SIG, &RED_SIG); + * while (true) { + * vision_signature_s_t rtn = vision_get_by_sig(VISION_PORT, 0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ +vision_signature_s_t vision_signature_from_utility(const int32_t id, const int32_t u_min, const int32_t u_max, + const int32_t u_mean, const int32_t v_min, const int32_t v_max, + const int32_t v_mean, const float range, const int32_t type); + +/** + * Creates a color code that represents a combination of the given signature + * IDs. If fewer than 5 signatures are to be a part of the color code, pass 0 + * for the additional function parameters. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param port + * The V5 port number from 1-21 + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { + * vision_color_code_t code1 = vision_create_color_code(VISION_PORT, EXAMPLE_SIG, OTHER_SIG); + * } + * \endcode + */ +vision_color_code_t vision_create_color_code(uint8_t port, const uint32_t sig_id1, const uint32_t sig_id2, + const uint32_t sig_id3, const uint32_t sig_id4, const uint32_t sig_id5); + +/** + * Gets the nth largest object according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EHOSTDOWN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { + * while (true) { + * vision_object_s_t rtn = vision_get_by_size(VISION_PORT, 0); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode + */ +vision_object_s_t vision_get_by_size(uint8_t port, const uint32_t size_id); + +/** + * Gets the nth largest object of the given signature according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * EINVAL - sig_id is outside the range [1-8] + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which an object will be returned. + * + * \return The vision_object_s_t object corresponding to the given signature and + * size_id, or PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * while (true) { + * vision_object_s_t rtn = vision_get_by_sig(VISION_PORT, 0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ +vision_object_s_t vision_get_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id); + +/** + * Gets the nth largest object of the given color code according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { + * vision_color_code_t code1 = vision_create_color_code(VISION_PORT, EXAMPLE_SIG, OTHER_SIG); + * while (true) { + * vision_object_s_t rtn = vision_get_by_code(VISION_PORT, 0, code1); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode + */ +vision_object_s_t vision_get_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code); + +/** + * Gets the exposure parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return The current exposure setting from [0,150], PROS_ERR if an error + * occurred + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * if (vision_get_exposure(VISION_PORT) < 50) + * vision_set_exposure(VISION_PORT, 50); + * } + * \endcode + */ +int32_t vision_get_exposure(uint8_t port); + +/** + * Gets the number of objects currently detected by the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return The number of objects detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { + * while (true) { + * printf("Number of Objects Detected: %d\n", vision_get_object_count(VISION_PORT)); + * delay(2); + * } + * } + * \endcode + */ +int32_t vision_get_object_count(uint8_t port); + +/** + * Get the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * + * \return The current RGB white balance setting of the sensor + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define VISION_WHITE 0xff + * + * void initialize() { + * if (vision_get_white_balance(VISION_PORT) != VISION_WHITE) + * vision_set_white_balance(VISION_PORT, VISION_WHITE); + * } + * \endcode + */ +int32_t vision_get_white_balance(uint8_t port); + +/** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * vision_signature_s_t sig = vision_get_signature(VISION_PORT, EXAMPLE_SIG); + * vision_print_signature(sig); + * } + * \endcode + */ +int32_t vision_print_signature(const vision_signature_s_t sig); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_read_by_size(VISION_PORT, 0, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints the signature of the largest object found + * delay(2); + * } + * } + * \endcode + */ +int32_t vision_read_by_size(uint8_t port, const uint32_t size_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The signature ID [1-7] for which objects will be returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_read_by_sig(VISION_PORT, 0, EXAMPLE_SIG, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ +int32_t vision_read_by_sig(uint8_t port, const uint32_t size_id, const uint32_t sig_id, const uint32_t object_count, + vision_object_s_t* const object_arr); + +/** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21), or + * fewer than object_count number of objects were found. + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * vision_color_code_t code1 = vision_create_color_code(VISION_PORT, EXAMPLE_SIG, OTHER_SIG, 0, 0, 0); + * while (true) { + * vision_read_by_code(VISION_PORT, 0, code1, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints the signature of the largest object found + * delay(2); + * } + * } + * \endcode + */ +int32_t vision_read_by_code(uint8_t port, const uint32_t size_id, const vision_color_code_t color_code, + const uint32_t object_count, vision_object_s_t* const object_arr); + +/** + * Gets the object detection signature with the given id number. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * vision_signature_s_t sig = vision_get_signature(VISION_PORT, EXAMPLE_SIG); + * vision_print_signature(sig); + * } + * \endcode + */ +vision_signature_s_t vision_get_signature(uint8_t port, const uint8_t signature_id); + +/** + * Stores the supplied object detection signature onto the vision sensor. + * + * \note This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * \param port + * The V5 port number from 1-21 + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * vision_signature_s_t sig = vision_get_signature(VISION_PORT, EXAMPLE_SIG); + * sig.range = 10.0; + * vision_set_signature(VISION_PORT, EXAMPLE_SIG, &sig); + * } + * \endcode + */ +int32_t vision_set_signature(uint8_t port, const uint8_t signature_id, vision_signature_s_t* const signature_ptr); + +/** + * Enables/disables auto white-balancing on the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * EINVAL - enable was not 0 or 1 + * + * \param port + * The V5 port number from 1-21 + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * vision_set_auto_white_balance(VISION_PORT, true); + * } + * \endcode + */ +int32_t vision_set_auto_white_balance(uint8_t port, const uint8_t enable); + +/** + * Sets the exposure parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param percent + * The new exposure setting from [0,150] + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * if (vision_get_exposure(VISION_PORT) < 50) + * vision_set_exposure(VISION_PORT, 50); + * } + * \endcode + */ +int32_t vision_set_exposure(uint8_t port, const uint8_t exposure); + +/** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * vision_set_led(VISION_PORT, COLOR_BLANCHED_ALMOND); + * } + * \endcode + */ +int32_t vision_set_led(uint8_t port, const int32_t rgb); + +/** + * Sets the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define VISION_WHITE 0xff + * + * void initialize() { + * vision_set_white_balance(VISION_PORT, VISION_WHITE); + * } + * \endcode + */ +int32_t vision_set_white_balance(uint8_t port, const int32_t rgb); + +/** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * vision_set_zero_point(VISION_PORT, E_VISION_ZERO_CENTER); + * } + * \endcode + */ +int32_t vision_set_zero_point(uint8_t port, vision_zero_e_t zero_point); + +/** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENXIO - The given port is not within the range of V5 ports (1-21) + * EACCESS - Anothe resources is currently trying to access the port + * + * \param port + * The V5 port number from 1-21 + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * vision_set_wifi_mode(VISION_PORT, 0); + * } + * \endcode + */ +int32_t vision_set_wifi_mode(uint8_t port, const uint8_t enable); + +///@} + +///@} + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif + +#endif // _PROS_VISION_H_ diff --git a/include/pros/vision.hpp b/include/pros/vision.hpp new file mode 100644 index 0000000..b867679 --- /dev/null +++ b/include/pros/vision.hpp @@ -0,0 +1,733 @@ +/** + * \file pros/vision.hpp + * \ingroup cpp-vision + * + * Contains prototypes for the VEX Vision Sensor-related functions in C++. + * + * This file should not be modified by users, since it gets replaced whenever + * a kernel upgrade occurs. + * + * \copyright (c) 2017-2023, Purdue University ACM SIGBots. + * All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \defgroup cpp-vision Vision Sensor C++ API + * \note Additional example code for this module can be found in its [Tutorial.](@ref vision) + */ + +#ifndef _PROS_VISION_HPP_ +#define _PROS_VISION_HPP_ + +#include + +#include "pros/vision.h" + +namespace pros { +inline namespace v5 { +/** + * \ingroup cpp-vision + */ +class Vision : public Device { + /** + * \addtogroup cpp-vision + * @{ + */ + public: + /** + * Create a Vision Sensor object on the given port. + * + * This function uses the following values of errno when an error state is + * reached: + * ENXIO - The given value is not within the range of V5 ports (1-21). + * ENODEV - The port cannot be configured as a vision sensor + * + * \param port + * The V5 port number from 1-21 + * \param zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \b Example + * \code + * void opcontrol() { + * pros::Vision vision_sensor(1); // Creates a vision sensor on port one, with the zero point set to top left + * } + * \endcode + */ + explicit Vision(std::uint8_t port, vision_zero_e_t zero_point = E_VISION_ZERO_TOPLEFT); + + /** + * Clears the vision sensor LED color, reseting it back to its default + * behavior, displaying the most prominent object signature color. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * void initialize() { + * pros::Vision vision_sensor(1); + * vision_sensor.clear_led(); + * } + * \endcode + */ + std::int32_t clear_led(void) const; + + /** + * Creates a signature from the vision sensor utility + * + * \param id + * The signature ID + * \param u_min + * Minimum value on U axis + * \param u_max + * Maximum value on U axis + * \param u_mean + * Mean value on U axis + * \param v_min + * Minimum value on V axis + * \param v_max + * Maximum value on V axis + * \param v_mean + * Mean value on V axis + * \param rgb + * Scale factor + * \param type + * Signature type + * + * \return A vision_signature_s_t that can be set using Vision::set_signature + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * // values acquired from the vision utility + * vision_signature_s_t RED_SIG = + * vision_signature_from_utility(EXAMPLE_SIG, 8973, 11143, 10058, -2119, -1053, -1586, 5.4, 0); + * vision_sensor.set_signature(EXAMPLE_SIG, &RED_SIG); + * while (true) { + * vision_signature_s_t rtn = vision_sensor.get_by_sig(VISION_PORT, 0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ + static vision_signature_s_t signature_from_utility(const std::int32_t id, const std::int32_t u_min, + const std::int32_t u_max, const std::int32_t u_mean, + const std::int32_t v_min, const std::int32_t v_max, + const std::int32_t v_mean, const float range, + const std::int32_t type); + + /** + * Creates a color code that represents a combination of the given signature + * IDs. + * + * This function uses the following values of errno when an error state is + * reached: + * EINVAL - Fewer than two signatures have been provided or one of the + * signatures is out of its [1-7] range (or 0 when omitted). + * + * \param sig_id1 + * The first signature id [1-7] to add to the color code + * \param sig_id2 + * The second signature id [1-7] to add to the color code + * \param sig_id3 + * The third signature id [1-7] to add to the color code + * \param sig_id4 + * The fourth signature id [1-7] to add to the color code + * \param sig_id5 + * The fifth signature id [1-7] to add to the color code + * + * \return A vision_color_code_t object containing the color code information. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); + * } + * \endcode + */ + vision_color_code_t create_color_code(const std::uint32_t sig_id1, const std::uint32_t sig_id2, + const std::uint32_t sig_id3 = 0, const std::uint32_t sig_id4 = 0, + const std::uint32_t sig_id5 = 0) const; + + /** + * Gets the nth largest object according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * + * \return The vision_object_s_t object corresponding to the given size id, or + * PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_size(0); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode + */ + vision_object_s_t get_by_size(const std::uint32_t size_id) const; + + /** + * Gets the nth largest object of the given signature according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * + * \return The vision_object_s_t object corresponding to the given signature + * and size_id, or PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_sig(0, EXAMPLE_SIG); + * // Gets the largest object of the EXAMPLE_SIG signature + * printf("sig: %d", rtn.signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ + vision_object_s_t get_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id) const; + + /** + * Gets the nth largest object of the given color code according to size_id. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the Vision Sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which an object will be returned + * + * \return The vision_object_s_t object corresponding to the given color code + * and size_id, or PROS_ERR if an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG); + * while (true) { + * vision_object_s_t rtn = vision_sensor.get_by_code(0, code1); + * // Gets the largest object + * printf("sig: %d", rtn.signature); + * delay(2); + * } + * } + * \endcode + */ + vision_object_s_t get_by_code(const std::uint32_t size_id, const vision_color_code_t color_code) const; + + /** + * Gets the exposure parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current exposure parameter from [0,150], + * PROS_ERR if an error occurred + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * if (vision_sensor.get_exposure() < 50) + * vision_sensor.set_exposure(50); + * } + * \endcode + */ + std::int32_t get_exposure(void) const; + + /** + * Gets the number of objects currently detected by the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The number of objects detected on the specified vision sensor. + * Returns PROS_ERR if the port was invalid or an error occurred. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * while (true) { + * printf("Number of Objects Detected: %d\n", vision_sensor.get_object_count()); + * delay(2); + * } + * } + * \endcode + */ + std::int32_t get_object_count(void) const; + + /** + * Gets the object detection signature with the given id number. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param signature_id + * The signature id to read + * + * \return A vision_signature_s_t containing information about the signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_signature_s_t sig = vision_sensor.get_signature(EXAMPLE_SIG); + * vision_sensor.print_signature(sig); + * } + * \endcode + */ + vision_signature_s_t get_signature(const std::uint8_t signature_id) const; + + /** + * Get the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \return The current RGB white balance setting of the sensor + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define VISION_WHITE 0xff + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * if (vision_sensor.get_white_balance() != VISION_WHITE) + * vision_sensor.set_white_balance(VISION_WHITE); + * } + * \endcode + */ + std::int32_t get_white_balance(void) const; + + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param object_count + * The number of objects to read + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_sensor.read_by_size(0, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints the signature of the largest object found + * delay(2); + * } + * } + * \endcode + */ + std::int32_t read_by_size(const std::uint32_t size_id, const std::uint32_t object_count, + vision_object_s_t* const object_arr) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EDOM - size_id is greater than the number of available objects. + * EINVAL - sig_id is outside the range [1-8] + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param signature + * The vision_signature_s_t signature for which an object will be + * returned. + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * while (true) { + * vision_sensor.read_by_sig(0, EXAMPLE_SIG, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints "sig: 1" + * delay(2); + * } + * } + * \endcode + */ + std::int32_t read_by_sig(const std::uint32_t size_id, const std::uint32_t sig_id, const std::uint32_t object_count, + vision_object_s_t* const object_arr) const; + + /** + * Reads up to object_count object descriptors into object_arr. + * + * This function uses the following values of errno when an error state is + * reached: + * EDOM - size_id is greater than the number of available objects. + * ENODEV - The port cannot be configured as a vision sensor + * EAGAIN - Reading the vision sensor failed for an unknown reason. + * + * \param object_count + * The number of objects to read + * \param size_id + * The object to read from a list roughly ordered by object size + * (0 is the largest item, 1 is the second largest, etc.) + * \param color_code + * The vision_color_code_t for which objects will be returned + * \param[out] object_arr + * A pointer to copy the objects into + * + * \return The number of object signatures copied. This number will be less than + * object_count if there are fewer objects detected by the vision sensor. + * Returns PROS_ERR if the port was invalid, an error occurred, or fewer objects + * than size_id were found. All objects in object_arr that were not found are + * given VISION_OBJECT_ERR_SIG as their signature. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * #define OTHER_SIG 2 + * #define NUM_VISION_OBJECTS 4 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_object_s_t object_arr[NUM_VISION_OBJECTS]; + * vision_color_code_t code1 = vision_sensor.create_color_code(EXAMPLE_SIG, OTHER_SIG, 0, 0, 0); + * while (true) { + * vision_sensor.read_by_code(0, code1, NUM_VISION_OBJECTS, object_arr); + * printf("sig: %d", object_arr[0].signature); + * // Prints the signature of the largest object found + * delay(2); + * } + * } + * \endcode + */ + int32_t read_by_code(const std::uint32_t size_id, const vision_color_code_t color_code, + const std::uint32_t object_count, vision_object_s_t* const object_arr) const; + + /** + * Prints the contents of the signature as an initializer list to the terminal. + * + * \param sig + * The signature for which the contents will be printed + * + * \return 1 if no errors occured, PROS_ERR otherwise + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_signature_s_t sig = visionsensor.get_signature(EXAMPLE_SIG); + * vision_print_signature(sig); + * } + * \endcode + */ + static std::int32_t print_signature(const vision_signature_s_t sig); + + /** + * Enables/disables auto white-balancing on the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enabled + * Pass 0 to disable, 1 to enable + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_sensor.set_auto_white_balance(true); + * } + * \endcode + */ + std::int32_t set_auto_white_balance(const std::uint8_t enable) const; + + /** + * Sets the exposure parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param percent + * The new exposure setting from [0,150]. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * if (vision_sensor.get_exposure() < 50) + * vision_sensor.set_exposure(50); + * } + * \endcode + */ + std::int32_t set_exposure(const std::uint8_t exposure) const; + + /** + * Sets the vision sensor LED color, overriding the automatic behavior. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * An RGB code to set the LED to + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_sensor.set_led(COLOR_BLANCHED_ALMOND); + * } + * \endcode + */ + std::int32_t set_led(const std::int32_t rgb) const; + + /** + * Stores the supplied object detection signature onto the vision sensor. + * + * NOTE: This saves the signature in volatile memory, and the signature will be + * lost as soon as the sensor is powered down. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * EINVAL - sig_id is outside the range [1-8] + * + * \param signature_id + * The signature id to store into + * \param[in] signature_ptr + * A pointer to the signature to save + * + * \return 1 if no errors occured, PROS_ERR otherwise + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define EXAMPLE_SIG 1 + * + * void opcontrol() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_signature_s_t sig = vision_sensor.get_signature(EXAMPLE_SIG); + * sig.range = 10.0; + * vision_sensor.set_signature(EXAMPLE_SIG, &sig); + * } + * \endcode + */ + std::int32_t set_signature(const std::uint8_t signature_id, vision_signature_s_t* const signature_ptr) const; + + /** + * Sets the white balance parameter of the Vision Sensor. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param rgb + * The new RGB white balance setting of the sensor + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * #define VISION_WHITE 0xff + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_sensor.set_white_balance(VISION_WHITE); + * } + * \endcode + */ + std::int32_t set_white_balance(const std::int32_t rgb) const; + + /** + * Sets the (0,0) coordinate for the Field of View. + * + * This will affect the coordinates returned for each request for a + * vision_object_s_t from the sensor, so it is recommended that this function + * only be used to configure the sensor at the beginning of its use. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param zero_point + * One of vision_zero_e_t to set the (0,0) coordinate for the FOV + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_sensor.set_zero_point(E_VISION_ZERO_CENTER); + * } + * \endcode + */ + std::int32_t set_zero_point(vision_zero_e_t zero_point) const; + + /** + * Sets the Wi-Fi mode of the Vision sensor + * + * This functions uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a vision sensor + * + * \param enable + * Disable Wi-Fi on the Vision sensor if 0, enable otherwise (e.g. 1) + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + * + * \b Example + * \code + * #define VISION_PORT 1 + * + * void initialize() { + * pros::Vision vision_sensor(VISION_PORT); + * vision_sensor.set_wifi_mode(0); + * } + * \endcode + */ + std::int32_t set_wifi_mode(const std::uint8_t enable) const; + + private: + ///@} +}; +} // namespace v5 +} // namespace pros +#endif // _PROS_VISION_HPP_ diff --git a/project.pros b/project.pros new file mode 100644 index 0000000..cb89b4f --- /dev/null +++ b/project.pros @@ -0,0 +1,405 @@ +{ + "py/object": "pros.conductor.project.Project", + "py/state": { + "project_name": "Sharpsoft", + "target": "v5", + "templates": { + "kernel": { + "location": "C:\\Users\\kyley\\AppData\\Roaming\\PROS\\templates\\kernel@4.0.6", + "metadata": { + "cold_addr": "58720256", + "cold_output": "bin/cold.package.bin", + "hot_addr": "125829120", + "hot_output": "bin/hot.package.bin", + "origin": "kernel-beta-mainline", + "output": "bin/monolith.bin" + }, + "name": "kernel", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": null, + "system_files": [ + "firmware\\v5.ld", + "include\\pros\\colors.h", + "include\\pros\\distance.hpp", + "include\\pros\\llemu.hpp", + "firmware\\libm.a", + "include\\pros\\motor_group.hpp", + "include\\pros\\serial.hpp", + "common.mk", + "include\\pros\\device.hpp", + "include\\pros\\screen.hpp", + "include\\pros\\abstract_motor.hpp", + "include\\pros\\gps.h", + "include\\pros\\colors.hpp", + "include\\pros\\adi.h", + "include\\pros\\screen.h", + "include\\pros\\rotation.hpp", + "firmware\\v5-hot.ld", + "include\\pros\\link.h", + "include\\pros\\rotation.h", + "include\\api.h", + "include\\pros\\ext_adi.h", + "include\\pros\\device.h", + "include\\pros\\motors.hpp", + "firmware\\v5-common.ld", + "include\\pros\\apix.h", + "include\\pros\\rtos.hpp", + "include\\pros\\vision.hpp", + "include\\pros\\vision.h", + "include\\pros\\gps.hpp", + "include\\pros\\motors.h", + "include\\pros\\rtos.h", + "include\\pros\\imu.hpp", + "include\\pros\\llemu.h", + "include\\pros\\distance.h", + "firmware\\libc.a", + "include\\pros\\misc.hpp", + "include\\pros\\error.h", + "include\\pros\\serial.h", + "firmware\\libpros.a", + "include\\pros\\optical.h", + "include\\pros\\optical.hpp", + "include\\pros\\misc.h", + "include\\pros\\imu.h", + "include\\pros\\adi.hpp", + "include\\pros\\link.hpp" + ], + "target": "v5", + "user_files": [ + "include\\main.hpp", + ".gitignore", + "include\\main.h", + "src\\main.cpp", + "Makefile", + "include\\main.hh", + "src\\main.c", + "src\\main.cc" + ], + "version": "4.0.6" + }, + "liblvgl": { + "location": "C:\\Users\\kyley\\AppData\\Roaming\\PROS\\templates\\liblvgl@8.3.7", + "metadata": { + "origin": "kernel-beta-mainline" + }, + "name": "liblvgl", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": ">=4.0.0", + "system_files": [ + "include\\liblvgl\\draw\\lv_draw_line.h", + "include\\liblvgl\\draw\\lv_draw_triangle.h", + "include\\liblvgl\\extra\\others\\gridnav\\lv_gridnav.h", + "include\\liblvgl\\extra\\others\\ime\\lv_ime_pinyin.h", + "include\\liblvgl\\widgets\\lv_slider.h", + "include\\liblvgl\\extra\\libs\\freetype\\lv_freetype.h", + "include\\liblvgl\\extra\\widgets\\span\\lv_span.h", + "include\\liblvgl\\misc\\lv_assert.h", + "include\\liblvgl\\misc\\lv_async.h", + "include\\liblvgl\\widgets\\lv_line.h", + "include\\liblvgl\\core\\lv_indev_scroll.h", + "include\\liblvgl\\draw\\sw\\lv_draw_sw_dither.h", + "include\\liblvgl\\extra\\widgets\\spinner\\lv_spinner.h", + "include\\liblvgl\\extra\\others\\monkey\\lv_monkey.h", + "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_blend.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl.h", + "include\\liblvgl\\extra\\libs\\png\\lv_png.h", + "include\\liblvgl\\widgets\\lv_label.h", + "include\\liblvgl\\widgets\\lv_btnmatrix.h", + "include\\liblvgl\\extra\\layouts\\lv_layouts.h", + "include\\liblvgl\\extra\\libs\\gif\\gifdec.h", + "include\\liblvgl\\extra\\widgets\\list\\lv_list.h", + "include\\liblvgl\\draw\\lv_draw_label.h", + "include\\liblvgl\\extra\\others\\snapshot\\lv_snapshot.h", + "include\\liblvgl\\draw\\lv_draw_arc.h", + "include\\liblvgl\\extra\\themes\\lv_themes.h", + "include\\liblvgl\\extra\\widgets\\msgbox\\lv_msgbox.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_layer.h", + "include\\liblvgl\\lv_version.h", + "include\\liblvgl\\font\\lv_font_fmt_txt.h", + "include\\liblvgl\\core\\lv_disp.h", + "include\\liblvgl\\draw\\sw\\lv_draw_sw.h", + "include\\liblvgl\\core\\lv_obj_class.h", + "include\\liblvgl\\extra\\others\\imgfont\\lv_imgfont.h", + "include\\liblvgl\\extra\\themes\\basic\\lv_theme_basic.h", + "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar.h", + "include\\liblvgl\\misc\\lv_anim.h", + "include\\liblvgl\\misc\\lv_utils.h", + "include\\liblvgl\\misc\\lv_style.h", + "include\\liblvgl\\draw\\nxp\\pxp\\lv_gpu_nxp_pxp.h", + "include\\liblvgl\\widgets\\lv_objx_templ.h", + "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_rect.h", + "include\\liblvgl\\extra\\layouts\\grid\\lv_grid.h", + "include\\liblvgl\\lv_conf_kconfig.h", + "include\\liblvgl\\draw\\lv_img_decoder.h", + "include\\liblvgl\\hal\\lv_hal_disp.h", + "include\\liblvgl\\llemu.hpp", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_priv.h", + "include\\liblvgl\\draw\\sw\\lv_draw_sw_gradient.h", + "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar_header_arrow.h", + "include\\liblvgl\\extra\\widgets\\calendar\\lv_calendar_header_dropdown.h", + "include\\liblvgl\\core\\lv_obj.h", + "include\\liblvgl\\extra\\libs\\sjpg\\lv_sjpg.h", + "include\\liblvgl\\extra\\widgets\\lv_widgets.h", + "include\\liblvgl\\lvgl.h", + "include\\liblvgl\\draw\\lv_img_buf.h", + "include\\liblvgl\\extra\\widgets\\spinbox\\lv_spinbox.h", + "include\\liblvgl\\draw\\nxp\\vglite\\lv_gpu_nxp_vglite.h", + "include\\liblvgl\\draw\\lv_draw_rect.h", + "include\\liblvgl\\draw\\lv_img_cache.h", + "include\\liblvgl\\extra\\libs\\sjpg\\tjpgd.h", + "include\\liblvgl\\draw\\sw\\lv_draw_sw_blend.h", + "include\\liblvgl\\extra\\others\\fragment\\lv_fragment.h", + "include\\liblvgl\\widgets\\lv_dropdown.h", + "include\\liblvgl\\draw\\lv_draw_layer.h", + "include\\liblvgl\\extra\\libs\\qrcode\\qrcodegen.h", + "include\\liblvgl\\core\\lv_obj_style_gen.h", + "include\\liblvgl\\core\\lv_theme.h", + "include\\liblvgl\\widgets\\lv_arc.h", + "include\\liblvgl\\extra\\widgets\\tileview\\lv_tileview.h", + "include\\liblvgl\\llemu.h", + "include\\liblvgl\\misc\\lv_tlsf.h", + "include\\liblvgl\\misc\\lv_log.h", + "include\\liblvgl\\extra\\libs\\fsdrv\\lv_fsdrv.h", + "include\\liblvgl\\misc\\lv_ll.h", + "include\\liblvgl\\widgets\\lv_btn.h", + "include\\liblvgl\\misc\\lv_area.h", + "include\\liblvgl\\misc\\lv_fs.h", + "include\\liblvgl\\extra\\libs\\gif\\lv_gif.h", + "include\\liblvgl\\misc\\lv_txt_ap.h", + "include\\liblvgl\\draw\\stm32_dma2d\\lv_gpu_stm32_dma2d.h", + "include\\liblvgl\\misc\\lv_style_gen.h", + "include\\liblvgl\\widgets\\lv_canvas.h", + "include\\liblvgl\\font\\lv_font_loader.h", + "firmware\\liblvgl.a", + "include\\liblvgl\\core\\lv_obj_scroll.h", + "include\\liblvgl\\core\\lv_indev.h", + "include\\liblvgl\\extra\\libs\\ffmpeg\\lv_ffmpeg.h", + "include\\liblvgl\\extra\\widgets\\imgbtn\\lv_imgbtn.h", + "include\\liblvgl\\core\\lv_obj_pos.h", + "include\\liblvgl\\core\\lv_obj_style.h", + "include\\liblvgl\\widgets\\lv_table.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_stack_blur.h", + "include\\liblvgl\\lv_conf_internal.h", + "include\\liblvgl\\misc\\lv_timer.h", + "include\\liblvgl\\core\\lv_obj_draw.h", + "include\\liblvgl\\draw\\nxp\\lv_gpu_nxp.h", + "include\\liblvgl\\extra\\widgets\\win\\lv_win.h", + "include\\liblvgl\\extra\\others\\msg\\lv_msg.h", + "include\\liblvgl\\extra\\libs\\lv_libs.h", + "include\\liblvgl\\widgets\\lv_bar.h", + "include\\liblvgl\\extra\\others\\lv_others.h", + "include\\liblvgl\\misc\\lv_math.h", + "include\\liblvgl\\widgets\\lv_img.h", + "include\\liblvgl\\lv_conf_checker.h", + "include\\liblvgl\\misc\\lv_mem.h", + "include\\liblvgl\\widgets\\lv_textarea.h", + "include\\liblvgl\\lv_conf.h", + "include\\liblvgl\\extra\\widgets\\keyboard\\lv_keyboard.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_mask.h", + "include\\liblvgl\\draw\\lv_draw_mask.h", + "include\\liblvgl\\core\\lv_obj_tree.h", + "include\\liblvgl\\extra\\themes\\default\\lv_theme_default.h", + "include\\liblvgl\\extra\\lv_extra.h", + "include\\liblvgl\\extra\\widgets\\colorwheel\\lv_colorwheel.h", + "include\\liblvgl\\core\\lv_group.h", + "include\\liblvgl\\hal\\lv_hal_indev.h", + "include\\liblvgl\\draw\\nxp\\vglite\\lv_draw_vglite_arc.h", + "include\\liblvgl\\draw\\arm2d\\lv_gpu_arm2d.h", + "include\\liblvgl\\widgets\\lv_checkbox.h", + "include\\liblvgl\\draw\\swm341_dma2d\\lv_gpu_swm341_dma2d.h", + "include\\liblvgl\\extra\\themes\\mono\\lv_theme_mono.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_img.h", + "include\\liblvgl\\misc\\lv_bidi.h", + "include\\liblvgl\\misc\\lv_txt.h", + "include\\liblvgl\\extra\\widgets\\led\\lv_led.h", + "include\\liblvgl\\extra\\libs\\rlottie\\lv_rlottie.h", + "include\\liblvgl\\misc\\lv_printf.h", + "include\\liblvgl\\font\\lv_font.h", + "include\\liblvgl\\core\\lv_refr.h", + "include\\liblvgl\\lv_api_map.h", + "include\\liblvgl\\misc\\lv_color.h", + "include\\liblvgl\\misc\\lv_gc.h", + "include\\liblvgl\\misc\\lv_templ.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_composite.h", + "include\\liblvgl\\hal\\lv_hal_tick.h", + "include\\liblvgl\\misc\\lv_types.h", + "include\\liblvgl\\draw\\nxp\\pxp\\lv_draw_pxp_blend.h", + "include\\liblvgl\\draw\\lv_draw.h", + "include\\liblvgl\\extra\\libs\\bmp\\lv_bmp.h", + "include\\liblvgl\\extra\\libs\\qrcode\\lv_qrcode.h", + "include\\liblvgl\\extra\\widgets\\meter\\lv_meter.h", + "include\\liblvgl\\font\\lv_symbol_def.h", + "include\\liblvgl\\extra\\layouts\\flex\\lv_flex.h", + "include\\liblvgl\\widgets\\lv_roller.h", + "include\\liblvgl\\draw\\lv_draw_transform.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_utils.h", + "include\\liblvgl\\lv_conf.old.h", + "include\\liblvgl\\misc\\lv_anim_timeline.h", + "include\\liblvgl\\misc\\lv_lru.h", + "include\\liblvgl\\hal\\lv_hal.h", + "include\\liblvgl\\extra\\libs\\sjpg\\tjpgdcnf.h", + "include\\liblvgl\\extra\\widgets\\tabview\\lv_tabview.h", + "include\\liblvgl\\extra\\widgets\\menu\\lv_menu.h", + "include\\liblvgl\\extra\\widgets\\animimg\\lv_animimg.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_texture_cache.h", + "include\\liblvgl\\draw\\sdl\\lv_draw_sdl_rect.h", + "include\\liblvgl\\extra\\widgets\\chart\\lv_chart.h", + "include\\liblvgl\\core\\lv_event.h", + "include\\liblvgl\\draw\\lv_draw_img.h", + "include\\liblvgl\\widgets\\lv_switch.h", + "include\\liblvgl\\draw\\nxp\\pxp\\lv_gpu_nxp_pxp_osa.h", + "include\\liblvgl\\extra\\libs\\png\\lodepng.h" + ], + "target": "v5", + "user_files": [], + "version": "8.3.7" + }, + "okapilib": { + "location": "C:\\Users\\kyley\\AppData\\Roaming\\PROS\\templates\\okapilib@5.0.0", + "metadata": { + "origin": "kernel-beta-mainline" + }, + "name": "okapilib", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": "^4.0.3", + "system_files": [ + "include/okapi/api/units/QFrequency.hpp", + "include/okapi/api/control/iterative/iterativePosPidController.hpp", + "include/okapi/impl/util/configurableTimeUtilFactory.hpp", + "include/okapi/api/filter/passthroughFilter.hpp", + "include/okapi/api/coreProsAPI.hpp", + "include/okapi/squiggles/math/quinticpolynomial.hpp", + "firmware/okapilib.a", + "include/okapi/api/util/abstractTimer.hpp", + "include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp", + "include/okapi/squiggles/geometry/pose.hpp", + "include/okapi/api/control/util/pathfinderUtil.hpp", + "include/okapi/squiggles/constraints.hpp", + "include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp", + "include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp", + "include/okapi/api/control/async/asyncVelIntegratedController.hpp", + "include/okapi/api/units/RQuantity.hpp", + "include/okapi/api/units/QArea.hpp", + "include/okapi/api/units/QAngularJerk.hpp", + "include/okapi/api/odometry/twoEncoderOdometry.hpp", + "include/okapi/api/chassis/model/skidSteerModel.hpp", + "include/okapi/impl/util/timeUtilFactory.hpp", + "include/okapi/impl/device/rotarysensor/rotationSensor.hpp", + "include/okapi/api/control/async/asyncController.hpp", + "include/okapi/api/chassis/model/chassisModel.hpp", + "include/okapi/api/chassis/controller/odomChassisController.hpp", + "include/okapi/api/control/iterative/iterativePositionController.hpp", + "include/okapi/api/odometry/threeEncoderOdometry.hpp", + "include/okapi/impl/device/controllerUtil.hpp", + "include/okapi/api/device/rotarysensor/rotarySensor.hpp", + "include/okapi/api/chassis/controller/chassisControllerPid.hpp", + "include/okapi/impl/device/controller.hpp", + "include/okapi/squiggles/physicalmodel/physicalmodel.hpp", + "include/okapi/api/control/iterative/iterativeVelPidController.hpp", + "include/okapi/impl/device/distanceSensor.hpp", + "include/okapi/impl/filter/velMathFactory.hpp", + "include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp", + "include/okapi/squiggles/math/utils.hpp", + "include/okapi/api/util/abstractRate.hpp", + "include/okapi/api/util/supplier.hpp", + "include/okapi/api/chassis/controller/chassisController.hpp", + "include/okapi/api/odometry/stateMode.hpp", + "include/okapi/impl/util/timer.hpp", + "include/okapi/api/filter/ekfFilter.hpp", + "include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp", + "include/okapi/api/units/QVolume.hpp", + "include/okapi/api/chassis/controller/chassisScales.hpp", + "firmware/squiggles.mk", + "include/okapi/impl/device/motor/motor.hpp", + "include/okapi/api/odometry/odomMath.hpp", + "include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp", + "include/okapi/api/control/async/asyncMotionProfileController.hpp", + "include/okapi/api/chassis/model/hDriveModel.hpp", + "include/okapi/api/units/QJerk.hpp", + "include/okapi/impl/util/rate.hpp", + "include/okapi/api/control/offsettableControllerInput.hpp", + "include/okapi/squiggles/geometry/profilepoint.hpp", + "include/okapi/impl/device/rotarysensor/potentiometer.hpp", + "include/okapi/api/units/QAngularSpeed.hpp", + "include/okapi/squiggles/spline.hpp", + "include/okapi/api/odometry/odometry.hpp", + "include/okapi/api/util/timeUtil.hpp", + "include/okapi/squiggles/geometry/controlvector.hpp", + "include/okapi/api/control/util/flywheelSimulator.hpp", + "include/okapi/api/control/util/pidTuner.hpp", + "include/okapi/impl/device/motor/adiMotor.hpp", + "include/okapi/api/chassis/model/xDriveModel.hpp", + "include/okapi/api/units/QSpeed.hpp", + "include/okapi/api/odometry/point.hpp", + "include/okapi/api/filter/composableFilter.hpp", + "include/okapi/impl/device/adiUltrasonic.hpp", + "include/okapi/api/filter/averageFilter.hpp", + "include/okapi/api/units/QAngularAcceleration.hpp", + "include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp", + "include/okapi/api/control/util/controllerRunner.hpp", + "include/okapi/api/device/button/buttonBase.hpp", + "include/okapi/squiggles/squiggles.hpp", + "include/okapi/squiggles/physicalmodel/tankmodel.hpp", + "include/okapi/api/units/QMass.hpp", + "include/okapi/api/util/mathUtil.hpp", + "include/okapi/api/control/controllerOutput.hpp", + "include/okapi/impl/control/util/pidTunerFactory.hpp", + "include/okapi/api/filter/emaFilter.hpp", + "include/okapi/impl/control/iterative/iterativeControllerFactory.hpp", + "include/okapi/api/filter/filter.hpp", + "include/okapi/api/control/controllerInput.hpp", + "include/okapi/api/units/QForce.hpp", + "include/okapi/impl/device/rotarysensor/IMU.hpp", + "include/okapi/api/control/async/asyncLinearMotionProfileController.hpp", + "include/okapi/impl/device/button/controllerButton.hpp", + "include/okapi/squiggles/io.hpp", + "include/okapi/api/chassis/controller/defaultOdomChassisController.hpp", + "include/okapi/api/control/closedLoopController.hpp", + "include/okapi/api/control/iterative/iterativeVelocityController.hpp", + "include/okapi/impl/control/util/controllerRunnerFactory.hpp", + "include/okapi/api/units/RQuantityName.hpp", + "include/okapi/api/filter/filteredControllerInput.hpp", + "include/okapi/impl/control/async/asyncVelControllerBuilder.hpp", + "include/okapi/api/units/QAcceleration.hpp", + "include/okapi/api/control/async/asyncWrapper.hpp", + "include/okapi/api/util/logging.hpp", + "include/okapi/api/units/QTime.hpp", + "include/okapi/api/control/async/asyncPositionController.hpp", + "include/okapi/impl/device/button/adiButton.hpp", + "include/okapi/api/units/QPressure.hpp", + "include/okapi/impl/device/rotarysensor/adiEncoder.hpp", + "include/okapi/impl/device/motor/motorGroup.hpp", + "include/okapi/api/units/QLength.hpp", + "include/okapi/api.hpp", + "include/okapi/api/units/QAngle.hpp", + "include/okapi/impl/control/async/asyncPosControllerBuilder.hpp", + "include/okapi/api/filter/medianFilter.hpp", + "include/okapi/api/control/async/asyncPosPidController.hpp", + "include/okapi/api/control/async/asyncVelPidController.hpp", + "include/okapi/api/control/async/asyncVelocityController.hpp", + "include/okapi/impl/device/rotarysensor/adiGyro.hpp", + "include/okapi/impl/device/rotarysensor/integratedEncoder.hpp", + "include/okapi/api/device/button/abstractButton.hpp", + "include/okapi/squiggles/physicalmodel/passthroughmodel.hpp", + "include/okapi/api/filter/demaFilter.hpp", + "include/okapi/api/device/motor/abstractMotor.hpp", + "include/okapi/impl/device/opticalSensor.hpp", + "include/okapi/api/control/async/asyncPosIntegratedController.hpp", + "include/okapi/api/filter/velMath.hpp", + "include/okapi/api/control/iterative/iterativeController.hpp", + "include/okapi/api/odometry/odomState.hpp", + "include/okapi/api/chassis/model/readOnlyChassisModel.hpp", + "include/okapi/api/control/util/settledUtil.hpp", + "include/okapi/api/units/QTorque.hpp" + ], + "target": "v5", + "user_files": [], + "version": "5.0.0" + } + }, + "upload_options": { + "description": "Demo project for Sharpsoft. Currently contains the library's code. May be moved elsewhere in the future." + }, + "use_early_access": true + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b332322 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,15 @@ +#include "main.h" + +void initialize() +{ + +} + +void disabled() { } +void competition_initialize() { } +void autonomous() { } + +void opcontrol() +{ + +}