diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3cf9e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Compiled Object files +*.o +*.obj + +# Executables +*.bin +*.elf + +# PROS +bin/ +.vscode/ +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..6dcf5ba --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +################################################################################ +######################### 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:=1 +# TODO: CHANGE THIS! +LIBNAME:=ryanlib +VERSION:=1.0.1 +# 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 the include directory get exported +TEMPLATE_FILES=$(INCDIR)/**/*.h $(INCDIR)/**/*.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..6341070 --- /dev/null +++ b/common.mk @@ -0,0 +1,287 @@ +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 +GCCFLAGS=-ffunction-sections -fdata-sections -fdiagnostics-color -funwind-tables + +WARNFLAGS+=-Wno-psabi + +SPACE := $() $() +COMMA := , + +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=gnu11 +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu++17 +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) + $Dprosv5 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 $@ $@, $(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 +$(call test_output_2,Adding timestamp ,echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(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/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..4450b32 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..ae1c4df 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..27a7b64 --- /dev/null +++ b/include/api.h @@ -0,0 +1,82 @@ +/** + * \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 (c) 2017-2022, 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 3 +#define PROS_VERSION_MINOR 6 +#define PROS_VERSION_PATCH 2 +#define PROS_VERSION_STRING "3.6.2" + +#define PROS_ERR (INT32_MAX) +#define PROS_ERR_F (INFINITY) + +#include "pros/adi.h" +#include "pros/colors.h" +#include "pros/distance.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/rtos.h" +#include "pros/rotation.h" +#include "pros/screen.h" +#include "pros/vision.h" + +#ifdef __cplusplus +#include "pros/adi.hpp" +#include "pros/distance.hpp" +#include "pros/gps.hpp" +#include "pros/imu.hpp" +#include "pros/llemu.hpp" +#include "pros/misc.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" +#include "pros/link.hpp" +#endif + +#endif // _PROS_API_H_ diff --git a/include/display/README.md b/include/display/README.md new file mode 100644 index 0000000..afdfdeb --- /dev/null +++ b/include/display/README.md @@ -0,0 +1,71 @@ +# Littlev Graphics Libraray + +![LittlevGL cover](http://www.gl.littlev.hu/home/main_cover_small.png) + +LittlevGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint. + +Homepage: https://littlevgl.com + +### Table Of Content +* [Key features](#key-features) +* [Porting](#porting) +* [Project set-up](#project-set-up) +* [PC simulator](#pc-simulator) +* [Screenshots](#screenshots) +* [Contributing](#contributing) +* [Donate](#donate) + +## Key features +* Powerful building blocks buttons, charts, lists, sliders, images etc +* Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling +* Various input devices touch pad, mouse, keyboard, encoder, buttons etc +* Multi language support with UTF-8 decoding +* Fully customizable graphical elements +* Hardware independent to use with any microcontroller or display +* Scalable to operate with few memory (50 kB Flash, 10 kB RAM) +* OS, External memory and GPU supported but not required +* Single frame buffer operation even with advances graphical effects +* Written in C for maximal compatibility +* Simulator to develop on PC without embedded hardware +* Tutorials, examples, themes for rapid development +* Documentation and API references online + +## Porting +In the most sime case you need 4 things: +1. Call `lv_tick_inc(1)` in every millisecods in a Timer or Task +2. Register a function which can **copy a pixel array** to an area of the screen +3. Register a function which can **read an input device**. (E.g. touch pad) +4. Call `lv_task_handler()` periodically in every few milliseconds +For more information visit https://littlevgl.com/porting + +## Project set-up +1. **Clone** or [Download](https://littlevgl.com/download) the lvgl repository: `git clone https://github.com/littlevgl/lvgl.git` +2. **Create project** with your preferred IDE and add the *lvgl* folder +3. Copy **lvgl/lv_conf_templ.h** as **lv_conf.h** next to the *lvgl* folder +4. In the lv_conf.h delete the first `#if 0` and its `#endif`. Let the default configurations at first. +5. In your *main.c*: #include "lvgl/lvgl.h" +6. In your *main function*: + * lvgl_init(); + * tick, display and input device initialization (see above) +7. To **test** create a label: `lv_obj_t * label = lv_label_create(lv_scr_act(), NULL);` +8. In the main *while(1)* call `lv_task_handler();` and make a few milliseconds delay (e.g. `my_delay_ms(5);`) +9. Compile the code and load it to your embedded hardware + +## PC Simulator +If you don't have got an embedded hardware you can test the graphics library in a PC simulator. The simulator uses [SDL2](https://www.libsdl.org/) to emulate a display on your monitor and a touch pad with your mouse. + +There is a pre-configured PC project for **Eclipse CDT** in this repository: https://github.com/littlevgl/pc_simulator + +## Screenshots +![TFT material](http://www.gl.littlev.hu/github_res/tft_material.png) +![TFT zen](http://www.gl.littlev.hu/github_res/tft_zen.png) +![TFT alien](http://www.gl.littlev.hu/github_res/tft_alien.png) +![TFT night](http://www.gl.littlev.hu/github_res/tft_night.png) + +## Contributing +See [CONTRIBUTING.md](https://github.com/littlevgl/lvgl/blob/master/docs/CONTRIBUTING.md) + +## Donate +If you are pleased with the graphics library, found it useful or be happy with the support you got, please help its further development: + +[![Donate](https://littlevgl.com/donate_dir/donate_btn.png)](https://littlevgl.com/donate) diff --git a/include/display/licence.txt b/include/display/licence.txt new file mode 100644 index 0000000..beaef1d --- /dev/null +++ b/include/display/licence.txt @@ -0,0 +1,8 @@ +MIT licence +Copyright (c) 2016 Gábor Kiss-Vámosi + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/include/display/lv_conf.h b/include/display/lv_conf.h new file mode 100644 index 0000000..0b1a162 --- /dev/null +++ b/include/display/lv_conf.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 \ + 1 /*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 \ + "kapi.h" /*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 "display/lv_conf_checker.h" +#endif /*LV_CONF_H*/ diff --git a/include/display/lv_conf_checker.h b/include/display/lv_conf_checker.h new file mode 100644 index 0000000..3a8ead5 --- /dev/null +++ b/include/display/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/display/lv_core/lv_core.mk b/include/display/lv_core/lv_core.mk new file mode 100644 index 0000000..9992e3f --- /dev/null +++ b/include/display/lv_core/lv_core.mk @@ -0,0 +1,12 @@ +CSRCS += lv_group.c +CSRCS += lv_indev.c +CSRCS += lv_obj.c +CSRCS += lv_refr.c +CSRCS += lv_style.c +CSRCS += lv_vdb.c +CSRCS += lv_lang.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_core +VPATH += :$(LVGL_DIR)/lvgl/lv_core + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_core" diff --git a/include/display/lv_core/lv_group.h b/include/display/lv_core/lv_group.h new file mode 100644 index 0000000..4fb6043 --- /dev/null +++ b/include/display/lv_core/lv_group.h @@ -0,0 +1,247 @@ +/** + * @file lv_group.h + * + */ + +#ifndef LV_GROUP_H +#define LV_GROUP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +/*Predefined keys to control the focused object via lv_group_send(group, c)*/ +/*For compatibility in signal function define the keys regardless to LV_GROUP*/ +#define LV_GROUP_KEY_UP 17 /*0x11*/ +#define LV_GROUP_KEY_DOWN 18 /*0x12*/ +#define LV_GROUP_KEY_RIGHT 19 /*0x13*/ +#define LV_GROUP_KEY_LEFT 20 /*0x14*/ +#define LV_GROUP_KEY_ESC 27 /*0x1B*/ +#define LV_GROUP_KEY_DEL 127 /*0x7F*/ +#define LV_GROUP_KEY_BACKSPACE 8 /*0x08*/ +#define LV_GROUP_KEY_ENTER 10 /*0x0A, '\n'*/ +#define LV_GROUP_KEY_NEXT 9 /*0x09, '\t'*/ +#define LV_GROUP_KEY_PREV 11 /*0x0B, '*/ + +#if USE_LV_GROUP != 0 +/********************** + * TYPEDEFS + **********************/ +struct _lv_group_t; + +typedef void (*lv_group_style_mod_func_t)(lv_style_t *); +typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *); + +typedef struct _lv_group_t +{ + lv_ll_t obj_ll; /*Linked list to store the objects in the group */ + lv_obj_t ** obj_focus; /*The object in focus*/ + lv_group_style_mod_func_t style_mod; /*A function which modifies the style of the focused object*/ + lv_group_style_mod_func_t style_mod_edit;/*A function which modifies the style of the focused object*/ + lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/ + lv_style_t style_tmp; /*Stores the modified style of the focused object */ + uint8_t frozen :1; /*1: can't focus to new object*/ + uint8_t editing :1; /*1: Edit mode, 0: Navigate mode*/ + uint8_t click_focus :1; /*1: If an object in a group is clicked by an indev then it will be focused */ + uint8_t refocus_policy :1; /*1: Focus prev if focused on deletion. 0: Focus prev 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_t { + LV_GROUP_REFOCUS_POLICY_NEXT = 0, + LV_GROUP_REFOCUS_POLICY_PREV = 1 +} lv_group_refocus_policy_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * 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); + +/** + * 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, lv_obj_t * obj); + +/** + * Remove an object from its group + * @param obj pointer to an object to remove + */ +void lv_group_remove_obj(lv_obj_t * obj); + +/** + * Focus on an object (defocus the current) + * @param obj pointer to an object to focus on + */ +void lv_group_focus_obj(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_GROUP_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 modify the object's style if it is in focus + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * Set a function for a group which will modify the object's style if it is in focus in edit mode + * @param group pointer to a group + * @param style_mod_func the style modifier function pointer + */ +void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func); + +/** + * 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 whether the next or previous item in a group is focused if the currently focussed obj is deleted. + * @param group pointer to a group + * @param 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 the `click_focus` attribute. If enabled then the object will be focused then it is clicked. + * @param group pointer to group + * @param en: true: enable `click_focus` + */ +void lv_group_set_click_focus(lv_group_t * group, bool en); + +/** + * 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); + +/** + * Modify a style with the set 'style_mod' function. The input style remains unchanged. + * @param group pointer to group + * @param style pointer to a style to modify + * @return a copy of the input style but modified with the 'style_mod' function + */ +lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style); + +/** + * Get the focused object or NULL if there isn't one + * @param group pointer to a group + * @return pointer to the focused object + */ +lv_obj_t * lv_group_get_focused(const lv_group_t * group); + +/** + * Get a the style modifier function of a group + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group); + +/** + * Get a the style modifier function of a group in edit mode + * @param group pointer to a group + * @return pointer to the style modifier function + */ +lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(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 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 the `click_focus` attribute. + * @param group pointer to group + * @return true: `click_focus` is enabled; false: disabled + */ +bool lv_group_get_click_focus(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); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GROUP != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GROUP_H*/ diff --git a/include/display/lv_core/lv_indev.h b/include/display/lv_core/lv_indev.h new file mode 100644 index 0000000..b066246 --- /dev/null +++ b/include/display/lv_core/lv_indev.h @@ -0,0 +1,157 @@ +/** + * @file lv_indev_proc.h + * + */ + +#ifndef LV_INDEV_H +#define LV_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include "display/lv_hal/lv_hal_indev.h" +#include "display/lv_core/lv_group.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the display input device subsystem + */ +void lv_indev_init(void); + +/** + * 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_hal_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 + */ +void lv_indev_reset(lv_indev_t * indev); + +/** + * Reset the long press state of an input device + * @param indev_proc pointer to an input device + */ +void lv_indev_reset_lpr(lv_indev_t * indev); + +/** + * Enable input devices device by type + * @param type Input device type + * @param enable true: enable this type; false: disable this type + */ +void lv_indev_enable(lv_hal_indev_type_t type, bool enable); + +/** + * 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); + +#if USE_LV_GROUP +/** + * 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); +#endif + +/** + * 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); + +/** + * Set feedback callback for indev. + * @param indev pointer to an input device + * @param feedback feedback callback + */ +void lv_indev_set_feedback(lv_indev_t *indev, lv_indev_feedback_t feedback); + +/** + * 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 last 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 if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return true: drag is in progress + */ +bool lv_indev_is_dragging(const lv_indev_t * indev); + +/** + * Get the vector of dragging 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 vector + */ +void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); +/** + * Get elapsed time since last press + * @param indev pointer to an input device (NULL to get the overall smallest inactivity) + * @return Elapsed ticks (milliseconds) since last press + */ +uint32_t lv_indev_get_inactive_time(const lv_indev_t * indev); + +/** + * Get feedback callback for indev. + * @param indev pointer to an input device + * @return feedback callback + */ +lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t *indev); + +/** + * Do nothing until the next release + * @param indev pointer to an input device + */ +void lv_indev_wait_release(lv_indev_t * indev); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_H*/ diff --git a/include/display/lv_core/lv_lang.h b/include/display/lv_core/lv_lang.h new file mode 100644 index 0000000..efbdd0a --- /dev/null +++ b/include/display/lv_core/lv_lang.h @@ -0,0 +1,74 @@ +/** + * @file lv_lang.h + * + */ + +#ifndef LV_LANG_H +#define LV_LANG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MULTI_LANG + +#include + +/********************* + * DEFINES + *********************/ +#define LV_LANG_TXT_ID_NONE 0xFFFF /*Used to not assign any text IDs for a multi-language object.*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Change the language + * @param lang_id the id of the + */ +void lv_lang_set(uint8_t lang_id); + +/** + * Set a function to get the texts of the set languages from a `txt_id` + * @param fp a function pointer to get the texts + */ +void lv_lang_set_text_func(const void * (*fp)(uint16_t)); + +/** + * Use the function set by `lv_lang_set_text_func` to get the `txt_id` text in the set language + * @param txt_id an ID of the text to get + * @return the `txt_id` txt on the set language + */ +const void * lv_lang_get_text(uint16_t txt_id); + +/** + * Return with ID of the currently selected language + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +uint8_t lv_lang_act(void); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_MULTI_LANG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LANG_H*/ diff --git a/include/display/lv_core/lv_obj.h b/include/display/lv_core/lv_obj.h new file mode 100644 index 0000000..02378a5 --- /dev/null +++ b/include/display/lv_core/lv_obj.h @@ -0,0 +1,841 @@ +/** + * @file lv_obj.h + * + */ + +#ifndef LV_OBJ_H +#define LV_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_style.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_mem.h" +#include "display/lv_misc/lv_ll.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_log.h" + +/********************* + * DEFINES + *********************/ + +/*Error check of lv_conf.h*/ +#if LV_HOR_RES == 0 || LV_VER_RES == 0 +#error "LittlevGL: LV_HOR_RES and LV_VER_RES must be greater than 0" +#endif + +#if LV_ANTIALIAS > 1 +#error "LittlevGL: LV_ANTIALIAS can be only 0 or 1" +#endif + +#if LV_VDB_SIZE == 0 && LV_ANTIALIAS != 0 +#error "LittlevGL: If LV_VDB_SIZE == 0 the anti-aliasing must be disabled" +#endif + +#if LV_VDB_SIZE > 0 && LV_VDB_SIZE < LV_HOR_RES +#error "LittlevGL: Small Virtual Display Buffer (lv_conf.h: LV_VDB_SIZE >= LV_HOR_RES)" +#endif + +#if LV_VDB_SIZE == 0 && USE_LV_REAL_DRAW == 0 +#error "LittlevGL: If LV_VDB_SIZE = 0 Real drawing function are required (lv_conf.h: USE_LV_REAL_DRAW 1)" +#endif + + +#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/ +#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/ + +#define LV_MAX_ANCESTOR_NUM 8 + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_obj_t; + +enum +{ + LV_DESIGN_DRAW_MAIN, + LV_DESIGN_DRAW_POST, + LV_DESIGN_COVER_CHK, +}; +typedef uint8_t lv_design_mode_t; + +typedef bool (* lv_design_func_t) (struct _lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode); + +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; + +enum +{ + /*General signals*/ + LV_SIGNAL_CLEANUP, + LV_SIGNAL_CHILD_CHG, + LV_SIGNAL_CORD_CHG, + LV_SIGNAL_STYLE_CHG, + LV_SIGNAL_REFR_EXT_SIZE, + LV_SIGNAL_LANG_CHG, + LV_SIGNAL_GET_TYPE, + + _LV_SIGNAL_FEEDBACK_SECTION_START, + /*Input device related*/ + LV_SIGNAL_PRESSED, + LV_SIGNAL_PRESSING, + LV_SIGNAL_PRESS_LOST, + LV_SIGNAL_RELEASED, + LV_SIGNAL_LONG_PRESS, + LV_SIGNAL_LONG_PRESS_REP, + LV_SIGNAL_DRAG_BEGIN, + LV_SIGNAL_DRAG_END, + + /*Group related*/ + LV_SIGNAL_FOCUS, + LV_SIGNAL_DEFOCUS, + LV_SIGNAL_CONTROLL, + _LV_SIGNAL_FEEDBACK_SECTION_END, + LV_SIGNAL_GET_EDITABLE, +}; +typedef uint8_t lv_signal_t; + +typedef lv_res_t (* lv_signal_func_t) (struct _lv_obj_t * obj, lv_signal_t sign, void * param); + +enum +{ + LV_ALIGN_CENTER = 0, + LV_ALIGN_IN_TOP_LEFT, + LV_ALIGN_IN_TOP_MID, + LV_ALIGN_IN_TOP_RIGHT, + LV_ALIGN_IN_BOTTOM_LEFT, + LV_ALIGN_IN_BOTTOM_MID, + LV_ALIGN_IN_BOTTOM_RIGHT, + LV_ALIGN_IN_LEFT_MID, + LV_ALIGN_IN_RIGHT_MID, + 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; + +#if LV_OBJ_REALIGN +typedef struct { + const struct _lv_obj_t * base; + lv_coord_t xofs; + lv_coord_t yofs; + lv_align_t align; + uint8_t auto_realign :1; + uint8_t origo_align :1; /*1: the oigo (center of the object) was aligned with `lv_obj_align_origo`*/ +}lv_reailgn_t; +#endif + + +typedef struct _lv_obj_t +{ + struct _lv_obj_t * par; /*Pointer to the parent object*/ + lv_ll_t child_ll; /*Linked list to store the children objects*/ + + lv_area_t coords; /*Coordinates of the object (x1, y1, x2, y2)*/ + + lv_signal_func_t signal_func; /*Object type specific signal function*/ + lv_design_func_t design_func; /*Object type specific design function*/ + + void * ext_attr; /*Object type specific extended data*/ + lv_style_t * style_p; /*Pointer to the object's style*/ + +#if LV_OBJ_FREE_PTR != 0 + void * free_ptr; /*Application specific pointer (set it freely)*/ +#endif + +#if USE_LV_GROUP != 0 + void * group_p; /*Pointer to the group of the object*/ +#endif + /*Attributes and states*/ + uint8_t click :1; /*1: Can be pressed by an input device*/ + uint8_t drag :1; /*1: Enable the dragging*/ + uint8_t drag_throw :1; /*1: Enable throwing with drag*/ + uint8_t drag_parent :1; /*1: Parent will be dragged instead*/ + uint8_t hidden :1; /*1: Object is hidden*/ + uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/ + uint8_t opa_scale_en :1; /*1: opa_scale is set*/ + uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from `lv_protect_t`*/ + lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/ + + lv_coord_t ext_size; /*EXTtend the size of the object in every direction. E.g. for shadow drawing*/ +#if LV_OBJ_REALIGN + lv_reailgn_t realign; +#endif + +#ifdef LV_OBJ_FREE_NUM_TYPE + LV_OBJ_FREE_NUM_TYPE free_num; /*Application specific identifier (set it freely)*/ +#endif +} lv_obj_t; + +typedef lv_res_t (*lv_action_t) (struct _lv_obj_t * obj); + +/*Protect some attributes (max. 8 bit)*/ +enum +{ + LV_PROTECT_NONE = 0x00, + LV_PROTECT_CHILD_CHG = 0x01, /*Disable the child change signal. Used by the library*/ + LV_PROTECT_PARENT = 0x02, /*Prevent automatic parent change (e.g. in lv_page)*/ + LV_PROTECT_POS = 0x04, /*Prevent automatic positioning (e.g. in lv_cont layout)*/ + LV_PROTECT_FOLLOW = 0x08, /*Prevent the object be followed in automatic ordering (e.g. in lv_cont PRETTY layout)*/ + LV_PROTECT_PRESS_LOST= 0x10, /*If the `indev` was pressing this object but swiped out while pressing do not search other object.*/ + LV_PROTECT_CLICK_FOCUS= 0x20,/*Prevent focusing the object by clicking on it*/ +}; +typedef uint8_t lv_protect_t; + + +/*Used by `lv_obj_get_type()`. The object's and its ancestor types are stored here*/ +typedef struct { + const char * type[LV_MAX_ANCESTOR_NUM]; /*[0]: the actual type, [1]: ancestor, [2] #1's ancestor ... [x]: "lv_obj" */ +} lv_obj_type_t; + +enum +{ + LV_ANIM_NONE = 0, + LV_ANIM_FLOAT_TOP, /*Float from/to the top*/ + LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/ + LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/ + LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/ + LV_ANIM_GROW_H, /*Grow/shrink horizontally*/ + LV_ANIM_GROW_V, /*Grow/shrink vertically*/ +}; +typedef uint8_t lv_anim_builtin_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the 'lv' library. + */ +void lv_init(void); + +/*-------------------- + * Create and delete + *-------------------*/ + +/** + * Create a basic object + * @param parent pointer to a parent object. + * If NULL then a screen will be created + * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * @return pointer to the new object + */ +lv_obj_t * lv_obj_create(lv_obj_t * parent,const lv_obj_t * copy); + +/** + * Delete 'obj' and all of its children + * @param obj pointer to an object to delete + * @return LV_RES_INV because the object is deleted + */ +lv_res_t lv_obj_del(lv_obj_t * obj); + +/** + * Delete all children of an object + * @param obj pointer to an object + */ +void lv_obj_clean(lv_obj_t *obj); + +/** + * Mark the object as invalid therefore its current position will be redrawn by 'lv_refr_task' + * @param obj pointer to an object + */ +void lv_obj_invalidate(const lv_obj_t * obj); + +/*===================== + * Setter functions + *====================*/ + +/*-------------- + * Screen set + *--------------*/ + +/** + * Load a new screen + * @param scr pointer to a screen + */ +void lv_scr_load(lv_obj_t * scr); + +/*-------------------- + * Parent/children set + *--------------------*/ + +/** + * Set a new parent for an object. Its relative position will be the same. + * @param obj pointer to an object. Can't be a screen. + * @param parent pointer to the new parent object. (Can't be NULL) + */ +void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent); + +/*-------------------- + * Coordinate set + * ------------------*/ + +/** + * Set relative the position of an object (relative to the parent) + * @param obj pointer to an object + * @param x new distance from the left side of the parent + * @param y new distance from the top of the parent + */ +void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y); + +/** + * Set the x coordinate of a object + * @param obj pointer to an object + * @param x new distance from the left side from the parent + */ +void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x); + +/** + * Set the y coordinate of a object + * @param obj pointer to an object + * @param y new distance from the top of the parent + */ +void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y); + +/** + * Set the size of an object + * @param obj pointer to an object + * @param w new width + * @param h new height + */ +void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h); + +/** + * Set the width of an object + * @param obj pointer to an object + * @param w new width + */ +void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w); + +/** + * Set the height of an object + * @param obj pointer to an object + * @param h new height + */ +void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align(lv_obj_t * obj,const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Align an object to an other object. + * @param obj pointer to an object to align + * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. + * @param align type of alignment (see 'lv_align_t' enum) + * @param x_mod x coordinate shift after alignment + * @param y_mod y coordinate shift after alignment + */ +void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_mod, lv_coord_t y_mod); + +/** + * Realign the object based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + */ +void lv_obj_realign(lv_obj_t * obj); + +/** + * Enable the automatic realign of the object when its size has changed based on the last `lv_obj_align` parameters. + * @param obj pointer to an object + * @param en true: enable auto realign; false: disable auto realign + */ +void lv_obj_set_auto_realign(lv_obj_t * obj, bool en); + +/*--------------------- + * Appearance set + *--------------------*/ + +/** + * Set a new style for an object + * @param obj pointer to an object + * @param style_p pointer to the new style + */ +void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style); + +/** + * Notify an object about its style is modified + * @param obj pointer to an object + */ +void lv_obj_refresh_style(lv_obj_t * obj); + +/** + * 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_mod(lv_style_t * style); + +/*----------------- + * Attribute set + *----------------*/ + +/** + * Hide an object. It won't be visible and clickable. + * @param obj pointer to an object + * @param en true: hide the object + */ +void lv_obj_set_hidden(lv_obj_t * obj, bool en); + +/** + * Enable or disable the clicking of an object + * @param obj pointer to an object + * @param en true: make the object clickable + */ +void lv_obj_set_click(lv_obj_t * obj, bool en); + +/** + * Enable to bring this object to the foreground if it + * or any of its children is clicked + * @param obj pointer to an object + * @param en true: enable the auto top feature + */ +void lv_obj_set_top(lv_obj_t * obj, bool en); + +/** + * Enable the dragging of an object + * @param obj pointer to an object + * @param en true: make the object dragable + */ +void lv_obj_set_drag(lv_obj_t * obj, bool en); + +/** + * Enable the throwing of an object after is is dragged + * @param obj pointer to an object + * @param en true: enable the drag throw + */ +void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); + +/** + * Enable to use parent for drag related operations. + * If trying to drag the object the parent will be moved instead + * @param obj pointer to an object + * @param en true: enable the 'drag parent' for the object + */ +void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); + +/** + * Set editable parameter Used by groups and keyboard/encoder control. + * Editable object has something inside to choose (the elements of a list) + * @param obj pointer to an object + * @param en true: enable editing + */ +//void lv_obj_set_editable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`) + * @param obj pointer to an object + * @param en true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +void lv_obj_set_opa_scale_enable(lv_obj_t * obj, bool en); + +/** + * Set the opa scale of an object + * @param obj pointer to an object + * @param opa_scale a factor to scale down opacity [0..255] + */ +void lv_obj_set_opa_scale(lv_obj_t * obj, lv_opa_t opa_scale); + +/** + * Set a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_set_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Clear a bit or bits in the protect filed + * @param obj pointer to an object + * @param prot 'OR'-ed values from `lv_protect_t` + */ +void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot); + +/** + * Set the signal function of an object. + * Always call the previous signal function in the new. + * @param obj pointer to an object + * @param fp the new signal function + */ +void lv_obj_set_signal_func(lv_obj_t * obj, lv_signal_func_t fp); + +/** + * Set a new design function for an object + * @param obj pointer to an object + * @param fp the new design function + */ +void lv_obj_set_design_func(lv_obj_t * obj, lv_design_func_t fp); + +/*---------------- + * Other set + *--------------*/ + +/** + * Allocate a new ext. data for an object + * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext + */ +void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size); + +/** + * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object + * @param obj pointer to an object + */ +void lv_obj_refresh_ext_size(lv_obj_t * obj); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Set an application specific number for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_num the new free number + */ +void lv_obj_set_free_num(lv_obj_t * obj, LV_OBJ_FREE_NUM_TYPE free_num); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Set an application specific pointer for an object. + * It can help to identify objects in the application. + * @param obj pointer to an object + * @param free_p the new free pinter + */ +void lv_obj_set_free_ptr(lv_obj_t * obj, void * free_p); +#endif + +#if USE_LV_ANIMATION +/** + * Animate an object + * @param obj pointer to an object to animate + * @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT + * @param time time of animation in milliseconds + * @param delay delay before the animation in milliseconds + * @param cb a function to call when the animation is ready + */ +void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay, void (*cb) (lv_obj_t *)); +#endif + +/*======================= + * Getter functions + *======================*/ + +/*------------------ + * Screen get + *-----------------*/ + +/** + * Return with a pointer to the active screen + * @return pointer to the active screen object (loaded by 'lv_scr_load()') + */ +lv_obj_t * lv_scr_act(void); + +/** + * Return with the top layer. (Same on every screen and it is above the normal screen layer) + * @return pointer to the top layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_top(void); + +/** + * Return with the system layer. (Same on every screen and it is above the all other layers) + * It is used for example by the cursor + * @return pointer to the system layer object (transparent screen sized lv_obj) + */ +lv_obj_t * lv_layer_sys(void); + +/** + * Return with the screen of an object + * @param obj pointer to an object + * @return pointer to a screen + */ +lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj); + +/*--------------------- + * Parent/children get + *--------------------*/ + +/** + * Returns with the parent of an object + * @param obj pointer to an object + * @return pointer to the parent of 'obj' + */ +lv_obj_t * lv_obj_get_parent(const lv_obj_t * obj); + +/** + * Iterate through the children of an object (start from the "youngest, lastly created") + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Iterate through the children of an object (start from the "oldest", firstly created) + * @param obj pointer to an object + * @param child NULL at first call to get the next children + * and the previous return value later + * @return the child after 'act_child' or NULL if no more child + */ +lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child); + +/** + * Count the children of an object (only children directly on 'obj') + * @param obj pointer to an object + * @return children number of 'obj' + */ +uint16_t lv_obj_count_children(const lv_obj_t * obj); + +/*--------------------- + * Coordinate get + *--------------------*/ + +/** + * Copy the coordinates of an object to an area + * @param obj pointer to an object + * @param cords_p pointer to an area to store the coordinates + */ +void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p); + +/** + * Get the x coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the left side of its parent + */ +lv_coord_t lv_obj_get_x(const lv_obj_t * obj); + +/** + * Get the y coordinate of object + * @param obj pointer to an object + * @return distance of 'obj' from the top of its parent + */ +lv_coord_t lv_obj_get_y(const lv_obj_t * obj); + +/** + * Get the width of an object + * @param obj pointer to an object + * @return the width + */ +lv_coord_t lv_obj_get_width(const lv_obj_t * obj); + +/** + * Get the height of an object + * @param obj pointer to an object + * @return the height + */ +lv_coord_t lv_obj_get_height(const lv_obj_t * obj); + +/** + * Get the extended size attribute of an object + * @param obj pointer to an object + * @return the extended size attribute + */ +lv_coord_t lv_obj_get_ext_size(const lv_obj_t * obj); + +/** + * Get the automatic realign property of the object. + * @param obj pointer to an object + * @return true: auto realign is enabled; false: auto realign is disabled + */ +bool lv_obj_get_auto_realign(lv_obj_t * obj); + +/*----------------- + * Appearance get + *---------------*/ + +/** + * Get the style pointer of an object (if NULL get style of the parent) + * @param obj pointer to an object + * @return pointer to a style + */ +lv_style_t * lv_obj_get_style(const lv_obj_t * obj); + +/*----------------- + * Attribute get + *----------------*/ + +/** + * Get the hidden attribute of an object + * @param obj pointer to an object + * @return true: the object is hidden + */ +bool lv_obj_get_hidden(const lv_obj_t * obj); + +/** + * Get the click enable attribute of an object + * @param obj pointer to an object + * @return true: the object is clickable + */ +bool lv_obj_get_click(const lv_obj_t * obj); + +/** + * Get the top enable attribute of an object + * @param obj pointer to an object + * @return true: the auto top feature is enabled + */ +bool lv_obj_get_top(const lv_obj_t * obj); + +/** + * Get the drag enable attribute of an object + * @param obj pointer to an object + * @return true: the object is dragable + */ +bool lv_obj_get_drag(const lv_obj_t * obj); + +/** + * Get the drag throw enable attribute of an object + * @param obj pointer to an object + * @return true: drag throw is enabled + */ +bool lv_obj_get_drag_throw(const lv_obj_t * obj); + +/** + * Get the drag parent attribute of an object + * @param obj pointer to an object + * @return true: drag parent is enabled + */ +bool lv_obj_get_drag_parent(const lv_obj_t * obj); + + +/** + * Get the opa scale enable parameter + * @param obj pointer to an object + * @return true: opa scaling is enabled for this object and all children; false: no opa scaling + */ +lv_opa_t lv_obj_get_opa_scale_enable(const lv_obj_t * obj); + +/** + * Get the opa scale parameter of an object + * @param obj pointer to an object + * @return opa scale [0..255] + */ +lv_opa_t lv_obj_get_opa_scale(const lv_obj_t * obj); + +/** + * Get the protect field of an object + * @param obj pointer to an object + * @return protect field ('OR'ed values of `lv_protect_t`) + */ +uint8_t lv_obj_get_protect(const lv_obj_t * obj); + +/** + * Check at least one bit of a given protect bitfield is set + * @param obj pointer to an object + * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) + * @return false: none of the given bits are set, true: at least one bit is set + */ +bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot); + +/** + * Get the signal function of an object + * @param obj pointer to an object + * @return the signal function + */ +lv_signal_func_t lv_obj_get_signal_func(const lv_obj_t * obj); + +/** + * Get the design function of an object + * @param obj pointer to an object + * @return the design function + */ +lv_design_func_t lv_obj_get_design_func(const lv_obj_t * obj); + +/*------------------ + * Other get + *-----------------*/ + +/** + * Get the ext pointer + * @param obj pointer to an object + * @return the ext pointer but not the dynamic version + * Use it as ext->data1, and NOT da(ext)->data1 + */ +void * lv_obj_get_ext_attr(const lv_obj_t * obj); + +/** + * Get object's and its ancestors type. Put their name in `type_buf` starting with the current type. + * E.g. buf.type[0]="lv_btn", buf.type[1]="lv_cont", buf.type[2]="lv_obj" + * @param obj pointer to an object which type should be get + * @param buf pointer to an `lv_obj_type_t` buffer to store the types + */ +void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf); + +#ifdef LV_OBJ_FREE_NUM_TYPE +/** + * Get the free number + * @param obj pointer to an object + * @return the free number + */ +LV_OBJ_FREE_NUM_TYPE lv_obj_get_free_num(const lv_obj_t * obj); +#endif + +#if LV_OBJ_FREE_PTR != 0 +/** + * Get the free pointer + * @param obj pointer to an object + * @return the free pointer + */ +void * lv_obj_get_free_ptr(const lv_obj_t * obj); +#endif + +#if USE_LV_GROUP +/** + * 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); + + +/** + * Tell whether the object is the focused object of a group or not. + * @param obj pointer to an object + * @return true: the object is focused, false: the object is not focused or not in a group + */ +bool lv_obj_is_focused(const lv_obj_t * obj); + +#endif + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_OBJ_H*/ diff --git a/include/display/lv_core/lv_refr.h b/include/display/lv_core/lv_refr.h new file mode 100644 index 0000000..75b22d0 --- /dev/null +++ b/include/display/lv_core/lv_refr.h @@ -0,0 +1,95 @@ +/** + * @file lv_refr.h + * + */ + +#ifndef LV_REFR_H +#define LV_REFR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * 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_task_handler` but a long blocking process can + * prevent the call of `lv_task_handler`. In this case if the the GUI is updated in the process (e.g. progress bar) + * this function can be called when the screen should be updated. + */ +void lv_refr_now(void); + +/** + * Invalidate an area + * @param area_p pointer to area which should be invalidated + */ +void lv_inv_area(const lv_area_t * area_p); + +/** + * Set a function to call after every refresh to announce the refresh time and the number of refreshed pixels + * @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num)) + */ +void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t)); + +/** + * Called when an area is invalidated to modify the coordinates of the area. + * Special display controllers may require special coordinate rounding + * @param cb pointer to the a function which will modify the area + */ +void lv_refr_set_round_cb(void(*cb)(lv_area_t*)); + +/** + * Get the number of areas in the buffer + * @return number of invalid areas + */ +uint16_t lv_refr_get_buf_size(void); + +/** + * Pop (delete) the last 'num' invalidated areas from the buffer + * @param num number of areas to delete + */ +void lv_refr_pop_from_buf(uint16_t num); +/********************** + * STATIC FUNCTIONS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_REFR_H*/ diff --git a/include/display/lv_core/lv_style.h b/include/display/lv_core/lv_style.h new file mode 100644 index 0000000..4206ada --- /dev/null +++ b/include/display/lv_core/lv_style.h @@ -0,0 +1,199 @@ +/** + * @file lv_style.h + * + */ + +#ifndef LV_STYLE_H +#define LV_STYLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_anim.h" + +/********************* + * DEFINES + *********************/ +#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /*A very big radius to always draw as circle*/ + +/********************** + * TYPEDEFS + **********************/ + +/*Border types (Use 'OR'ed values)*/ +enum +{ + LV_BORDER_NONE = 0x00, + LV_BORDER_BOTTOM = 0x01, + LV_BORDER_TOP = 0x02, + LV_BORDER_LEFT = 0x04, + LV_BORDER_RIGHT = 0x08, + LV_BORDER_FULL = 0x0F, + LV_BORDER_INTERNAL = 0x10, /*FOR matrix-like objects (e.g. Button matrix)*/ +}; +typedef uint8_t lv_border_part_t; + +/*Shadow types*/ +enum +{ + LV_SHADOW_BOTTOM = 0, + LV_SHADOW_FULL, +}; +typedef uint8_t lv_shadow_type_t; + +typedef struct +{ + uint8_t glass :1; /*1: Do not inherit this style*/ + + struct { + lv_color_t main_color; + lv_color_t grad_color; /*`grad_color` will be removed in v6.0, use `aux_color` instead*/ + lv_coord_t radius; + lv_opa_t opa; + + struct { + lv_color_t color; + lv_coord_t width; + lv_border_part_t part; + lv_opa_t opa; + } border; + + struct { + lv_color_t color; + lv_coord_t width; + lv_shadow_type_t type; + } shadow; + + struct { + lv_coord_t ver; + lv_coord_t hor; + lv_coord_t inner; + } padding; + + uint8_t empty :1; /*Transparent background (border still drawn)*/ + } body; + + + struct { + lv_color_t color; + const lv_font_t * font; + lv_coord_t letter_space; + lv_coord_t line_space; + lv_opa_t opa; + } text; + + struct { + lv_color_t color; + lv_opa_t intense; + lv_opa_t opa; + } image; + + struct { + lv_color_t color; + lv_coord_t width; + lv_opa_t opa; + uint8_t rounded :1; /*1: rounded line endings*/ + } line; +} lv_style_t; + +#if USE_LV_ANIMATION +typedef struct { + const lv_style_t * style_start; /*Pointer to the starting style*/ + const lv_style_t * style_end; /*Pointer to the destination style*/ + lv_style_t * style_anim; /*Pointer to a style to animate*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/ + int16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ +} lv_style_anim_t; + +/* Example initialization +lv_style_anim_t a; +a.style_anim = &style_to_anim; +a.style_start = &style_1; +a.style_end = &style_2; +a.act_time = 0; +a.time = 1000; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +a.end_cb = NULL; +lv_style_anim_create(&a); + */ +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the basic styles + */ +void lv_style_init (void); + +/** + * Copy a style to an other + * @param dest pointer to the destination style + * @param src pointer to the source style + */ +void lv_style_copy(lv_style_t * dest, const lv_style_t * src); + + +/** + * Mix two styles according to a given ratio + * @param start start style + * @param end end style + * @param res store the result style here + * @param ratio the ratio of mix [0..256]; 0: `start` style; 256: `end` style + */ +void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t * res, uint16_t ratio); + +#if USE_LV_ANIMATION + +/** + * Create an animation from a pre-configured 'lv_style_anim_t' variable + * @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied) + * @return pointer to a descriptor. Really this variable will be animated. (Can be used in `lv_anim_del(dsc, NULL)`) + */ +void * lv_style_anim_create(lv_style_anim_t * anim); +#endif + +/************************* + * GLOBAL VARIABLES + *************************/ +extern lv_style_t lv_style_scr; +extern lv_style_t lv_style_transp; +extern lv_style_t lv_style_transp_fit; +extern lv_style_t lv_style_transp_tight; +extern lv_style_t lv_style_plain; +extern lv_style_t lv_style_plain_color; +extern lv_style_t lv_style_pretty; +extern lv_style_t lv_style_pretty_color; +extern lv_style_t lv_style_btn_rel; +extern lv_style_t lv_style_btn_pr; +extern lv_style_t lv_style_btn_tgl_rel; +extern lv_style_t lv_style_btn_tgl_pr; +extern lv_style_t lv_style_btn_ina; + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_STYLE_H*/ diff --git a/include/display/lv_core/lv_vdb.h b/include/display/lv_core/lv_vdb.h new file mode 100644 index 0000000..32aac5d --- /dev/null +++ b/include/display/lv_core/lv_vdb.h @@ -0,0 +1,119 @@ +/** + * @file lv_vdb.h + * + */ + +#ifndef LV_VDB_H +#define LV_VDB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ +/*Can be used in `lv_conf.h` the set an invalid address for the VDB. It should be replaced later by a valid address using `lv_vdb_set_adr()`*/ +#define LV_VDB_ADR_INV 8 /*8 is still too small to be valid but it's aligned on 64 bit machines as well*/ + +#ifndef LV_VDB_PX_BPP +#define LV_VDB_PX_BPP LV_COLOR_SIZE /* Default is LV_COLOR_SIZE */ +#endif + + +#if LV_VDB_TRUE_DOUBLE_BUFFERED && (LV_VDB_SIZE != LV_HOR_RES * LV_VER_RES || LV_VDB_DOUBLE == 0) +#error "With LV_VDB_TRUE_DOUBLE_BUFFERED: (LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES and LV_VDB_DOUBLE = 1 is required" +#endif + + +/* The size of VDB in bytes. + * (LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3): just divide by 8 to convert bits to bytes + * (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0): add an extra byte to round up. + * E.g. if LV_VDB_SIZE = 10 and LV_VDB_PX_BPP = 1 -> 10 bits -> 2 bytes*/ +#define LV_VDB_SIZE_IN_BYTES ((LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3) + (((LV_VDB_SIZE * LV_VDB_PX_BPP) & 0x7) ? 1 : 0) + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + lv_area_t area; + lv_color_t *buf; +} lv_vdb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode + * @return pointer to a 'vdb' variable + */ +lv_vdb_t * lv_vdb_get(void); + +/** + * Flush the content of the vdb + */ +void lv_vdb_flush(void); + +/** + * Set the address of VDB buffer(s) manually. To use this set `LV_VDB_ADR` (and `LV_VDB2_ADR`) to `LV_VDB_ADR_INV` in `lv_conf.h`. + * It should be called before `lv_init()`. The size of the buffer should be: `LV_VDB_SIZE_IN_BYTES` + * @param buf1 address of the VDB. + * @param buf2 address of the second buffer. `NULL` if `LV_VDB_DOUBLE 0` + */ +void lv_vdb_set_adr(void * buf1, void * buf2); + +/** + * Call in the display driver's 'disp_flush' function when the flushing is finished + */ +void lv_flush_ready(void); + +/** + * Get currently active VDB, where the drawing happens. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the active VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_active(void); + +/** + * Get currently inactive VDB, which is being displayed or being flushed. Used with `LV_VDB_DOUBLE 1` + * @return pointer to the inactive VDB. If `LV_VDB_DOUBLE 0` give the single VDB + */ +lv_vdb_t * lv_vdb_get_inactive(void); + +/** + * Whether the flushing is in progress or not + * @return true: flushing is in progress; false: flushing ready + */ +bool lv_vdb_is_flushing(void); + +/********************** + * MACROS + **********************/ + +#else /*LV_VDB_SIZE != 0*/ + +/*Just for compatibility*/ +void lv_flush_ready(void); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_VDB_H*/ diff --git a/include/display/lv_draw/lv_draw.h b/include/display/lv_draw/lv_draw.h new file mode 100644 index 0000000..5503883 --- /dev/null +++ b/include/display/lv_draw/lv_draw.h @@ -0,0 +1,115 @@ +/** + * @file lv_draw.h + * + */ + +#ifndef LV_DRAW_H +#define LV_DRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" +#include "display/lv_misc/lv_txt.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 + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_IMG_SRC_VARIABLE, + LV_IMG_SRC_FILE, + LV_IMG_SRC_SYMBOL, + LV_IMG_SRC_UNKNOWN, +}; +typedef uint8_t lv_img_src_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +#if LV_ANTIALIAS != 0 + +/** + * Get the opacity of a pixel based it's position in a line segment + * @param seg segment length + * @param px_id position of of a pixel which opacity should be get [0..seg-1] + * @param base_opa the base opacity + * @return the opacity of the given pixel + */ +lv_opa_t lv_draw_aa_get_opa(lv_coord_t seg, lv_coord_t px_id, lv_opa_t base_opa); + +/** + * Add a vertical anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_ver_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); + +/** + * Add a horizontal anti-aliasing segment (pixels with decreasing opacity) + * @param x start point x coordinate + * @param y start point y coordinate + * @param length length of segment (negative value to start from 0 opacity) + * @param mask draw only in this area + * @param color color of pixels + * @param opa maximum opacity + */ +void lv_draw_aa_hor_seg(lv_coord_t x, lv_coord_t y, lv_coord_t length, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +#endif + +/********************** + * GLOBAL VARIABLES + **********************/ +extern void (*const px_fp)(lv_coord_t x, lv_coord_t y, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const fill_fp)(const lv_area_t * coords, const lv_area_t * mask, lv_color_t color, lv_opa_t opa); +extern void (*const letter_fp)(const lv_point_t * pos_p, const lv_area_t * mask, const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa); +extern void (*const map_fp)(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDES + *********************/ +#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" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_H*/ diff --git a/include/display/lv_draw/lv_draw.mk b/include/display/lv_draw/lv_draw.mk new file mode 100644 index 0000000..a384eef --- /dev/null +++ b/include/display/lv_draw/lv_draw.mk @@ -0,0 +1,14 @@ +CSRCS += lv_draw_vbasic.c +CSRCS += lv_draw_rbasic.c +CSRCS += lv_draw.c +CSRCS += lv_draw_rect.c +CSRCS += lv_draw_label.c +CSRCS += lv_draw_line.c +CSRCS += lv_draw_img.c +CSRCS += lv_draw_arc.c +CSRCS += lv_draw_triangle.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_draw +VPATH += :$(LVGL_DIR)/lvgl/lv_draw + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_draw" diff --git a/include/display/lv_draw/lv_draw_arc.h b/include/display/lv_draw/lv_draw_arc.h new file mode 100644 index 0000000..203eabe --- /dev/null +++ b/include/display/lv_draw/lv_draw_arc.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_arc.h + * + */ + +#ifndef LV_DRAW_ARC_H +#define LV_DRAW_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * 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 style style of the arc (`body.thickness`, `body.main_color`, `body.opa` is used) + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, const lv_area_t * mask, + uint16_t start_angle, uint16_t end_angle, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_ARC*/ diff --git a/include/display/lv_draw/lv_draw_img.h b/include/display/lv_draw/lv_draw_img.h new file mode 100644 index 0000000..ff77958 --- /dev/null +++ b/include/display/lv_draw/lv_draw_img.h @@ -0,0 +1,167 @@ +/** + * @file lv_draw_img.h + * + */ + +#ifndef LV_DRAW_IMG_H +#define LV_DRAW_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_IMG_DECODER_OPEN_FAIL ((void*)(-1)) + +/********************** + * TYPEDEFS + **********************/ +struct _lv_img_t; + +typedef struct { + + /* 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 */ + 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; + +/*Image color format*/ +enum { + LV_IMG_CF_UNKOWN = 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 (always chroma keyed)*/ + LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/ + LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always 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*/ +}; +typedef uint8_t lv_img_cf_t; + +/* Image header it is compatible with + * the result image converter utility*/ +typedef struct +{ + lv_img_header_t header; + uint32_t data_size; + const uint8_t * data; +} lv_img_dsc_t; + +/* Decoder function definitions */ + + +/** + * 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)(const void * src, lv_img_header_t * header); + +/** + * Open an image for decoding. Prepare it as it is required to read it later + * @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 style the style of image (maybe it will be required to determine a color or something) + * @return there are 3 possible return values: + * 1) buffer with the decoded image + * 2) if can decode the whole image NULL. decoder_read_line will be called to read the image line-by-line + * 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an error occurred + */ +typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style); + +/** + * 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 x start x coordinate + * @param y startt 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)(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf); + +/** + * Close the pending decoding. Free resources etc. + */ +typedef void (*lv_img_decoder_close_f_t)(void); + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * 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 style style of the image + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, + const void * src, const lv_style_t * style, lv_opa_t opa_scale); + + +/** + * 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. SYMBOL_CLOSE) + * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKOWN + */ +lv_img_src_t lv_img_src_get_type(const void * src); + +/** + * Set custom decoder functions. See the typdefs of the function typed above for more info about them + * @param info_fp info get function + * @param open_fp open function + * @param read_fp read line function + * @param close_fp clode function + */ +void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp, + lv_img_decoder_read_line_f_t read_fp, lv_img_decoder_close_f_t close_fp); + +lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header); + +uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf); + +bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf); + +bool lv_img_color_format_has_alpha(lv_img_cf_t cf); + + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/include/display/lv_draw/lv_draw_label.h b/include/display/lv_draw/lv_draw_label.h new file mode 100644 index 0000000..8798573 --- /dev/null +++ b/include/display/lv_draw/lv_draw_label.h @@ -0,0 +1,53 @@ +/** + * @file lv_draw_label.h + * + */ + +#ifndef LV_DRAW_LABEL_H +#define LV_DRAW_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Write a text + * @param coords coordinates of the label + * @param mask the label will be drawn only in this area + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + * @param txt 0 terminated text to write + * @param flag settings for the text from 'txt_flag_t' enum + * @param offset text offset in x and y direction (NULL if unused) + * + */ +void lv_draw_label(const lv_area_t * coords,const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale, + const char * txt, lv_txt_flag_t flag, lv_point_t * offset); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LABEL_H*/ diff --git a/include/display/lv_draw/lv_draw_line.h b/include/display/lv_draw/lv_draw_line.h new file mode 100644 index 0000000..4269475 --- /dev/null +++ b/include/display/lv_draw/lv_draw_line.h @@ -0,0 +1,49 @@ +/** + * @file lv_draw_line.h + * + */ + +#ifndef LV_DRAW_LINE_H +#define LV_DRAW_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a line + * @param point1 first point of the line + * @param point2 second point of the line + * @param mask the line will be drawn only on this area + * @param style pointer to a line's style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * mask, + const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_LINE_H*/ diff --git a/include/display/lv_draw/lv_draw_rbasic.h b/include/display/lv_draw/lv_draw_rbasic.h new file mode 100644 index 0000000..403cb80 --- /dev/null +++ b/include/display/lv_draw/lv_draw_rbasic.h @@ -0,0 +1,96 @@ +/** + * @file lv_draw_rbasic..h + * + */ + +#ifndef LV_DRAW_RBASIC_H +#define LV_DRAW_RBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_REAL_DRAW != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_rpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); + +/** + * Fill an area on the display + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity (ignored, only for compatibility with lv_vfill) + */ +void lv_rfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter to the display + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (ignored, only for compatibility with lv_vletter) + */ +void lv_rletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * When the letter is ant-aliased it needs to know the background color + * @param bg_color the background color of the currently drawn letter + */ +void lv_rletter_set_background(lv_color_t color); + + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map (ignored, only for compatibility with 'lv_vmap') + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel (not supported, only l'v_vmap' can draw it) + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_rmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_REAL_DRAW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/include/display/lv_draw/lv_draw_rect.h b/include/display/lv_draw/lv_draw_rect.h new file mode 100644 index 0000000..933590c --- /dev/null +++ b/include/display/lv_draw/lv_draw_rect.h @@ -0,0 +1,48 @@ +/** + * @file lv_draw_rect.h + * + */ + +#ifndef LV_DRAW_RECT_H +#define LV_DRAW_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw a rectangle + * @param coords the coordinates of the rectangle + * @param mask the rectangle will be drawn only in this mask + * @param style pointer to a style + * @param opa_scale scale down all opacities by the factor + */ +void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa_scale); + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RECT_H*/ diff --git a/include/display/lv_draw/lv_draw_triangle.h b/include/display/lv_draw/lv_draw_triangle.h new file mode 100644 index 0000000..c3c6208 --- /dev/null +++ b/include/display/lv_draw/lv_draw_triangle.h @@ -0,0 +1,51 @@ +/** + * @file lv_draw_triangle.h + * + */ + +#ifndef LV_DRAW_TRIANGLE_H +#define LV_DRAW_TRIANGLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/*Experimental use for 3D modeling*/ +#define USE_LV_TRIANGLE 1 + +#if USE_LV_TRIANGLE != 0 +/** + * + * @param points pointer to an array with 3 points + * @param mask the triangle will be drawn only in this mask + * @param color color of the triangle + */ +void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, lv_color_t color); +#endif + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_TRIANGLE_H*/ diff --git a/include/display/lv_draw/lv_draw_vbasic.h b/include/display/lv_draw/lv_draw_vbasic.h new file mode 100644 index 0000000..82d4b7a --- /dev/null +++ b/include/display/lv_draw/lv_draw_vbasic.h @@ -0,0 +1,89 @@ +/** + * @file lv_draw_vbasic.h + * + */ + +#ifndef LV_DRAW_VBASIC_H +#define LV_DRAW_VBASIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if LV_VDB_SIZE != 0 + +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t color, lv_opa_t opa); +/** + * Fill an area in the Virtual Display Buffer + * @param cords_p coordinates of the area to fill + * @param mask_p fill only o this mask + * @param color fill color + * @param opa opacity of the area (0..255) + */ +void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a letter in the Virtual Display Buffer + * @param pos_p left-top coordinate of the latter + * @param mask_p the letter will be drawn only on this area + * @param font_p pointer to font + * @param letter a letter to draw + * @param color color of letter + * @param opa opacity of letter (0..255) + */ +void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p, + const lv_font_t * font_p, uint32_t letter, + lv_color_t color, lv_opa_t opa); + +/** + * Draw a color map to the display (image) + * @param cords_p coordinates the color map + * @param mask_p the map will drawn only on this area (truncated to VDB area) + * @param map_p pointer to a lv_color_t array + * @param opa opacity of the map + * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels + * @param alpha_byte true: extra alpha byte is inserted for every pixel + * @param recolor mix the pixels with this color + * @param recolor_opa the intense of recoloring + */ +void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p, + const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte, + lv_color_t recolor, lv_opa_t recolor_opa); + +/********************** + * MACROS + **********************/ + +#endif /*LV_VDB_SIZE != 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DRAW_RBASIC_H*/ diff --git a/include/display/lv_fonts/lv_font_builtin.h b/include/display/lv_fonts/lv_font_builtin.h new file mode 100644 index 0000000..5687fa1 --- /dev/null +++ b/include/display/lv_fonts/lv_font_builtin.h @@ -0,0 +1,150 @@ +/** + * @file lv_font_builtin.h + * + */ + +#ifndef LV_FONT_BUILTIN_H +#define LV_FONT_BUILTIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_misc/lv_font.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the built-in fonts + */ +void lv_font_builtin_init(void); + +/********************** + * MACROS + **********************/ + +/********************** + * FONT DECLARATIONS + **********************/ + +/*10 px */ +#if USE_LV_FONT_DEJAVU_10 +LV_FONT_DECLARE(lv_font_dejavu_10); +#endif + +#if USE_LV_FONT_DEJAVU_10_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_10_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_10_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_10_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_10 +LV_FONT_DECLARE(lv_font_symbol_10); +#endif + +/*20 px */ +#if USE_LV_FONT_DEJAVU_20 +LV_FONT_DECLARE(lv_font_dejavu_20); +#endif + +#if USE_LV_FONT_DEJAVU_20_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_20_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_20_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_20_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_20 +LV_FONT_DECLARE(lv_font_symbol_20); +#endif + +/*30 px */ +#if USE_LV_FONT_DEJAVU_30 +LV_FONT_DECLARE(lv_font_dejavu_30); +#endif + +#if USE_LV_FONT_DEJAVU_30_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_30_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_30_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_30_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_30 +LV_FONT_DECLARE(lv_font_symbol_30); +#endif + +/*40 px */ +#if USE_LV_FONT_DEJAVU_40 +LV_FONT_DECLARE(lv_font_dejavu_40); +#endif + +#if USE_LV_FONT_DEJAVU_40_LATIN_SUP +LV_FONT_DECLARE(lv_font_dejavu_40_latin_sup); +#endif + +#if USE_LV_FONT_DEJAVU_40_CYRILLIC +LV_FONT_DECLARE(lv_font_dejavu_40_cyrillic); +#endif + +#if USE_LV_FONT_SYMBOL_40 +LV_FONT_DECLARE(lv_font_symbol_40); +#endif + +#if USE_LV_FONT_MONOSPACE_8 +LV_FONT_DECLARE(lv_font_monospace_8); +#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_20 +LV_FONT_DECLARE(pros_font_dejavu_mono_20); +#endif +#if USE_PROS_FONT_DEJAVU_MONO_20_LATIN_SUP +LV_FONT_DECLARE(pros_font_dejavu_mono_20_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 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FONT_BUILTIN_H*/ diff --git a/include/display/lv_fonts/lv_fonts.mk b/include/display/lv_fonts/lv_fonts.mk new file mode 100644 index 0000000..f124b55 --- /dev/null +++ b/include/display/lv_fonts/lv_fonts.mk @@ -0,0 +1,23 @@ +CSRCS += lv_font_builtin.c +CSRCS += lv_font_dejavu_10.c +CSRCS += lv_font_dejavu_20.c +CSRCS += lv_font_dejavu_30.c +CSRCS += lv_font_dejavu_40.c +CSRCS += lv_font_dejavu_10_cyrillic.c +CSRCS += lv_font_dejavu_20_cyrillic.c +CSRCS += lv_font_dejavu_30_cyrillic.c +CSRCS += lv_font_dejavu_40_cyrillic.c +CSRCS += lv_font_dejavu_10_latin_sup.c +CSRCS += lv_font_dejavu_20_latin_sup.c +CSRCS += lv_font_dejavu_30_latin_sup.c +CSRCS += lv_font_dejavu_40_latin_sup.c +CSRCS += lv_font_symbol_10.c +CSRCS += lv_font_symbol_20.c +CSRCS += lv_font_symbol_30.c +CSRCS += lv_font_symbol_40.c +CSRCS += lv_font_monospace_8.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_fonts +VPATH += :$(LVGL_DIR)/lvgl/lv_fonts + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_fonts" diff --git a/include/display/lv_hal/lv_hal.h b/include/display/lv_hal/lv_hal.h new file mode 100644 index 0000000..5ab28f2 --- /dev/null +++ b/include/display/lv_hal/lv_hal.h @@ -0,0 +1,40 @@ +/** + * @file hal.h + * + */ + +#ifndef HAL_H +#define HAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_hal_disp.h" +#include "lv_hal_indev.h" +#include "lv_hal_tick.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_hal/lv_hal.mk b/include/display/lv_hal/lv_hal.mk new file mode 100644 index 0000000..83f4bf1 --- /dev/null +++ b/include/display/lv_hal/lv_hal.mk @@ -0,0 +1,8 @@ +CSRCS += lv_hal_disp.c +CSRCS += lv_hal_indev.c +CSRCS += lv_hal_tick.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_hal +VPATH += :$(LVGL_DIR)/lvgl/lv_hal + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_hal" diff --git a/include/display/lv_hal/lv_hal_disp.h b/include/display/lv_hal/lv_hal_disp.h new file mode 100644 index 0000000..273f331 --- /dev/null +++ b/include/display/lv_hal/lv_hal_disp.h @@ -0,0 +1,174 @@ +/** + * @file hal_disp.h + * + * @description Display Driver HAL interface header file + * + */ + +#ifndef HAL_DISP_H +#define HAL_DISP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_color.h" +#include "display/lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * Display Driver structure to be registered by HAL + */ +typedef struct _disp_drv_t { + /*Write the internal buffer (VDB) to the display. 'lv_flush_ready()' has to be called when finished*/ + void (*disp_flush)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Fill an area with a color on the display*/ + void (*disp_fill)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + + /*Write pixel map (e.g. image) to the display*/ + void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); + + /*Optional interface functions to use GPU*/ +#if USE_LV_GPU + /*Blend two memories using opacity (GPU only)*/ + void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + + /*Fill a memory with a color (GPU only)*/ + void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color); +#endif + +#if LV_VDB_SIZE + /*Optional: Set a pixel in a buffer according to the requirements of the display*/ + void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa); +#endif +} lv_disp_drv_t; + +typedef struct _disp_t { + lv_disp_drv_t driver; + struct _disp_t *next; +} lv_disp_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize a display 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 driver pointer to driver variable to initialize + */ +void lv_disp_drv_init(lv_disp_drv_t *driver); + +/** + * Register an initialized display driver. + * Automatically set the first display as active. + * @param driver pointer to an initialized 'lv_disp_drv_t' variable (can be local variable) + * @return pointer to the new display or NULL on error + */ +lv_disp_t * lv_disp_drv_register(lv_disp_drv_t *driver); + +/** + * Set the active display + * @param disp pointer to a display (return value of 'lv_disp_register') + */ +void lv_disp_set_active(lv_disp_t * disp); + +/** + * Get a pointer to the active display + * @return pointer to the active display + */ +lv_disp_t * lv_disp_get_active(void); + +/** + * 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_next(lv_disp_t * disp); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_p pointer to an array of colors + */ +void lv_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p); + +/** + * Fill a rectangular area with a color on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color fill color + */ +void lv_disp_fill(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t color); + +/** + * Put a color map to a rectangular area on the active display + * @param x1 left coordinate of the rectangle + * @param x2 right coordinate of the rectangle + * @param y1 top coordinate of the rectangle + * @param y2 bottom coordinate of the rectangle + * @param color_map pointer to an array of colors + */ +void lv_disp_map(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_map); + +#if USE_LV_GPU +/** + * Blend pixels to a destination memory from a source memory + * In 'lv_disp_drv_t' 'mem_blend' is optional. (NULL if not available) + * @param dest a memory address. Blend 'src' here. + * @param src pointer to pixel map. Blend it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa); + +/** + * Fill a memory with a color (GPUs may support it) + * In 'lv_disp_drv_t' 'mem_fill' is optional. (NULL if not available) + * @param dest a memory address. Copy 'src' here. + * @param src pointer to pixel map. Copy it to 'dest'. + * @param length number of pixels in 'src' + * @param opa opacity (0, LV_OPA_TRANSP: transparent ... 255, LV_OPA_COVER, fully cover) + */ +void lv_disp_mem_fill(lv_color_t * dest, uint32_t length, lv_color_t color); +/** + * Shows if memory blending (by GPU) is supported or not + * @return false: 'mem_blend' is not supported in the driver; true: 'mem_blend' is supported in the driver + */ +bool lv_disp_is_mem_blend_supported(void); + +/** + * Shows if memory fill (by GPU) is supported or not + * @return false: 'mem_fill' is not supported in the drover; true: 'mem_fill' is supported in the driver + */ +bool lv_disp_is_mem_fill_supported(void); +#endif +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_hal/lv_hal_indev.h b/include/display/lv_hal/lv_hal_indev.h new file mode 100644 index 0000000..0252dc4 --- /dev/null +++ b/include/display/lv_hal/lv_hal_indev.h @@ -0,0 +1,166 @@ +/** + * @file hal_indev.h + * + * @description Input Device HAL interface layer header file + * + */ + +#ifndef HAL_INDEV_H +#define HAL_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include +#include +#include "lv_hal.h" +#include "display/lv_misc/lv_area.h" +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Possible input device types*/ +enum { + LV_INDEV_TYPE_NONE, /*Show 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 assinged to a specific point of the screen*/ + LV_INDEV_TYPE_ENCODER, /*Encoder with only Left, Right turn and a Button*/ +}; +typedef uint8_t lv_hal_indev_type_t; + +/*States for input devices*/ +enum { + LV_INDEV_STATE_REL = 0, + LV_INDEV_STATE_PR +}; +typedef uint8_t lv_indev_state_t; + +/*Data type when an input device is read */ +typedef struct { + union { + 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; /*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*/ + }; + void *user_data; /*'lv_indev_drv_t.priv' for this driver*/ + lv_indev_state_t state; /*LV_INDEV_STATE_REL or LV_INDEV_STATE_PR*/ +} lv_indev_data_t; + +/*Initialized by the user and registered by 'lv_indev_add()'*/ +typedef struct { + lv_hal_indev_type_t type; /*Input device type*/ + bool (*read)(lv_indev_data_t *data); /*Function pointer to read data. Return 'true' if there is still data to be read (buffered)*/ + void *user_data; /*Pointer to user defined data, passed in 'lv_indev_data_t' on read*/ +} lv_indev_drv_t; + +struct _lv_obj_t; + +/*Run time data of input devices*/ +typedef struct _lv_indev_proc_t { + lv_indev_state_t state; + union { + struct { /*Pointer and button data*/ + lv_point_t act_point; + lv_point_t last_point; + lv_point_t vect; + lv_point_t drag_sum; /*Count the dragged pixels to check LV_INDEV_DRAG_LIMIT*/ + struct _lv_obj_t * act_obj; + struct _lv_obj_t * last_obj; + + /*Flags*/ + uint8_t drag_range_out :1; + uint8_t drag_in_prog :1; + uint8_t wait_unil_release :1; + }; + struct { /*Keypad data*/ + lv_indev_state_t last_state; + uint32_t last_key; + }; + }; + + uint32_t pr_timestamp; /*Pressed time stamp*/ + uint32_t longpr_rep_timestamp; /*Long press repeat time stamp*/ + + /*Flags*/ + uint8_t long_pr_sent :1; + uint8_t reset_query :1; + uint8_t disabled :1; +} lv_indev_proc_t; + +struct _lv_indev_t; + +typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, lv_signal_t); + +struct _lv_obj_t; +struct _lv_group_t; + +/*The main input device descriptor with driver, runtime data ('proc') and some additional information*/ +typedef struct _lv_indev_t { + lv_indev_drv_t driver; + lv_indev_proc_t proc; + lv_indev_feedback_t feedback; + uint32_t last_activity_time; + union { + 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*/ + + }; + struct _lv_indev_t *next; +} lv_indev_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize an input device 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 driver pointer to driver variable to initialize + */ +void lv_indev_drv_init(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(lv_indev_drv_t *driver); + +/** + * Get the next input device. + * @param indev pointer to the current input device. NULL to initialize. + * @return the next input devise or NULL if no more. Gives the first input device when the parameter is NULL + */ +lv_indev_t * lv_indev_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 + * @return false: no more data; true: there more data to read (buffered) + */ +bool lv_indev_read(lv_indev_t * indev, lv_indev_data_t *data); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_hal/lv_hal_tick.h b/include/display/lv_hal/lv_hal_tick.h new file mode 100644 index 0000000..c59ed0b --- /dev/null +++ b/include/display/lv_hal/lv_hal_tick.h @@ -0,0 +1,66 @@ +/** + * @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 + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include +#include + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TICK_INC +#define LV_ATTRIBUTE_TICK_INC +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * 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); + +/** + * 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 systick_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/display/lv_misc/lv_anim.h b/include/display/lv_misc/lv_anim.h new file mode 100644 index 0000000..b3b8553 --- /dev/null +++ b/include/display/lv_misc/lv_anim.h @@ -0,0 +1,177 @@ +/** + * @file anim.h + * + */ + +#ifndef ANIM_H +#define ANIM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ANIMATION + +#include +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_anim_t; + +typedef int32_t(*lv_anim_path_t)(const struct _lv_anim_t*); + +typedef void (*lv_anim_fp_t)(void *, int32_t); +typedef void (*lv_anim_cb_t)(void *); + +typedef struct _lv_anim_t +{ + void * var; /*Variable to animate*/ + lv_anim_fp_t fp; /*Animator function*/ + lv_anim_cb_t end_cb; /*Call it when the animation is ready*/ + lv_anim_path_t path; /*An array with the steps of animations*/ + int32_t start; /*Start value*/ + int32_t end; /*End value*/ + uint16_t time; /*Animation time in ms*/ + int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ + uint8_t playback :1; /*When the animation is ready play it back*/ + uint8_t repeat :1; /*Repeat the animation infinitely*/ + /*Animation system use these - user shouldn't set*/ + uint8_t playback_now :1; /*Play back is in progress*/ + uint32_t has_run :1; /*Indicates the animation has run it this round*/ +} lv_anim_t; + +/*Example initialization +lv_anim_t a; +a.var = obj; +a.start = lv_obj_get_height(obj); +a.end = new_height; +a.fp = (lv_anim_fp_t)lv_obj_set_height; +a.path = lv_anim_path_linear; +a.end_cb = NULL; +a.act_time = 0; +a.time = 200; +a.playback = 0; +a.playback_pause = 0; +a.repeat = 0; +a.repeat_pause = 0; +lv_anim_create(&a); + */ +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init. the animation module + */ +void lv_anim_init(void); + +/** + * Create an animation + * @param anim_p an initialized 'anim_t' variable. Not required after call. + */ +void lv_anim_create(lv_anim_t * anim_p); + +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool lv_anim_del(void * var, lv_anim_fp_t fp); + +/** + * 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 + */ +uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); + +/** + * 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); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ANIMATION == 0*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ANIM_H*/ + diff --git a/include/display/lv_misc/lv_area.h b/include/display/lv_misc/lv_area.h new file mode 100644 index 0000000..fc8b7de --- /dev/null +++ b/include/display/lv_misc/lv_area.h @@ -0,0 +1,169 @@ +/** + * @file lv_area.h + * + */ + +#ifndef LV_AREA_H +#define LV_AREA_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include +#include + +/********************* + * DEFINES + *********************/ +#define LV_COORD_MAX (16383) /*To avoid overflow don't let the max [-32,32k] range */ +#define LV_COORD_MIN (-16384) + +/********************** + * TYPEDEFS + **********************/ +typedef int16_t lv_coord_t; + +typedef struct +{ + lv_coord_t x; + lv_coord_t y; +} lv_point_t; + +typedef struct +{ + lv_coord_t x1; + lv_coord_t y1; + lv_coord_t x2; + lv_coord_t y2; +} lv_area_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) +{ + memcpy(dest, src, sizeof(lv_area_t)); +} + +/** + * 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 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 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); + +/** + * 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 + * @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); + +/** + * 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 on aholder_p + * @param aholder pointer to an area which could involve ain_p + * @return + */ +bool lv_area_is_in(const lv_area_t * ain_p, const lv_area_t * aholder_p); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/include/display/lv_misc/lv_circ.h b/include/display/lv_misc/lv_circ.h new file mode 100644 index 0000000..f2065f7 --- /dev/null +++ b/include/display/lv_misc/lv_circ.h @@ -0,0 +1,79 @@ +/** + * @file lv_circ.h + * + */ + +#ifndef LV_CIRC_H +#define LV_CIRC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_CIRC_OCT1_X(p) (p.x) +#define LV_CIRC_OCT1_Y(p) (p.y) +#define LV_CIRC_OCT2_X(p) (p.y) +#define LV_CIRC_OCT2_Y(p) (p.x) +#define LV_CIRC_OCT3_X(p) (-p.y) +#define LV_CIRC_OCT3_Y(p) (p.x) +#define LV_CIRC_OCT4_X(p) (-p.x) +#define LV_CIRC_OCT4_Y(p) (p.y) +#define LV_CIRC_OCT5_X(p) (-p.x) +#define LV_CIRC_OCT5_Y(p) (-p.y) +#define LV_CIRC_OCT6_X(p) (-p.y) +#define LV_CIRC_OCT6_Y(p) (-p.x) +#define LV_CIRC_OCT7_X(p) (p.y) +#define LV_CIRC_OCT7_Y(p) (-p.x) +#define LV_CIRC_OCT8_X(p) (p.x) +#define LV_CIRC_OCT8_Y(p) (-p.y) + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the circle drawing + * @param c pointer to a point. The coordinates will be calculated here + * @param tmp point to a variable. It will store temporary data + * @param radius radius of the circle + */ +void lv_circ_init(lv_point_t * c, lv_coord_t * tmp, lv_coord_t radius); + +/** + * Test the circle drawing is ready or not + * @param c same as in circ_init + * @return true if the circle is not ready yet + */ +bool lv_circ_cont(lv_point_t * c); + +/** + * Get the next point from the circle + * @param c same as in circ_init. The next point stored here. + * @param tmp same as in circ_init. + */ +void lv_circ_next(lv_point_t * c, lv_coord_t * tmp); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif diff --git a/include/display/lv_misc/lv_color.h b/include/display/lv_misc/lv_color.h new file mode 100644 index 0000000..e2da813 --- /dev/null +++ b/include/display/lv_misc/lv_color.h @@ -0,0 +1,445 @@ +/** + * @file lv_color.h + * + */ + +#ifndef LV_COLOR_H +#define LV_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/*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 != 32 && LV_COLOR_SCREEN_TRANSP != 0 +#error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in 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 + *********************/ +#define LV_COLOR_WHITE LV_COLOR_MAKE(0xFF,0xFF,0xFF) +#define LV_COLOR_SILVER LV_COLOR_MAKE(0xC0,0xC0,0xC0) +#define LV_COLOR_GRAY LV_COLOR_MAKE(0x80,0x80,0x80) +#define LV_COLOR_BLACK LV_COLOR_MAKE(0x00,0x00,0x00) +#define LV_COLOR_RED LV_COLOR_MAKE(0xFF,0x00,0x00) +#define LV_COLOR_MAROON LV_COLOR_MAKE(0x80,0x00,0x00) +#define LV_COLOR_YELLOW LV_COLOR_MAKE(0xFF,0xFF,0x00) +#define LV_COLOR_OLIVE LV_COLOR_MAKE(0x80,0x80,0x00) +#define LV_COLOR_LIME LV_COLOR_MAKE(0x00,0xFF,0x00) +#define LV_COLOR_GREEN LV_COLOR_MAKE(0x00,0x80,0x00) +#define LV_COLOR_CYAN LV_COLOR_MAKE(0x00,0xFF,0xFF) +#define LV_COLOR_AQUA LV_COLOR_CYAN +#define LV_COLOR_TEAL LV_COLOR_MAKE(0x00,0x80,0x80) +#define LV_COLOR_BLUE LV_COLOR_MAKE(0x00,0x00,0xFF) +#define LV_COLOR_NAVY LV_COLOR_MAKE(0x00,0x00,0x80) +#define LV_COLOR_MAGENTA LV_COLOR_MAKE(0xFF,0x00,0xFF) +#define LV_COLOR_PURPLE LV_COLOR_MAKE(0x80,0x00,0x80) +#define LV_COLOR_ORANGE LV_COLOR_MAKE(0xFF,0xA5,0x00) + +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 16 /*Opacities below this will be transparent*/ +#define LV_OPA_MAX 251 /*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 + +/********************** + * TYPEDEFS + **********************/ + +typedef union +{ + uint8_t blue :1; + uint8_t green :1; + uint8_t red :1; + uint8_t full :1; +} lv_color1_t; + +typedef union +{ + struct + { + uint8_t blue :2; + uint8_t green :3; + uint8_t red :3; + }; + 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 + }; + uint16_t full; +} lv_color16_t; + +typedef union +{ + struct + { + uint8_t blue; + uint8_t green; + uint8_t red; + uint8_t alpha; + }; + uint32_t full; +} lv_color32_t; + +#if LV_COLOR_DEPTH == 1 +typedef uint8_t lv_color_int_t; +typedef lv_color1_t lv_color_t; +#elif LV_COLOR_DEPTH == 8 +typedef uint8_t lv_color_int_t; +typedef lv_color8_t lv_color_t; +#elif LV_COLOR_DEPTH == 16 +typedef uint16_t lv_color_int_t; +typedef lv_color16_t lv_color_t; +#elif LV_COLOR_DEPTH == 32 +typedef uint32_t lv_color_int_t; +typedef lv_color32_t lv_color_t; +#else +#error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!" +#endif + +typedef uint8_t lv_opa_t; + +typedef struct +{ + uint16_t h; + uint8_t s; + uint8_t v; +} lv_color_hsv_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 2 bits + * ---------------------- + * 8 bit red LSB = (2^5 - 1) / (2^2 - 1) = 31 / 3 = 10 + * + * - When calculating to smaller color type simply shift out the LSBs + * E.g. 8 bit Red has 2 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((color.red & 0x4) || + (color.green & 0x4) || + (color.blue & 0x2)) { + return 1; + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + if((color.red & 0x10) || + (color.green & 0x20) || + (color.blue & 0x10)) { + return 1; +# else + if((color.red & 0x10) || + (color.green_h & 0x20) || + (color.blue & 0x10)) { + return 1; +# endif + } else { + return 0; + } +#elif LV_COLOR_DEPTH == 32 + if((color.red & 0x80) || + (color.green & 0x80) || + (color.blue & 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 + +# if LV_COLOR_16_SWAP == 0 + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green >> 3; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# else + lv_color8_t ret; + ret.red = color.red >> 2; /* 5 - 3 = 2*/ + ret.green = color.green_h; /* 6 - 3 = 3*/ + ret.blue = color.blue >> 3; /* 5 - 2 = 3*/ + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + lv_color8_t ret; + ret.red = color.red >> 5; /* 8 - 3 = 5*/ + ret.green = color.green >> 5; /* 8 - 3 = 5*/ + ret.blue = color.blue >> 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; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red * 4; /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/ + ret.green = color.green * 9; /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/ + ret.blue = color.blue * 10; /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/ +# else + ret.red = color.red * 4; + uint8_t g_tmp = color.green * 9; + ret.green_h = (g_tmp & 0x1F) >> 3; + ret.green_l = g_tmp & 0x07; + ret.blue = color.blue * 10; +# endif + return ret.full; +#elif LV_COLOR_DEPTH == 16 + return color.full; +#elif LV_COLOR_DEPTH == 32 + lv_color16_t ret; +# if LV_COLOR_16_SWAP == 0 + ret.red = color.red >> 3; /* 8 - 5 = 3*/ + ret.green = color.green >> 2; /* 8 - 6 = 2*/ + ret.blue = color.blue >> 3; /* 8 - 5 = 3*/ +# else + ret.red = color.red >> 3; + ret.green_h = (color.green & 0xE0) >> 5; + ret.green_l = (color.green & 0x1C) >> 2; + ret.blue = color.blue >> 3; +# endif + 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 0; + else return 0xFFFFFFFF; +#elif LV_COLOR_DEPTH == 8 + lv_color32_t ret; + ret.red = color.red * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.green = color.green * 36; /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/ + ret.blue = color.blue * 85; /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/ + ret.alpha = 0xFF; + return ret.full; +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = color.green * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# else + lv_color32_t ret; + ret.red = color.red * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.green = ((color.green_h << 3) + color.green_l) * 4; /*(2^8 - 1)/(2^6 - 1) = 255/63 = 4*/ + ret.blue = color.blue * 8; /*(2^8 - 1)/(2^5 - 1) = 255/31 = 8*/ + ret.alpha = 0xFF; + return ret.full; +# endif +#elif LV_COLOR_DEPTH == 32 + return color.full; +#endif +} + +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 != 1 + /*LV_COLOR_DEPTH == 8, 16 or 32*/ + ret.red = (uint16_t)((uint16_t) c1.red * mix + (c2.red * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP + /*If swapped Green is in 2 parts*/ + uint16_t g_1 = (c1.green_h << 3) + c1.green_l; + uint16_t g_2 = (c2.green_h << 3) + c2.green_l; + uint16_t g_out = (uint16_t)((uint16_t) g_1 * mix + (g_2 * (255 - mix))) >> 8; + ret.green_h = g_out >> 3; + ret.green_l = g_out & 0x7; +# else + ret.green = (uint16_t)((uint16_t) c1.green * mix + (c2.green * (255 - mix))) >> 8; +# endif + ret.blue = (uint16_t)((uint16_t) c1.blue * mix + (c2.blue * (255 - mix))) >> 8; +# if LV_COLOR_DEPTH == 32 + ret.alpha = 0xFF; +# endif +#else + /*LV_COLOR_DEPTH == 1*/ + ret.full = mix > LV_OPA_50 ? c1.full : c2.full; +#endif + + return ret; +} + +/** + * 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 = 3 * c32.red + c32.blue + 4 * c32.green; + return (uint16_t) bright >> 3; +} + +/* The most simple macro to create a color from R,G and B values + * The order of bit field is different on Big-endian and Little-endian machines*/ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(b8 >> 7 | g8 >> 7 | r8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 6, g8 >> 5, r8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +# if LV_COLOR_16_SWAP == 0 +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8 >> 3, g8 >> 2, r8 >> 3}}) +# else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{g8 >> 5, r8 >> 3, b8 >> 3, (g8 >> 2) & 0x7}}) +# endif +#elif LV_COLOR_DEPTH == 32 +#ifdef __cplusplus +# define LV_COLOR_MAKE(r8, g8, b8) lv_color_t{b8, g8, r8, 0xff} +#else +# define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{b8, g8, r8, 0xff}}) /*Fix 0xff alpha*/ +#endif +#endif +#else +#if LV_COLOR_DEPTH == 1 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){(r8 >> 7 | g8 >> 7 | b8 >> 7)}) +#elif LV_COLOR_DEPTH == 8 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 6, g8 >> 5, b8 >> 5}}) +#elif LV_COLOR_DEPTH == 16 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{r8 >> 3, g8 >> 2, b8 >> 3}}) +#elif LV_COLOR_DEPTH == 32 +#define LV_COLOR_MAKE(r8, g8, b8) ((lv_color_t){{0xff, r8, g8, b8}}) /*Fix 0xff alpha*/ +#endif +#endif + + +#define LV_COLOR_HEX(c) LV_COLOR_MAKE((uint8_t) ((uint32_t)((uint32_t)c >> 16) & 0xFF), \ + (uint8_t) ((uint32_t)((uint32_t)c >> 8) & 0xFF), \ + (uint8_t) ((uint32_t) c & 0xFF)) + +/*Usage LV_COLOR_HEX3(0x16C) which means LV_COLOR_HEX(0x1166CC)*/ +#define LV_COLOR_HEX3(c) LV_COLOR_MAKE((uint8_t) (((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), \ + (uint8_t) ((uint32_t)(c & 0xF0) | ((c & 0xF0) >> 4)), \ + (uint8_t) ((uint32_t)(c & 0xF) | ((c & 0xF) << 4))) + +static inline lv_color_t lv_color_hex(uint32_t c){ + return LV_COLOR_HEX(c); +} + +static inline lv_color_t lv_color_hex3(uint32_t c){ + return LV_COLOR_HEX3(c); +} + + +/** + * 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 an RGB color to HSV + * @param r red + * @param g green + * @param b blue + * @return the given RGB color n HSV + */ +lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_COLOR*/ diff --git a/include/display/lv_misc/lv_font.h b/include/display/lv_misc/lv_font.h new file mode 100644 index 0000000..0b1675c --- /dev/null +++ b/include/display/lv_misc/lv_font.h @@ -0,0 +1,192 @@ +/** + * @file lv_font.h + * + */ + +#ifndef LV_FONT_H +#define LV_FONT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include + +#include "lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t w_px :8; + uint32_t glyph_index :24; +} lv_font_glyph_dsc_t; + +typedef struct +{ + uint32_t unicode :21; + uint32_t glyph_dsc_index :11; +} lv_font_unicode_map_t; + +typedef struct _lv_font_struct +{ + uint32_t unicode_first; + uint32_t unicode_last; + const uint8_t * glyph_bitmap; + const lv_font_glyph_dsc_t * glyph_dsc; + const uint32_t * unicode_list; + const uint8_t * (*get_bitmap)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's bitmap from a font*/ + int16_t (*get_width)(const struct _lv_font_struct *,uint32_t); /*Get a glyph's with with a given font*/ + struct _lv_font_struct * next_page; /*Pointer to a font extension*/ + uint32_t h_px :8; + uint32_t bpp :4; /*Bit per pixel: 1, 2 or 4*/ + uint32_t monospace :8; /*Fix width (0: normal width)*/ + uint16_t glyph_cnt; /*Number of glyphs (letters) in the font*/ +} lv_font_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the fonts + */ +void lv_font_init(void); + +/** + * Add a font to an other to extend the character set. + * @param child the font to add + * @param parent this font will be extended. Using it later will contain the characters from `child` + */ +void lv_font_add(lv_font_t *child, lv_font_t *parent); + +/** + * Remove a font from a character set. + * @param child the font to remove + * @param parent remove `child` from here + */ +void lv_font_remove(lv_font_t * child, lv_font_t * parent); + +/** + * Tells if font which contains `letter` is monospace or not + * @param font_p point to font + * @param letter an UNICODE character code + * @return true: the letter is monospace; false not monospace + */ +bool lv_font_is_monospace(const lv_font_t * font_p, uint32_t letter); + +/** + * Return with the bitmap of a font. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return pointer to the bitmap of the letter + */ +const uint8_t * lv_font_get_bitmap(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the width of a letter in a font. If `monospace` is set then return with it. + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_width(const lv_font_t * font_p, uint32_t letter); + + +/** + * Get the width of the letter without overwriting it with the `monospace` attribute + * @param font_p pointer to a font + * @param letter an UNICODE character code + * @return the width of a letter + */ +uint8_t lv_font_get_real_width(const lv_font_t * font_p, uint32_t letter); + +/** + * Get the height of a font + * @param font_p pointer to a font + * @return the height of a font + */ +static inline uint8_t lv_font_get_height(const lv_font_t * font_p) +{ + return font_p->h_px; +} + +/** + * Get the bit-per-pixel of font + * @param font pointer to font + * @param letter a letter from font (font extensions can have different bpp) + * @return bpp of the font (or font extension) + */ +uint8_t lv_font_get_bpp(const lv_font_t * font, uint32_t letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic bitmap get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which bitmap should be get + * @return pointer to the bitmap or NULL if not found + */ +const uint8_t * lv_font_get_bitmap_sparse(const lv_font_t * font, uint32_t unicode_letter); +/** + * Generic glyph width get function used in 'font->get_width' when the font contains all characters in the range + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the gylph or -1 if not found + */ +int16_t lv_font_get_width_continuous(const lv_font_t * font, uint32_t unicode_letter); + +/** + * Generic glyph width get function used in 'font->get_bitmap' when the font NOT contains all characters in the range (sparse) + * @param font pointer to font + * @param unicode_letter an unicode letter which width should be get + * @return width of the glyph or -1 if not found + */ +int16_t lv_font_get_width_sparse(const lv_font_t * font, uint32_t unicode_letter); + +/********************** + * MACROS + **********************/ + +#define LV_FONT_DECLARE(font_name) extern lv_font_t font_name + + +/********************** + * ADD BUILT IN FONTS + **********************/ +#include "display/lv_fonts/lv_font_builtin.h" + +/*Declare the custom (user defined) fonts*/ +#ifdef LV_FONT_CUSTOM_DECLARE +LV_FONT_CUSTOM_DECLARE +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*USE_FONT*/ + diff --git a/include/display/lv_misc/lv_fs.h b/include/display/lv_misc/lv_fs.h new file mode 100644 index 0000000..845b479 --- /dev/null +++ b/include/display/lv_misc/lv_fs.h @@ -0,0 +1,277 @@ +/** + * @file lv_fs.h + * + */ + +#ifndef LV_FS_H +#define LV_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define LV_FS_MAX_FN_LENGTH 64 + +/********************** + * TYPEDEFS + **********************/ +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; + +struct __lv_fs_drv_t; + +typedef struct +{ + void * file_d; + struct __lv_fs_drv_t* drv; +} lv_fs_file_t; + + +typedef struct +{ + void * dir_d; + struct __lv_fs_drv_t * drv; +} lv_fs_dir_t; + +enum +{ + LV_FS_MODE_WR = 0x01, + LV_FS_MODE_RD = 0x02, +}; +typedef uint8_t lv_fs_mode_t; + +typedef struct __lv_fs_drv_t +{ + char letter; + uint16_t file_size; + uint16_t rddir_size; + bool (*ready) (void); + + lv_fs_res_t (*open) (void * file_p, const char * path, lv_fs_mode_t mode); + lv_fs_res_t (*close) (void * file_p); + lv_fs_res_t (*remove) (const char * fn); + lv_fs_res_t (*read) (void * file_p, void * buf, uint32_t btr, uint32_t * br); + lv_fs_res_t (*write) (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + lv_fs_res_t (*seek) (void * file_p, uint32_t pos); + lv_fs_res_t (*tell) (void * file_p, uint32_t * pos_p); + lv_fs_res_t (*trunc) (void * file_p); + lv_fs_res_t (*size) (void * file_p, uint32_t * size_p); + lv_fs_res_t (*rename) (const char * oldname, const char * newname); + lv_fs_res_t (*free) (uint32_t * total_p, uint32_t * free_p); + + lv_fs_res_t (*dir_open) (void * rddir_p, const char * path); + lv_fs_res_t (*dir_read) (void * rddir_p, char * fn); + lv_fs_res_t (*dir_close) (void * rddir_p); +} lv_fs_drv_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the File system interface + */ +void lv_fs_init(void); + +/** + * Add a new drive + * @param drv_p pointer to an lv_fs_drv_t structure which is inited with the + * corresponding function pointers. The data will be copied so the variable can be local. + */ +void lv_fs_add_drv(lv_fs_drv_t * drv_p); + +/** + * Test if a drive is rady 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); + +/** + * Delete a file + * @param path path of the file to delete + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_remove (const char * path); + +/** + * 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 btr Bytes To Write + * @param br 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) + * @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); + +/** + * 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); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_fs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_trunc (lv_fs_file_t * file_p); + +/** + * Give the size of a file bytes + * @param file_p pointer to a lv_fs_file_t variable + * @param size pointer to a variable to store the size + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_size (lv_fs_file_t * file_p, uint32_t * size); + +/** + * Rename a file + * @param oldname path to the file + * @param newname path with the new name + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_fs_rename (const char * oldname, const char * newname); + +/** + * Initialize a 'fs_dir_t' variable for directory reading + * @param rddir_p pointer to a 'fs_read_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_rdir_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); + +/** + * Get the free and total size of a driver in kB + * @param letter the driver letter + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free size [kB] + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_fs_free (char letter, uint32_t * total_p, uint32_t * free_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 buf buffer to store the letters ('\0' added after the last letter) + * @return pointer to the beginning of the last element in the path + */ +const char * lv_fs_get_last(const char * path); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FS_H*/ diff --git a/include/display/lv_misc/lv_gc.h b/include/display/lv_misc/lv_gc.h new file mode 100644 index 0000000..e3d0d8a --- /dev/null +++ b/include/display/lv_misc/lv_gc.h @@ -0,0 +1,77 @@ +/** + * @file lv_gc.h + * + */ + +#ifndef LV_GC_H +#define LV_GC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ + +#define LV_GC_ROOTS(prefix) \ + prefix lv_ll_t _lv_task_ll; /*Linked list to store the lv_tasks*/ \ + prefix lv_ll_t _lv_scr_ll; /*Linked list of screens*/ \ + prefix lv_ll_t _lv_drv_ll;\ + prefix lv_ll_t _lv_file_ll;\ + prefix lv_ll_t _lv_anim_ll;\ + prefix void * _lv_def_scr;\ + prefix void * _lv_act_scr;\ + prefix void * _lv_top_layer;\ + prefix void * _lv_sys_layer;\ + prefix void * _lv_task_act;\ + prefix void * _lv_indev_list;\ + prefix void * _lv_disp_list;\ + + +#define LV_NO_PREFIX +#define LV_ROOTS LV_GC_ROOTS(LV_NO_PREFIX) + +#if LV_ENABLE_GC == 1 +# if LV_MEM_CUSTOM != 1 +# error "GC requires CUSTOM_MEM" +# endif /* LV_MEM_CUSTOM */ +#else /* LV_ENABLE_GC */ +# define LV_GC_ROOT(x) x + LV_GC_ROOTS(extern) +#endif /* LV_ENABLE_GC */ + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GC_H*/ diff --git a/include/display/lv_misc/lv_ll.h b/include/display/lv_misc/lv_ll.h new file mode 100644 index 0000000..086ba40 --- /dev/null +++ b/include/display/lv_misc/lv_ll.h @@ -0,0 +1,145 @@ +/** + * @file lv_ll.c + * 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 "lv_mem.h" +#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_dsc pointer to ll_dsc 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 head + */ +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 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_rem(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 + */ +void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node); + +/** + * 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 head 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); + +/** + * Move a nodw 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); + +/********************** + * MACROS + **********************/ + +#define LL_READ(list, i) for(i = lv_ll_get_head(&list); i != NULL; i = lv_ll_get_next(&list, i)) + +#define 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/display/lv_misc/lv_log.h b/include/display/lv_misc/lv_log.h new file mode 100644 index 0000000..adcb846 --- /dev/null +++ b/include/display/lv_misc/lv_log.h @@ -0,0 +1,86 @@ +/** + * @file lv_log.h + * + */ + +#ifndef LV_LOG_H +#define LV_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif +#include + +/********************* + * DEFINES + *********************/ + +/*Possible log level. For compatibility declare it independently from `USE_LV_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_NUM 4 + +typedef int8_t lv_log_level_t; + +#if USE_LV_LOG +/********************** + * TYPEDEFS + **********************/ + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Register custom print (or anything else) function to call when log is added + * @param f a function pointer: + * `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char * dsc)` + */ +void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *)); + +/** + * 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 dsc description of the log + */ +void lv_log_add(lv_log_level_t level, const char * file, int line, const char * dsc); + +/********************** + * MACROS + **********************/ + +#define LV_LOG_TRACE(dsc) lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, dsc); +#define LV_LOG_INFO(dsc) lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, dsc); +#define LV_LOG_WARN(dsc) lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, dsc); +#define LV_LOG_ERROR(dsc) lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, dsc); + +#else /*USE_LV_LOG*/ + +/*Do nothing if `USE_LV_LOG 0`*/ +#define lv_log_add(level, file, line, dsc) {;} +#define LV_LOG_TRACE(dsc) {;} +#define LV_LOG_INFO(dsc) {;} +#define LV_LOG_WARN(dsc) {;} +#define LV_LOG_ERROR(dsc) {;} +#endif /*USE_LV_LOG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LOG_H*/ diff --git a/include/display/lv_misc/lv_math.h b/include/display/lv_misc/lv_math.h new file mode 100644 index 0000000..a0229eb --- /dev/null +++ b/include/display/lv_misc/lv_math.h @@ -0,0 +1,73 @@ +/** + * @file math_base.h + * + */ + +#ifndef LV_MATH_H +#define LV_MATH_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#include + +/********************* + * DEFINES + *********************/ +#define LV_MATH_MIN(a,b) ((a) < (b) ? (a) : (b)) +#define LV_MATH_MAX(a,b) ((a) > (b) ? (a) : (b)) +#define LV_MATH_ABS(x) ((x) > 0 ? (x) : (-(x))) + +#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 + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Convert a number to string + * @param num a number + * @param buf pointer to a `char` buffer. The result will be stored here (max 10 elements) + * @return same as `buf` (just for convenience) + */ +char * lv_math_num_to_str(int32_t num, char * buf); + +/** + * Return with sinus of an angle + * @param angle + * @return sinus of 'angle'. sin(-90) = -32767, sin(90) = 32767 + */ +int16_t lv_trigo_sin(int16_t angle); + +/** + * 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] + */ +int32_t lv_bezier3(uint32_t t, int32_t u0, int32_t u1, int32_t u2, int32_t u3); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_misc/lv_mem.h b/include/display/lv_misc/lv_mem.h new file mode 100644 index 0000000..7742901 --- /dev/null +++ b/include/display/lv_misc/lv_mem.h @@ -0,0 +1,127 @@ +/** + * @file lv_mem.h + * + */ + +#ifndef LV_MEM_H +#define LV_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_log.h" + +/********************* + * DEFINES + *********************/ +// Check windows +#ifdef __WIN64 +# define LV_MEM_ENV64 +#endif + +// Check GCC +#ifdef __GNUC__ +# if defined(__x86_64__) || defined(__ppc64__) +# define LV_MEM_ENV64 +# endif +#endif + +/********************** + * TYPEDEFS + **********************/ + +typedef struct +{ + uint32_t total_size; + uint32_t free_cnt; + uint32_t free_size; + uint32_t free_biggest_size; + uint32_t used_cnt; + uint8_t used_pct; + uint8_t frag_pct; +} lv_mem_monitor_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Initiaize the dyn_mem module (work memory and other variables) + */ +void lv_mem_init(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(uint32_t size); + +/** + * Free an allocated data + * @param data pointer to an allocated memory + */ +void lv_mem_free(const 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 + */ +void * lv_mem_realloc(void * data_p, uint32_t new_size); + +/** + * Join the adjacent free memory blocks + */ +void lv_mem_defrag(void); + +/** + * Give information about the work memory of dynamic allocation + * @param mon_p pointer to a dm_mon_p variable, + * the result of the analysis will be stored here + */ +void lv_mem_monitor(lv_mem_monitor_t * mon_p); + +/** + * Give the size of an allocated memory + * @param data pointer to an allocated memory + * @return the size of data memory in bytes + */ +uint32_t lv_mem_get_size(const void * data); + + +/********************** + * MACROS + **********************/ + +/** + * Halt on NULL pointer + * p pointer to a memory + */ +#if USE_LV_LOG == 0 +# define lv_mem_assert(p) {if(p == NULL) while(1); } +#else +# define lv_mem_assert(p) {if(p == NULL) {LV_LOG_ERROR("Out of memory!"); while(1); }} +#endif +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MEM_H*/ + diff --git a/include/display/lv_misc/lv_misc.mk b/include/display/lv_misc/lv_misc.mk new file mode 100644 index 0000000..470f123 --- /dev/null +++ b/include/display/lv_misc/lv_misc.mk @@ -0,0 +1,19 @@ +CSRCS += lv_font.c +CSRCS += lv_circ.c +CSRCS += lv_area.c +CSRCS += lv_task.c +CSRCS += lv_fs.c +CSRCS += lv_anim.c +CSRCS += lv_mem.c +CSRCS += lv_ll.c +CSRCS += lv_color.c +CSRCS += lv_txt.c +CSRCS += lv_ufs.c +CSRCS += lv_math.c +CSRCS += lv_log.c +CSRCS += lv_gc.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_misc +VPATH += :$(LVGL_DIR)/lvgl/lv_misc + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_misc" diff --git a/include/display/lv_misc/lv_symbol_def.h b/include/display/lv_misc/lv_symbol_def.h new file mode 100644 index 0000000..6ba6241 --- /dev/null +++ b/include/display/lv_misc/lv_symbol_def.h @@ -0,0 +1,207 @@ +#ifndef LV_SYMBOL_DEF_H +#define LV_SYMBOL_DEF_H + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +/* + * With no UTF-8 support (192- 255) (192..241 is used) + * + * With UTF-8 support (in Supplemental Private Use Area-A): 0xF800 .. 0xF831 + * - Basic symbols: 0xE000..0xE01F + * - File symbols: 0xE020..0xE03F + * - Feedback symbols: 0xE040..0xE05F + * - Reserved: 0xE060..0xE07F + */ + +#if LV_TXT_UTF8 == 0 +#define LV_SYMBOL_GLYPH_FIRST 0xC0 +#define SYMBOL_AUDIO _SYMBOL_VALUE1(C0) +#define SYMBOL_VIDEO _SYMBOL_VALUE1(C1) +#define SYMBOL_LIST _SYMBOL_VALUE1(C2) +#define SYMBOL_OK _SYMBOL_VALUE1(C3) +#define SYMBOL_CLOSE _SYMBOL_VALUE1(C4) +#define SYMBOL_POWER _SYMBOL_VALUE1(C5) +#define SYMBOL_SETTINGS _SYMBOL_VALUE1(C6) +#define SYMBOL_TRASH _SYMBOL_VALUE1(C7) +#define SYMBOL_HOME _SYMBOL_VALUE1(C8) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE1(C9) +#define SYMBOL_DRIVE _SYMBOL_VALUE1(CA) +#define SYMBOL_REFRESH _SYMBOL_VALUE1(CB) +#define SYMBOL_MUTE _SYMBOL_VALUE1(CC) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE1(CD) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE1(CE) +#define SYMBOL_IMAGE _SYMBOL_VALUE1(CF) +#define SYMBOL_EDIT _SYMBOL_VALUE1(D0) +#define SYMBOL_PREV _SYMBOL_VALUE1(D1) +#define SYMBOL_PLAY _SYMBOL_VALUE1(D2) +#define SYMBOL_PAUSE _SYMBOL_VALUE1(D3) +#define SYMBOL_STOP _SYMBOL_VALUE1(D4) +#define SYMBOL_NEXT _SYMBOL_VALUE1(D5) +#define SYMBOL_EJECT _SYMBOL_VALUE1(D6) +#define SYMBOL_LEFT _SYMBOL_VALUE1(D7) +#define SYMBOL_RIGHT _SYMBOL_VALUE1(D8) +#define SYMBOL_PLUS _SYMBOL_VALUE1(D9) +#define SYMBOL_MINUS _SYMBOL_VALUE1(DA) +#define SYMBOL_WARNING _SYMBOL_VALUE1(DB) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE1(DC) +#define SYMBOL_UP _SYMBOL_VALUE1(DD) +#define SYMBOL_DOWN _SYMBOL_VALUE1(DE) +#define SYMBOL_LOOP _SYMBOL_VALUE1(DF) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE1(E0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE1(E1) +#define SYMBOL_CALL _SYMBOL_VALUE1(E2) +#define SYMBOL_CUT _SYMBOL_VALUE1(E3) +#define SYMBOL_COPY _SYMBOL_VALUE1(E4) +#define SYMBOL_SAVE _SYMBOL_VALUE1(E5) +#define SYMBOL_CHARGE _SYMBOL_VALUE1(E6) +#define SYMBOL_BELL _SYMBOL_VALUE1(E7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE1(E8) +#define SYMBOL_GPS _SYMBOL_VALUE1(E9) +#define SYMBOL_FILE _SYMBOL_VALUE1(EA) +#define SYMBOL_WIFI _SYMBOL_VALUE1(EB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE1(EC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE1(ED) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE1(EE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE1(EF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE1(F0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE1(F1) +#define LV_SYMBOL_GLYPH_LAST 0xF1 +#define SYMBOL_DUMMY _SYMBOL_VALUE1(FF) /*Invalid symbol. If written before a string then `lv_img` will show it as a label*/ + +#else +#define LV_SYMBOL_GLYPH_FIRST 0xF800 +#define SYMBOL_AUDIO _SYMBOL_VALUE3(EF,A0,80) +#define SYMBOL_VIDEO _SYMBOL_VALUE3(EF,A0,81) +#define SYMBOL_LIST _SYMBOL_VALUE3(EF,A0,82) +#define SYMBOL_OK _SYMBOL_VALUE3(EF,A0,83) +#define SYMBOL_CLOSE _SYMBOL_VALUE3(EF,A0,84) +#define SYMBOL_POWER _SYMBOL_VALUE3(EF,A0,85) +#define SYMBOL_SETTINGS _SYMBOL_VALUE3(EF,A0,86) +#define SYMBOL_TRASH _SYMBOL_VALUE3(EF,A0,87) +#define SYMBOL_HOME _SYMBOL_VALUE3(EF,A0,88) +#define SYMBOL_DOWNLOAD _SYMBOL_VALUE3(EF,A0,89) +#define SYMBOL_DRIVE _SYMBOL_VALUE3(EF,A0,8A) +#define SYMBOL_REFRESH _SYMBOL_VALUE3(EF,A0,8B) +#define SYMBOL_MUTE _SYMBOL_VALUE3(EF,A0,8C) +#define SYMBOL_VOLUME_MID _SYMBOL_VALUE3(EF,A0,8D) +#define SYMBOL_VOLUME_MAX _SYMBOL_VALUE3(EF,A0,8E) +#define SYMBOL_IMAGE _SYMBOL_VALUE3(EF,A0,8F) +#define SYMBOL_EDIT _SYMBOL_VALUE3(EF,A0,90) +#define SYMBOL_PREV _SYMBOL_VALUE3(EF,A0,91) +#define SYMBOL_PLAY _SYMBOL_VALUE3(EF,A0,92) +#define SYMBOL_PAUSE _SYMBOL_VALUE3(EF,A0,93) +#define SYMBOL_STOP _SYMBOL_VALUE3(EF,A0,94) +#define SYMBOL_NEXT _SYMBOL_VALUE3(EF,A0,95) +#define SYMBOL_EJECT _SYMBOL_VALUE3(EF,A0,96) +#define SYMBOL_LEFT _SYMBOL_VALUE3(EF,A0,97) +#define SYMBOL_RIGHT _SYMBOL_VALUE3(EF,A0,98) +#define SYMBOL_PLUS _SYMBOL_VALUE3(EF,A0,99) +#define SYMBOL_MINUS _SYMBOL_VALUE3(EF,A0,9A) +#define SYMBOL_WARNING _SYMBOL_VALUE3(EF,A0,9B) +#define SYMBOL_SHUFFLE _SYMBOL_VALUE3(EF,A0,9C) +#define SYMBOL_UP _SYMBOL_VALUE3(EF,A0,9D) +#define SYMBOL_DOWN _SYMBOL_VALUE3(EF,A0,9E) +#define SYMBOL_LOOP _SYMBOL_VALUE3(EF,A0,9F) +#define SYMBOL_DIRECTORY _SYMBOL_VALUE3(EF,A0,A0) +#define SYMBOL_UPLOAD _SYMBOL_VALUE3(EF,A0,A1) +#define SYMBOL_CALL _SYMBOL_VALUE3(EF,A0,A2) +#define SYMBOL_CUT _SYMBOL_VALUE3(EF,A0,A3) +#define SYMBOL_COPY _SYMBOL_VALUE3(EF,A0,A4) +#define SYMBOL_SAVE _SYMBOL_VALUE3(EF,A0,A5) +#define SYMBOL_CHARGE _SYMBOL_VALUE3(EF,A0,A6) +#define SYMBOL_BELL _SYMBOL_VALUE3(EF,A0,A7) +#define SYMBOL_KEYBOARD _SYMBOL_VALUE3(EF,A0,A8) +#define SYMBOL_GPS _SYMBOL_VALUE3(EF,A0,A9) +#define SYMBOL_FILE _SYMBOL_VALUE3(EF,A0,AA) +#define SYMBOL_WIFI _SYMBOL_VALUE3(EF,A0,AB) +#define SYMBOL_BATTERY_FULL _SYMBOL_VALUE3(EF,A0,AC) +#define SYMBOL_BATTERY_3 _SYMBOL_VALUE3(EF,A0,AD) +#define SYMBOL_BATTERY_2 _SYMBOL_VALUE3(EF,A0,AE) +#define SYMBOL_BATTERY_1 _SYMBOL_VALUE3(EF,A0,AF) +#define SYMBOL_BATTERY_EMPTY _SYMBOL_VALUE3(EF,A0,B0) +#define SYMBOL_BLUETOOTH _SYMBOL_VALUE3(EF,A0,B1) +#define LV_SYMBOL_GLYPH_LAST 0xF831 +#define SYMBOL_DUMMY _SYMBOL_VALUE3(EF,A3,BF) /*Invalid symbol at (U+F831). If written before a string then `lv_img` will show it as a label*/ +#endif + +#define _SYMBOL_VALUE1(x) (0x ## x) +#define _SYMBOL_VALUE3(x, y, z) (0x ## z ## y ## x) +#define _SYMBOL_NUMSTR(sym) LV_ ## sym ## _NUMSTR = sym + +enum +{ + _SYMBOL_NUMSTR(SYMBOL_AUDIO), + _SYMBOL_NUMSTR(SYMBOL_VIDEO), + _SYMBOL_NUMSTR(SYMBOL_LIST), + _SYMBOL_NUMSTR(SYMBOL_OK), + _SYMBOL_NUMSTR(SYMBOL_CLOSE), + _SYMBOL_NUMSTR(SYMBOL_POWER), + _SYMBOL_NUMSTR(SYMBOL_SETTINGS), + _SYMBOL_NUMSTR(SYMBOL_TRASH), + _SYMBOL_NUMSTR(SYMBOL_HOME), + _SYMBOL_NUMSTR(SYMBOL_DOWNLOAD), + _SYMBOL_NUMSTR(SYMBOL_DRIVE), + _SYMBOL_NUMSTR(SYMBOL_REFRESH), + _SYMBOL_NUMSTR(SYMBOL_MUTE), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MID), + _SYMBOL_NUMSTR(SYMBOL_VOLUME_MAX), + _SYMBOL_NUMSTR(SYMBOL_IMAGE), + _SYMBOL_NUMSTR(SYMBOL_EDIT), + _SYMBOL_NUMSTR(SYMBOL_PREV), + _SYMBOL_NUMSTR(SYMBOL_PLAY), + _SYMBOL_NUMSTR(SYMBOL_PAUSE), + _SYMBOL_NUMSTR(SYMBOL_STOP), + _SYMBOL_NUMSTR(SYMBOL_NEXT), + _SYMBOL_NUMSTR(SYMBOL_EJECT), + _SYMBOL_NUMSTR(SYMBOL_LEFT), + _SYMBOL_NUMSTR(SYMBOL_RIGHT), + _SYMBOL_NUMSTR(SYMBOL_PLUS), + _SYMBOL_NUMSTR(SYMBOL_MINUS), + _SYMBOL_NUMSTR(SYMBOL_WARNING), + _SYMBOL_NUMSTR(SYMBOL_SHUFFLE), + _SYMBOL_NUMSTR(SYMBOL_UP), + _SYMBOL_NUMSTR(SYMBOL_DOWN), + _SYMBOL_NUMSTR(SYMBOL_LOOP), + _SYMBOL_NUMSTR(SYMBOL_DIRECTORY), + _SYMBOL_NUMSTR(SYMBOL_UPLOAD), + _SYMBOL_NUMSTR(SYMBOL_CALL), + _SYMBOL_NUMSTR(SYMBOL_CUT), + _SYMBOL_NUMSTR(SYMBOL_COPY), + _SYMBOL_NUMSTR(SYMBOL_SAVE), + _SYMBOL_NUMSTR(SYMBOL_CHARGE), + _SYMBOL_NUMSTR(SYMBOL_BELL), + _SYMBOL_NUMSTR(SYMBOL_KEYBOARD), + _SYMBOL_NUMSTR(SYMBOL_GPS), + _SYMBOL_NUMSTR(SYMBOL_FILE), + _SYMBOL_NUMSTR(SYMBOL_WIFI), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_FULL), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_3), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_2), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_1), + _SYMBOL_NUMSTR(SYMBOL_BATTERY_EMPTY), + _SYMBOL_NUMSTR(SYMBOL_BLUETOOTH), + _SYMBOL_NUMSTR(SYMBOL_DUMMY), +}; + +#undef _SYMBOL_VALUE1 +#undef _SYMBOL_VALUE3 + +#define _SYMBOL_STR_(x) #x +#define _SYMBOL_STR(x) _SYMBOL_STR_(x) +#define _SYMBOL_CHAR(c) \x ## c +#define _SYMBOL_VALUE1(x) _SYMBOL_STR(_SYMBOL_CHAR(x)) +#define _SYMBOL_VALUE3(x, y, z) _SYMBOL_STR(_SYMBOL_CHAR(x)_SYMBOL_CHAR(y)_SYMBOL_CHAR(z)) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*LV_SYMBOL_DEF_H*/ diff --git a/include/display/lv_misc/lv_task.h b/include/display/lv_misc/lv_task.h new file mode 100644 index 0000000..6cac3ef --- /dev/null +++ b/include/display/lv_misc/lv_task.h @@ -0,0 +1,149 @@ +/** + * @file lv_task.c + * An 'lv_task' is a void (*fp) (void* param) type function which will be called periodically. + * A priority (5 levels + disable) can be assigned to lv_tasks. + */ + +#ifndef LV_TASK_H +#define LV_TASK_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include +#include "lv_mem.h" +#include "lv_ll.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_ATTRIBUTE_TASK_HANDLER +#define LV_ATTRIBUTE_TASK_HANDLER +#endif +/********************** + * TYPEDEFS + **********************/ +/** + * Possible priorities for lv_tasks + */ +enum +{ + LV_TASK_PRIO_OFF = 0, + LV_TASK_PRIO_LOWEST, + LV_TASK_PRIO_LOW, + LV_TASK_PRIO_MID, + LV_TASK_PRIO_HIGH, + LV_TASK_PRIO_HIGHEST, + LV_TASK_PRIO_NUM, +}; +typedef uint8_t lv_task_prio_t; + +/** + * Descriptor of a lv_task + */ +typedef struct +{ + uint32_t period; + uint32_t last_run; + void (*task) (void*); + void * param; + uint8_t prio:3; + uint8_t once:1; +} lv_task_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Init the lv_task module + */ +void lv_task_init(void); + +/** + * Call it periodically to handle lv_tasks. + */ +LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void); + +/** + * Create a new lv_task + * @param task a function which is the task itself + * @param period call period in ms unit + * @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped) + * @param param free parameter + * @return pointer to the new task + */ +lv_task_t* lv_task_create(void (*task) (void *), uint32_t period, lv_task_prio_t prio, void * param); + +/** + * Delete a lv_task + * @param lv_task_p pointer to task created by lv_task_p + */ +void lv_task_del(lv_task_t* lv_task_p); + +/** + * Set new priority for a lv_task + * @param lv_task_p pointer to a lv_task + * @param prio the new priority + */ +void lv_task_set_prio(lv_task_t* lv_task_p, lv_task_prio_t prio); + +/** + * Set new period for a lv_task + * @param lv_task_p pointer to a lv_task + * @param period the new period + */ +void lv_task_set_period(lv_task_t* lv_task_p, uint32_t period); + +/** + * Make a lv_task ready. It will not wait its period. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_ready(lv_task_t* lv_task_p); + + +/** + * Delete the lv_task after one call + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_once(lv_task_t * lv_task_p); + +/** + * Reset a lv_task. + * It will be called the previously set period milliseconds later. + * @param lv_task_p pointer to a lv_task. + */ +void lv_task_reset(lv_task_t* lv_task_p); + +/** + * Enable or disable the whole lv_task handling + * @param en: true: lv_task handling is running, false: lv_task handling is suspended + */ +void lv_task_enable(bool en); + +/** + * Get idle percentage + * @return the lv_task idle in percentage + */ +uint8_t lv_task_get_idle(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_misc/lv_templ.h b/include/display/lv_misc/lv_templ.h new file mode 100644 index 0000000..a5459e8 --- /dev/null +++ b/include/display/lv_misc/lv_templ.h @@ -0,0 +1,38 @@ +/** + * @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/display/lv_misc/lv_txt.h b/include/display/lv_misc/lv_txt.h new file mode 100644 index 0000000..2e98b60 --- /dev/null +++ b/include/display/lv_misc/lv_txt.h @@ -0,0 +1,198 @@ +/** + * @file lv_text.h + * + */ + +#ifndef LV_TXT_H +#define LV_TXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include +#include "lv_area.h" +#include "lv_font.h" +#include "lv_area.h" + +/********************* + * DEFINES + *********************/ +#define LV_TXT_COLOR_CMD "#" + +/********************** + * TYPEDEFS + **********************/ +enum +{ + LV_TXT_FLAG_NONE = 0x00, + LV_TXT_FLAG_RECOLOR = 0x01, /*Enable parsing of recolor command*/ + LV_TXT_FLAG_EXPAND = 0x02, /*Ignore width to avoid automatic word wrapping*/ + LV_TXT_FLAG_CENTER = 0x04, /*Align the text to the middle*/ + LV_TXT_FLAG_RIGHT = 0x08, /*Align the text to the right*/ +}; +typedef uint8_t lv_txt_flag_t; + +enum +{ + LV_TXT_CMD_STATE_WAIT, /*Waiting for command*/ + LV_TXT_CMD_STATE_PAR, /*Processing the parameter*/ + LV_TXT_CMD_STATE_IN, /*Processing the command*/ +}; +typedef uint8_t lv_txt_cmd_state_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 pinter 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 'txt_flag_t' enum + * @param max_width max with of the text (break the lines to fit this size) Set CORD_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_txt_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 with of the text (break the lines to fit this size) Set CORD_MAX to avoid line breaks + * @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) + */ +uint16_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_txt_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, uint16_t length, + const lv_font_t * font, lv_coord_t letter_space, lv_txt_flag_t flag); + + +/** + * Check next character in a string and decide if te 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_txt_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) + * @param pos position to insert (0: before the original text, 1: after the first char etc.) + * @param ins_txt text to insert + */ +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 + * @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); + +/*************************************************************** + * GLOBAL FUNCTION POINTERS FOR CAHRACTER 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 an Unicode letter to encoded + * @param letter_uni an 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 an 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_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 /*USE_TXT*/ diff --git a/include/display/lv_misc/lv_ufs.h b/include/display/lv_misc/lv_ufs.h new file mode 100644 index 0000000..d30cbe0 --- /dev/null +++ b/include/display/lv_misc/lv_ufs.h @@ -0,0 +1,214 @@ +/** + * @file lv_ufs.h + * Implementation of RAM file system which do NOT support directories. + * The API is compatible with the lv_fs_int module. + */ + +#ifndef LV_UFS_H +#define LV_UFS_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_FILESYSTEM + +#include +#include "lv_fs.h" +#include "lv_mem.h" + +/********************* + * DEFINES + *********************/ +#define UFS_LETTER 'U' + +/********************** + * TYPEDEFS + **********************/ +/*Description of a file entry */ +typedef struct +{ + char * fn_d; + void * data_d; + uint32_t size; /*Data length in bytes*/ + uint16_t oc; /*Open Count*/ + uint8_t const_data :1; +} lv_ufs_ent_t; + +/*File descriptor, used to handle opening an entry more times simultaneously + Contains unique informations about the specific opening*/ +typedef struct +{ + lv_ufs_ent_t* ent; /*Pointer to the entry*/ + uint32_t rwp; /*Read Write Pointer*/ + uint8_t ar :1; /*1: Access for read is enabled */ + uint8_t aw :1; /*1: Access for write is enabled */ +} lv_ufs_file_t; + +/* Read directory descriptor. + * It is used to to iterate through the entries in a directory*/ +typedef struct +{ + lv_ufs_ent_t * last_ent; +} lv_ufs_dir_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a driver for ufs and initialize it. + */ +void lv_ufs_init(void); + +/** + * Give the state of the ufs + * @return true if ufs is initialized and can be used else false + */ +bool lv_ufs_ready(void); + +/** + * Open a file in ufs + * @param file_p pointer to a lv_ufs_file_t variable + * @param fn name of the file. There are no directories so e.g. "myfile.txt" + * @param mode element of 'fs_mode_t' enum or its 'OR' connection (e.g. FS_MODE_WR | FS_MODE_RD) + * @return LV_FS_RES_OK: no error, the file is opened + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_open (void * file_p, const char * fn, lv_fs_mode_t mode); + +/** + * Create a file with a constant data + * @param fn name of the file (directories are not supported) + * @param const_p pointer to a constant data + * @param len length of the data pointed by 'const_p' in bytes + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_create_const(const char * fn, const void * const_p, uint32_t len); + +/** + * Close an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_close (void * file_p); + +/** + * Remove a file. The file can not be opened. + * @param fn '\0' terminated string + * @return LV_FS_RES_OK: no error, the file is removed + * LV_FS_RES_DENIED: the file was opened, remove failed + */ +lv_fs_res_t lv_ufs_remove(const char * fn); + +/** + * Read data from an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param buf pointer to a memory block where to store the read data + * @param btr number of Bytes To Read + * @param br the real number of read bytes (Byte Read) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_read (void * file_p, void * buf, uint32_t btr, uint32_t * br); + +/** + * Write data to an opened file + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open) + * @param buf pointer to a memory block which content will be written + * @param btw the number Bytes To Write + * @param bw The real number of written bytes (Byte Written) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_write (void * file_p, const void * buf, uint32_t btw, uint32_t * bw); + +/** + * Set the read write pointer. Also expand the file size if necessary. + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos the new position of read write pointer + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_seek (void * file_p, uint32_t pos); + +/** + * Give the position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param pos_p pointer to to store the result + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_tell (void * file_p, uint32_t * pos_p); + +/** + * Truncate the file size to the current position of the read write pointer + * @param file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_trunc (void * file_p); + +/** + * Give the size of the file in bytes + * @param file_p file_p pointer to an 'ufs_file_t' variable. (opened with lv_ufs_open ) + * @param size_p pointer to store the size + * @return LV_FS_RES_OK: no error, the file is read + * any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_size (void * file_p, uint32_t * size_p); + +/** + * Initialize a lv_ufs_read_dir_t variable to directory reading + * @param rddir_p pointer to a 'ufs_read_dir_t' variable + * @param path uFS doesn't support folders so it has to be "" + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_open(void * rddir_p, const char * path); + +/** + * Read the next file name + * @param dir_p pointer to an initialized 'ufs_read_dir_t' variable + * @param fn pointer to buffer to sore the file name + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_read(void * dir_p, char * fn); + +/** + * Close the directory reading + * @param rddir_p pointer to an initialized 'ufs_read_dir_t' variable + * @return LV_FS_RES_OK or any error from lv_fs_res_t enum + */ +lv_fs_res_t lv_ufs_dir_close(void * rddir_p); + +/** + * Give the size of a drive + * @param total_p pointer to store the total size [kB] + * @param free_p pointer to store the free site [kB] + * @return LV_FS_RES_OK or any error from 'fs_res_t' + */ +lv_fs_res_t lv_ufs_free (uint32_t * total_p, uint32_t * free_p); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_FILESYSTEM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/include/display/lv_objx/lv_arc.h b/include/display/lv_objx/lv_arc.h new file mode 100644 index 0000000..4f82e0d --- /dev/null +++ b/include/display/lv_objx/lv_arc.h @@ -0,0 +1,127 @@ +/** + * @file lv_arc.h + * + */ + + +#ifndef LV_ARC_H +#define LV_ARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ARC != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of arc*/ +typedef struct { + /*New data for this type */ + lv_coord_t angle_start; + lv_coord_t angle_end; +} lv_arc_ext_t; + + +/*Styles*/ +enum { + LV_ARC_STYLE_MAIN, +}; +typedef uint8_t lv_arc_style_t; + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a arc objects + * @param par pointer to an object, it will be the parent of the new arc + * @param copy pointer to a arc object, if not NULL then the new object will be copied from it + * @return pointer to the created arc + */ +lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the start and end angles of an arc. 0 deg: bottom, 90 deg: right etc. + * @param arc pointer to an arc object + * @param start the start angle [0..360] + * @param end the end angle [0..360] + */ +void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end); + +/** + * Set a style of a arc. + * @param arc pointer to arc object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_arc_set_style(lv_obj_t * arc, lv_arc_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the start angle of an arc. + * @param arc pointer to an arc object + * @return the start angle [0..360] + */ +uint16_t lv_arc_get_angle_start(lv_obj_t * arc); + +/** + * Get the end angle of an arc. + * @param arc pointer to an arc object + * @return the end angle [0..360] + */ +uint16_t lv_arc_get_angle_end(lv_obj_t * arc); + +/** + * Get style of a arc. + * @param arc pointer to arc object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_arc_get_style(const lv_obj_t * arc, lv_arc_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ARC*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ARC_H*/ diff --git a/include/display/lv_objx/lv_bar.h b/include/display/lv_objx/lv_bar.h new file mode 100644 index 0000000..3938aa2 --- /dev/null +++ b/include/display/lv_objx/lv_bar.h @@ -0,0 +1,160 @@ +/** + * @file lv_bar.h + * + */ + +#ifndef LV_BAR_H +#define LV_BAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BAR != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of bar*/ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + int16_t cur_value; /*Current value of the bar*/ + int16_t min_value; /*Minimum value of the bar*/ + int16_t max_value; /*Maximum value of the bar*/ + uint8_t sym :1; /*Symmetric: means the center is around zero value*/ + lv_style_t *style_indic; /*Style of the indicator*/ +} lv_bar_ext_t; + +enum { + LV_BAR_STYLE_BG, + LV_BAR_STYLE_INDIC, +}; +typedef uint8_t lv_bar_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a bar objects + * @param par pointer to an object, it will be the parent of the new bar + * @param copy pointer to a bar object, if not NULL then the new object will be copied from it + * @return pointer to the created bar + */ +lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the bar + * @param bar pointer to a bar object + * @param value new value + */ +void lv_bar_set_value(lv_obj_t * bar, int16_t value); + +/** + * Set a new value with animation on the bar + * @param bar pointer to a bar object + * @param value new value + * @param anim_time animation time in milliseconds + */ +void lv_bar_set_value_anim(lv_obj_t * bar, int16_t value, uint16_t anim_time); + + +/** + * Set minimum and the maximum values of a bar + * @param bar pointer to the bar object + * @param min minimum value + * @param max maximum value + */ +void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max); + +/** + * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum position. + * @param bar pointer to a bar object + * @param en true: enable disable symmetric behavior; false: disable + */ +void lv_bar_set_sym(lv_obj_t * bar, bool en); + +/** + * Set a style of a bar + * @param bar pointer to a bar object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_bar_set_style(lv_obj_t *bar, lv_bar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a bar + * @param bar pointer to a bar object + * @return the value of the bar + */ +int16_t lv_bar_get_value(const lv_obj_t * bar); + +/** + * Get the minimum value of a bar + * @param bar pointer to a bar object + * @return the minimum value of the bar + */ +int16_t lv_bar_get_min_value(const lv_obj_t * bar); + +/** + * Get the maximum value of a bar + * @param bar pointer to a bar object + * @return the maximum value of the bar + */ +int16_t lv_bar_get_max_value(const lv_obj_t * bar); + +/** + * Get whether the bar is symmetric or not. + * @param bar pointer to a bar object + * @return true: symmetric is enabled; false: disable + */ +bool lv_bar_get_sym(lv_obj_t * bar); + +/** + * Get a style of a bar + * @param bar pointer to a bar object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_bar_get_style(const lv_obj_t *bar, lv_bar_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BAR_H*/ diff --git a/include/display/lv_objx/lv_btn.h b/include/display/lv_objx/lv_btn.h new file mode 100644 index 0000000..805b5d7 --- /dev/null +++ b/include/display/lv_objx/lv_btn.h @@ -0,0 +1,279 @@ +/** + * @file lv_btn.h + * + */ + +#ifndef LV_BTN_H +#define LV_BTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_btn: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* Button states + * It can be used not only by buttons but other button-like objects too*/ +enum +{ + LV_BTN_STATE_REL, + LV_BTN_STATE_PR, + LV_BTN_STATE_TGL_REL, + LV_BTN_STATE_TGL_PR, + LV_BTN_STATE_INA, + LV_BTN_STATE_NUM, +}; +typedef uint8_t lv_btn_state_t; + +enum +{ + LV_BTN_ACTION_CLICK, + LV_BTN_ACTION_PR, + LV_BTN_ACTION_LONG_PR, + LV_BTN_ACTION_LONG_PR_REPEAT, + LV_BTN_ACTION_NUM, +}; +typedef uint8_t lv_btn_action_t; + + +/*Data of button*/ +typedef struct +{ + lv_cont_ext_t cont; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t actions[LV_BTN_ACTION_NUM]; + lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/ + lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/ +#if LV_BTN_INK_EFFECT + uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/ + uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */ + uint16_t ink_out_time; /*[ms] Time of ink disappearing*/ +#endif + uint8_t toggle :1; /*1: Toggle enabled*/ + uint8_t long_pr_action_executed :1; /*1: Long press action executed (Handled by the library)*/ +} lv_btn_ext_t; + +/*Styles*/ +enum { + LV_BTN_STYLE_REL, + LV_BTN_STYLE_PR, + LV_BTN_STYLE_TGL_REL, + LV_BTN_STYLE_TGL_PR, + LV_BTN_STYLE_INA, +}; +typedef uint8_t lv_btn_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_btn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param btn pointer to a button object + * @param tgl true: enable toggled states, false: disable + */ +void lv_btn_set_toggle(lv_obj_t * btn, bool tgl); + +/** + * Set the state of the button + * @param btn pointer to a button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +void lv_btn_set_state(lv_obj_t * btn, lv_btn_state_t state); + +/** + * Toggle the state of the button (ON->OFF, OFF->ON) + * @param btn pointer to a button object + */ +void lv_btn_toggle(lv_obj_t * btn); + +/** + * Set a function to call when a button event happens + * @param btn pointer to a button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_btn_set_action(lv_obj_t * btn, lv_btn_action_t type, lv_action_t action); + +/** + * Set the layout on a button + * @param btn pointer to a button object + * @param layout a layout from 'lv_cont_layout_t' + */ +static inline void lv_btn_set_layout(lv_obj_t * btn, lv_layout_t layout) +{ + lv_cont_set_layout(btn, layout); +} + +/** + * Enable the horizontal or vertical fit. + * The button size will be set to involve the children horizontally or vertically. + * @param btn pointer to a button object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +static inline void lv_btn_set_fit(lv_obj_t * btn, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(btn, hor_en, ver_en); +} + +/** + * Set time of the ink effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_in_time(lv_obj_t * btn, uint16_t time); + +/** + * Set the wait time before the ink disappears + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_wait_time(lv_obj_t * btn, uint16_t time); + +/** + * Set time of the ink out effect (animate to the released state) + * @param btn pointer to a button object + * @param time the time of the ink animation + */ +void lv_btn_set_ink_out_time(lv_obj_t * btn, uint16_t time); + +/** + * Set a style of a button. + * @param btn pointer to button object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_btn_set_style(lv_obj_t * btn, lv_btn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current state of the button + * @param btn pointer to a button object + * @return the state of the button (from lv_btn_state_t enum) + */ +lv_btn_state_t lv_btn_get_state(const lv_obj_t * btn); + +/** + * Get the toggle enable attribute of the button + * @param btn pointer to a button object + * @return ture: toggle enabled, false: disabled + */ +bool lv_btn_get_toggle(const lv_obj_t * btn); + +/** + * Get the release action of a button + * @param btn pointer to a button object + * @return pointer to the release action function + */ +lv_action_t lv_btn_get_action(const lv_obj_t * btn, lv_btn_action_t type); + +/** + * Get the layout of a button + * @param btn pointer to button object + * @return the layout from 'lv_cont_layout_t' + */ +static inline lv_layout_t lv_btn_get_layout(const lv_obj_t * btn) +{ + return lv_cont_get_layout(btn); +} + +/** + * Get horizontal fit enable attribute of a button + * @param btn pointer to a button object + * @return true: horizontal fit is enabled; false: disabled + */ +static inline bool lv_btn_get_hor_fit(const lv_obj_t * btn) +{ + return lv_cont_get_hor_fit(btn); +} + +/** + * Get vertical fit enable attribute of a container + * @param btn pointer to a button object + * @return true: vertical fit is enabled; false: disabled + */ +static inline bool lv_btn_get_ver_fit(const lv_obj_t * btn) +{ + return lv_cont_get_ver_fit(btn); +} + +/** + * Get time of the ink in effect (draw a circle on click to animate in the new state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_in_time(const lv_obj_t * btn); + +/** + * Get the wait time before the ink disappears + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_wait_time(const lv_obj_t * btn); + +/** + * Get time of the ink out effect (animate to the releases state) + * @param btn pointer to a button object + * @return the time of the ink animation + */ +uint16_t lv_btn_get_ink_out_time(const lv_obj_t * btn); + +/** + * Get style of a button. + * @param btn pointer to button object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_btn_get_style(const lv_obj_t * btn, lv_btn_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BUTTON*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTN_H*/ diff --git a/include/display/lv_objx/lv_btnm.h b/include/display/lv_objx/lv_btnm.h new file mode 100644 index 0000000..89c066a --- /dev/null +++ b/include/display/lv_objx/lv_btnm.h @@ -0,0 +1,197 @@ +/** + * @file lv_btnm.h + * + */ + + +#ifndef LV_BTNM_H +#define LV_BTNM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_BTNM != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" +#include "lv_btn.h" + +/********************* + * DEFINES + *********************/ + +/*Control byte*/ +#define LV_BTNM_CTRL_CODE 0x80 /*The control byte has to begin (if present) with 0b10xxxxxx*/ +#define LV_BTNM_CTRL_MASK 0xC0 +#define LV_BTNM_WIDTH_MASK 0x07 +#define LV_BTNM_HIDE_MASK 0x08 +#define LV_BTNM_REPEAT_DISABLE_MASK 0x10 +#define LV_BTNM_INACTIVE_MASK 0x20 + + +#define LV_BTNM_PR_NONE 0xFFFF +/********************** + * TYPEDEFS + **********************/ + +/* Type of callback function which is called when a button is released or long pressed on the button matrix + * Parameters: button matrix, text of the released button + * return LV_ACTION_RES_INV if the button matrix is deleted else LV_ACTION_RES_OK*/ +typedef lv_res_t (*lv_btnm_action_t) (lv_obj_t *, const char *txt); + +/*Data of button matrix*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + const char ** map_p; /*Pointer to the current map*/ + lv_area_t *button_areas; /*Array of areas of buttons*/ + lv_btnm_action_t action; /*A function to call when a button is releases*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of buttons in each state*/ + uint16_t btn_cnt; /*Number of button in 'map_p'(Handled by the library)*/ + uint16_t btn_id_pr; /*Index of the currently pressed button (in `button_areas`) or LV_BTNM_PR_NONE*/ + uint16_t btn_id_tgl; /*Index of the currently toggled button (in `button_areas`) or LV_BTNM_PR_NONE */ + uint8_t toggle :1; /*Enable toggling*/ + uint8_t recolor :1; /*Enable button recoloring*/ +} lv_btnm_ext_t; + +enum { + LV_BTNM_STYLE_BG, + LV_BTNM_STYLE_BTN_REL, + LV_BTNM_STYLE_BTN_PR, + LV_BTNM_STYLE_BTN_TGL_REL, + LV_BTNM_STYLE_BTN_TGL_PR, + LV_BTNM_STYLE_BTN_INA, +}; +typedef uint8_t lv_btnm_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a button matrix objects + * @param par pointer to an object, it will be the parent of the new button matrix + * @param copy pointer to a button matrix object, if not NULL then the new object will be copied from it + * @return pointer to the created button matrix + */ +lv_obj_t * lv_btnm_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new map. Buttons will be created/deleted according to the map. + * @param btnm pointer to a button matrix object + * @param map pointer a string array. The last string has to be: "". + * Use "\n" to begin a new line. + * The first byte can be a control data: + * - bit 7: always 1 + * - bit 6: always 0 + * - bit 5: inactive (disabled) + * - bit 4: no repeat (on long press) + * - bit 3: hidden + * - bit 2..0: button relative width + * Example (practically use octal numbers): "\224abc": "abc" text with 4 width and no long press + */ +void lv_btnm_set_map(lv_obj_t * btnm, const char ** map); + +/** + * Set a new callback function for the buttons (It will be called when a button is released) + * @param btnm: pointer to button matrix object + * @param action pointer to a callback function + */ +void lv_btnm_set_action(lv_obj_t * btnm, lv_btnm_action_t action); + +/** + * Enable or disable button toggling + * @param btnm pointer to button matrix object + * @param en true: enable toggling; false: disable toggling + * @param id index of the currently toggled button (ignored if 'en' == false) + */ +void lv_btnm_set_toggle(lv_obj_t * btnm, bool en, uint16_t id); + +/** + * Set a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_btnm_set_style(lv_obj_t *btnm, lv_btnm_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_btnm_set_recolor(const lv_obj_t * btnm, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the current map of a button matrix + * @param btnm pointer to a button matrix object + * @return the current map + */ +const char ** lv_btnm_get_map(const lv_obj_t * btnm); + +/** + * Get a the callback function of the buttons on a button matrix + * @param btnm: pointer to button matrix object + * @return pointer to the callback function + */ +lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); + +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); + +/** + * Get the toggled button + * @param btnm pointer to button matrix object + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); + +/** + * Get a style of a button matrix + * @param btnm pointer to a button matrix object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_btnm_get_style(const lv_obj_t *btnm, lv_btnm_style_t type); + +/** + * Find whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_btnm_get_recolor(const lv_obj_t * btnm); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_BTNM*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_BTNM_H*/ diff --git a/include/display/lv_objx/lv_calendar.h b/include/display/lv_objx/lv_calendar.h new file mode 100644 index 0000000..3ef4b02 --- /dev/null +++ b/include/display/lv_objx/lv_calendar.h @@ -0,0 +1,246 @@ +/** + * @file lv_calendar.h + * + */ + +#ifndef LV_CALENDAR_H +#define LV_CALENDAR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CALENDAR != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + uint16_t year; + int8_t month; + int8_t day; +} lv_calendar_date_t; + +enum +{ + LV_CALENDAR_ACTION_CLICK, + LV_CALENDAR_ACTION_PR, + LV_CALENDAR_ACTION_LONG_PR, + LV_CALENDAR_ACTION_LONG_PR_REPEAT, + LV_CALENDAR_ACTION_NUM, +}; +typedef uint8_t lv_calendar_action_t; + +/*Data of calendar*/ +typedef struct { + /*None*/ /*Ext. of ancestor*/ + /*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)*/ + uint8_t highlighted_dates_num; /*Number of elements in `highlighted_days`*/ + int8_t btn_pressing; /*-1: prev month pressing, +1 next month pressing on the header*/ + lv_calendar_date_t pressed_date; + const char ** day_names; /*Pointer to an array with the name of the days (NULL: use default names)*/ + const char ** month_names; /*Pointer to an array with the name of the month (NULL. use default names)*/ + lv_action_t actions[LV_CALENDAR_ACTION_NUM]; + + /*Styles*/ + lv_style_t * style_header; + lv_style_t * style_header_pr; + lv_style_t * style_day_names; + lv_style_t * style_highlighted_days; + lv_style_t * style_inactive_days; + lv_style_t * style_week_box; + lv_style_t * style_today_box; +} lv_calendar_ext_t; + +/*Styles*/ +enum { + LV_CALENDAR_STYLE_BG, /*Also the style of the "normal" date numbers*/ + LV_CALENDAR_STYLE_HEADER, + LV_CALENDAR_STYLE_HEADER_PR, + LV_CALENDAR_STYLE_DAY_NAMES, + LV_CALENDAR_STYLE_HIGHLIGHTED_DAYS, + LV_CALENDAR_STYLE_INACTIVE_DAYS, + LV_CALENDAR_STYLE_WEEK_BOX, + LV_CALENDAR_STYLE_TODAY_BOX, +}; +typedef uint8_t lv_calendar_style_t; + + + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a calendar objects + * @param par pointer to an object, it will be the parent of the new calendar + * @param copy pointer to a calendar object, if not NULL then the new object will be copied from it + * @return pointer to the created calendar + */ +lv_obj_t * lv_calendar_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ +/** + * Set a function to call when a calendar event happens + * @param calendar pointer to a calendar object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +void lv_calendar_set_action(lv_obj_t * calendar, lv_calendar_action_t type, lv_action_t action); + +/** + * Set the today's date + * @param calendar pointer to a calendar object + * @param today pointer to an `lv_calendar_date_t` variable containing the date of today. The value will be saved it can be local variable too. + */ +void lv_calendar_set_today_date(lv_obj_t * calendar, lv_calendar_date_t * today); + +/** + * Set the currently showed + * @param calendar pointer to a calendar object + * @param showed pointer to an `lv_calendar_date_t` variable containing the date to show. The value will be saved it can be local variable too. + */ +void lv_calendar_set_showed_date(lv_obj_t * calendar, lv_calendar_date_t * showed); + +/** + * Set the the highlighted dates + * @param calendar pointer to a calendar object + * @param highlighted pointer to an `lv_calendar_date_t` array containing the dates. ONLY A POINTER WILL BE SAVED! CAN'T BE LOCAL ARRAY. + * @param date_num number of dates in the array + */ +void lv_calendar_set_highlighted_dates(lv_obj_t * calendar, lv_calendar_date_t * highlighted, uint16_t date_num); + + +/** + * Set the name of the days + * @param calendar 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 * calendar, const char ** day_names); + +/** + * Set the name of the month + * @param calendar pointer to a calendar object + * @param day_names pointer to an array with the names. E.g. `const char * days[12] = {"Jan", "Feb", ...}` + * Only the pointer will be saved so this variable can't be local which will be destroyed later. + */ +void lv_calendar_set_month_names(lv_obj_t * calendar, const char ** day_names); + +/** + * Set a style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_calendar_set_style(lv_obj_t * calendar, lv_calendar_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ +/** + * Get the action of a calendar + * @param calendar pointer to a calendar object + * @return pointer to the action function + */ +lv_action_t lv_calendar_get_action(const lv_obj_t * calendar, lv_calendar_action_t type); + +/** + * 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. + */ +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. + */ +lv_calendar_date_t * lv_calendar_get_showed_date(const lv_obj_t * calendar); + +/** + * Get the the pressed date. + * @param calendar pointer to a calendar object + * @return pointer to an `lv_calendar_date_t` variable containing the pressed date. + */ +lv_calendar_date_t * lv_calendar_get_pressed_date(const lv_obj_t * calendar); + +/** + * Get the 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 name of the days + * @param calendar pointer to a calendar object + * @return pointer to the array of day names + */ +const char ** lv_calendar_get_day_names(const lv_obj_t * calendar); + +/** + * Get the name of the month + * @param calendar pointer to a calendar object + * @return pointer to the array of month names + */ +const char ** lv_calendar_get_month_names(const lv_obj_t * calendar); + +/** + * Get style of a calendar. + * @param calendar pointer to calendar object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_calendar_get_style(const lv_obj_t * calendar, lv_calendar_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CALENDAR*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CALENDAR_H*/ diff --git a/include/display/lv_objx/lv_canvas.h b/include/display/lv_objx/lv_canvas.h new file mode 100644 index 0000000..14d6e87 --- /dev/null +++ b/include/display/lv_objx/lv_canvas.h @@ -0,0 +1,229 @@ +/** + * @file lv_canvas.h + * + */ + +#ifndef LV_CANVAS_H +#define LV_CANVAS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CANVAS != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of canvas*/ +typedef struct { + lv_img_ext_t img; /*Ext. of ancestor*/ + /*New data for this type */ + lv_img_dsc_t dsc; +} lv_canvas_ext_t; + + +/*Styles*/ +enum { + LV_CANVAS_STYLE_MAIN, +}; +typedef uint8_t lv_canvas_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a canvas object + * @param par pointer to an object, it will be the parent of the new canvas + * @param copy pointer to a canvas object, if not NULL then the new object will be copied from it + * @return pointer to the created canvas + */ +lv_obj_t * lv_canvas_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * 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 * h) / 8) + * 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. The following formats are supported: + * LV_IMG_CF_TRUE_COLOR, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, LV_IMG_CF_INDEXES_1/2/4/8BIT + */ +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 point + */ +void lv_canvas_set_px(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t c); + +/** + * Set a style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_canvas_set_style(lv_obj_t * canvas, lv_canvas_style_t type, lv_style_t * style); + +/*===================== + * 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 style of a canvas. + * @param canvas pointer to canvas object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_canvas_get_style(const lv_obj_t * canvas, lv_canvas_style_t type); + +/*===================== + * 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 w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_copy_buf(lv_obj_t * canvas, const void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Multiply a buffer with the canvas + * @param canvas pointer to a canvas object + * @param to_copy buffer to copy (multiply). LV_IMG_CF_TRUE_COLOR_ALPHA is not supported + * @param w width of the buffer to copy + * @param h height of the buffer to copy + * @param x left side of the destination position + * @param y top side of the destination position + */ +void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coord_t h, lv_coord_t x, lv_coord_t y); + +/** + * Draw circle function of the canvas + * @param canvas pointer to a canvas object + * @param x0 x coordinate of the circle + * @param y0 y coordinate of the circle + * @param radius radius of the circle + * @param color border color of the circle + */ +void lv_canvas_draw_circle(lv_obj_t * canvas, lv_coord_t x0, lv_coord_t y0, lv_coord_t radius, lv_color_t color); + +/** + * Draw line function of the canvas + * @param canvas pointer to a canvas object + * @param point1 start point of the line + * @param point2 end point of the line + * @param color color of the line + * + * NOTE: The lv_canvas_draw_line function originates from https://github.com/jb55/bresenham-line.c. + */ +void lv_canvas_draw_line(lv_obj_t * canvas, lv_point_t point1, lv_point_t point2, lv_color_t color); + +/** + * Draw triangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the triangle + * @param color line color of the triangle + */ +void lv_canvas_draw_triangle(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw rectangle function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the rectangle + * @param color line color of the rectangle + */ +void lv_canvas_draw_rect(lv_obj_t * canvas, lv_point_t * points, lv_color_t color); + +/** + * Draw polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param color line color of the polygon + */ +void lv_canvas_draw_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t color); + +/** + * Fill polygon function of the canvas + * @param canvas pointer to a canvas object + * @param points edge points of the polygon + * @param size edge count of the polygon + * @param boundary_color line color of the polygon + * @param fill_color fill color of the polygon + */ +void lv_canvas_fill_polygon(lv_obj_t * canvas, lv_point_t * points, size_t size, lv_color_t boundary_color, lv_color_t fill_color); +/** + * Boundary fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param boundary_color edge/boundary color of the area + * @param fill_color fill color of the area + */ +void lv_canvas_boundary_fill4(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t boundary_color, lv_color_t fill_color); + +/** + * Flood fill function of the canvas + * @param canvas pointer to a canvas object + * @param x x coordinate of the start position (seed) + * @param y y coordinate of the start position (seed) + * @param fill_color fill color of the area + * @param bg_color background color of the area + */ +void lv_canvas_flood_fill(lv_obj_t * canvas, lv_coord_t x, lv_coord_t y, lv_color_t fill_color, lv_color_t bg_color); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CANVAS*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CANVAS_H*/ diff --git a/include/display/lv_objx/lv_cb.h b/include/display/lv_objx/lv_cb.h new file mode 100644 index 0000000..5c550b6 --- /dev/null +++ b/include/display/lv_objx/lv_cb.h @@ -0,0 +1,174 @@ +/** + * @file lv_cb.h + * + */ + +#ifndef LV_CB_H +#define LV_CB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_cb: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_cb: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of check box*/ +typedef struct +{ + lv_btn_ext_t bg_btn; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * bullet; /*Pointer to button*/ + lv_obj_t * label; /*Pointer to label*/ +} lv_cb_ext_t; + +enum { + LV_CB_STYLE_BG, + LV_CB_STYLE_BOX_REL, + LV_CB_STYLE_BOX_PR, + LV_CB_STYLE_BOX_TGL_REL, + LV_CB_STYLE_BOX_TGL_PR, + LV_CB_STYLE_BOX_INA, +}; +typedef uint8_t lv_cb_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a check box objects + * @param par pointer to an object, it will be the parent of the new check box + * @param copy pointer to a check box object, if not NULL then the new object will be copied from it + * @return pointer to the created check box + */ +lv_obj_t * lv_cb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a check box + * @param cb pointer to a check box + * @param txt the text of the check box + */ +void lv_cb_set_text(lv_obj_t * cb, const char * txt); + +/** + * Set the state of the check box + * @param cb pointer to a check box object + * @param checked true: make the check box checked; false: make it unchecked + */ +static inline void lv_cb_set_checked(lv_obj_t * cb, bool checked) +{ + lv_btn_set_state(cb, checked ? LV_BTN_STATE_TGL_REL : LV_BTN_STATE_REL); +} + +/** + * Make the check box inactive (disabled) + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_inactive(lv_obj_t * cb) +{ + lv_btn_set_state(cb, LV_BTN_STATE_INA); +} + +/** + * Set a function to call when the check box is clicked + * @param cb pointer to a check box object + */ +static inline void lv_cb_set_action(lv_obj_t * cb, lv_action_t action) +{ + lv_btn_set_action(cb, LV_BTN_ACTION_CLICK, action); +} + + +/** + * Set a style of a check box + * @param cb pointer to check box object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_cb_set_style(lv_obj_t * cb, lv_cb_style_t type, lv_style_t *style); + +/*===================== + * 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_cb_get_text(const lv_obj_t * cb); + +/** + * Get the current state of the check box + * @param cb pointer to a check box object + * @return true: checked; false: not checked + */ +static inline bool lv_cb_is_checked(const lv_obj_t * cb) +{ + return lv_btn_get_state(cb) == LV_BTN_STATE_REL ? false : true; +} + +/** + * Get the action of a check box + * @param cb pointer to a button object + * @return pointer to the action function + */ +static inline lv_action_t lv_cb_get_action(const lv_obj_t * cb) +{ + return lv_btn_get_action(cb, LV_BTN_ACTION_CLICK); +} + + +/** + * Get a style of a button + * @param cb pointer to check box object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_cb_get_style(const lv_obj_t * cb, lv_cb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CB_H*/ diff --git a/include/display/lv_objx/lv_chart.h b/include/display/lv_objx/lv_chart.h new file mode 100644 index 0000000..92637e8 --- /dev/null +++ b/include/display/lv_objx/lv_chart.h @@ -0,0 +1,262 @@ +/** + * @file lv_chart.h + * + */ + +#ifndef LV_CHART_H +#define LV_CHART_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CHART != 0 + +#include "display/lv_core/lv_obj.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ +#define LV_CHART_POINT_DEF (LV_COORD_MIN) + +/********************** + * TYPEDEFS + **********************/ +typedef struct +{ + lv_coord_t * points; + lv_color_t color; + uint16_t start_point; +} lv_chart_series_t; + +/*Data of chart */ +typedef struct +{ + /*No inherited ext*/ /*Ext. of ancestor*/ + /*New data for this type */ + lv_ll_t series_ll; /*Linked list for the data line pointers (stores lv_chart_dl_t)*/ + lv_coord_t ymin; /*y min value (used to scale the data)*/ + lv_coord_t ymax; /*y max value (used to scale the data)*/ + uint8_t hdiv_cnt; /*Number of horizontal division lines*/ + uint8_t vdiv_cnt; /*Number of vertical division lines*/ + uint16_t point_cnt; /*Point number in a data line*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ + struct { + lv_coord_t width; /*Line width or point radius*/ + uint8_t num; /*Number of data lines in dl_ll*/ + lv_opa_t opa; /*Opacity of data lines*/ + lv_opa_t dark; /*Dark level of the point/column bottoms*/ + } series; +} lv_chart_ext_t; + +/*Chart types*/ +enum +{ + LV_CHART_TYPE_LINE = 0x01, /*Connect the points with lines*/ + LV_CHART_TYPE_COLUMN = 0x02, /*Draw columns*/ + LV_CHART_TYPE_POINT = 0x04, /*Draw circles on the points*/ + LV_CHART_TYPE_VERTICAL_LINE = 0x08, /*Draw vertical lines on points (useful when chart width == point count)*/ +}; +typedef uint8_t lv_chart_type_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a chart background objects + * @param par pointer to an object, it will be the parent of the new chart background + * @param copy pointer to a chart background object, if not NULL then the new object will be copied from it + * @return pointer to the created chart background + */ +lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Allocate and add a data series to the chart + * @param chart pointer to a chart object + * @param color color of the data series + * @return pointer to the allocated data series + */ +lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color); + +/** + * Clear the point of a serie + * @param chart pointer to a chart object + * @param serie pointer to the chart's serie to clear + */ +void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * serie); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of horizontal and vertical division lines + * @param chart pointer to a graph background 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 * chart, uint8_t hdiv, uint8_t vdiv); + +/** + * Set the minimal and maximal y values + * @param chart pointer to a graph background object + * @param ymin y minimum value + * @param ymax y maximum value + */ +void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax); + +/** + * Set a new type for a chart + * @param chart 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 * chart, lv_chart_type_t type); + +/** + * Set the number of points on a data line on a chart + * @param chart pointer r to chart object + * @param point_cnt new number of points on the data lines + */ +void lv_chart_set_point_count(lv_obj_t * chart, uint16_t point_cnt); + +/** + * Set the opacity of the data series + * @param chart pointer to a chart object + * @param opa opacity of the data series + */ +void lv_chart_set_series_opa(lv_obj_t * chart, lv_opa_t opa); + +/** + * Set the line width or point radius of the data series + * @param chart pointer to a chart object + * @param width the new width + */ +void lv_chart_set_series_width(lv_obj_t * chart, lv_coord_t width); + +/** + * Set the dark effect on the bottom of the points or columns + * @param chart pointer to a chart object + * @param dark_eff dark effect level (LV_OPA_TRANSP to turn off) + */ +void lv_chart_set_series_darking(lv_obj_t * chart, lv_opa_t dark_eff); + +/** + * Initialize all data points with a value + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value for all points + */ +void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the value s of points from an array + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y_array array of 'lv_coord_t' points (with 'points count' elements ) + */ +void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array); + +/** + * Shift all data right and set the most right data on a data line + * @param chart pointer to chart object + * @param ser pointer to a data series on 'chart' + * @param y the new value of the most right data + */ +void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y); + +/** + * Set the style of a chart + * @param chart pointer to a chart object + * @param style pointer to a style + */ +static inline void lv_chart_set_style(lv_obj_t *chart, lv_style_t *style) +{ + lv_obj_set_style(chart, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the type of a chart + * @param chart 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 * chart); + +/** + * 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_cnt(const lv_obj_t * chart); + +/** + * Get the opacity of the data series + * @param chart pointer to chart object + * @return the opacity of the data series + */ +lv_opa_t lv_chart_get_series_opa(const lv_obj_t * chart); + +/** + * Get the data series width + * @param chart pointer to chart object + * @return the width the data series (lines or points) + */ +lv_coord_t lv_chart_get_series_width(const lv_obj_t * chart); + +/** + * Get the dark effect level on the bottom of the points or columns + * @param chart pointer to chart object + * @return dark effect level (LV_OPA_TRANSP to turn off) + */ +lv_opa_t lv_chart_get_series_darking(const lv_obj_t * chart); + +/** + * Get the style of an chart object + * @param chart pointer to an chart object + * @return pointer to the chart's style + */ +static inline lv_style_t* lv_chart_get_style(const lv_obj_t *chart) +{ + return lv_obj_get_style(chart); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Refresh a chart if its data line has changed + * @param chart pointer to chart object + */ +void lv_chart_refresh(lv_obj_t * chart); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CHART*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CHART_H*/ diff --git a/include/display/lv_objx/lv_cont.h b/include/display/lv_objx/lv_cont.h new file mode 100644 index 0000000..3f4923d --- /dev/null +++ b/include/display/lv_objx/lv_cont.h @@ -0,0 +1,163 @@ +/** + * @file lv_cont.h + * + */ + +#ifndef LV_CONT_H +#define LV_CONT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_CONT != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Layout options*/ +enum +{ + LV_LAYOUT_OFF = 0, + LV_LAYOUT_CENTER, + LV_LAYOUT_COL_L, /*Column left align*/ + LV_LAYOUT_COL_M, /*Column middle align*/ + LV_LAYOUT_COL_R, /*Column right align*/ + LV_LAYOUT_ROW_T, /*Row top align*/ + LV_LAYOUT_ROW_M, /*Row middle align*/ + LV_LAYOUT_ROW_B, /*Row bottom align*/ + LV_LAYOUT_PRETTY, /*Put as many object as possible in row and begin a new row*/ + LV_LAYOUT_GRID, /*Align same-sized object into a grid*/ +}; +typedef uint8_t lv_layout_t; + +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext. */ /*Ext. of ancestor*/ + /*New data for this type */ + uint8_t layout :4; /*A layout from 'lv_cont_layout_t' enum*/ + uint8_t hor_fit :1; /*1: Enable horizontal fit to involve all children*/ + uint8_t ver_fit :1; /*1: Enable horizontal fit to involve all children*/ +} lv_cont_ext_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a container objects + * @param par pointer to an object, it will be the parent of the new container + * @param copy pointer to a container object, if not NULL then the new object will be copied from it + * @return pointer to the created container + */ +lv_obj_t * lv_cont_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a layout on a container + * @param cont pointer to a container object + * @param layout a layout from 'lv_cont_layout_t' + */ +void lv_cont_set_layout(lv_obj_t * cont, lv_layout_t layout); + + +/** + * Enable the horizontal or vertical fit. + * The container size will be set to involve the children horizontally or vertically. + * @param cont pointer to a container object + * @param hor_en true: enable the horizontal fit + * @param ver_en true: enable the vertical fit + */ +void lv_cont_set_fit(lv_obj_t * cont, bool hor_en, bool ver_en); + +/** + * Set the style of a container + * @param cont pointer to a container object + * @param style pointer to the new style + */ +static inline void lv_cont_set_style(lv_obj_t *cont, lv_style_t * style) +{ + lv_obj_set_style(cont, style); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the layout of a container + * @param cont pointer to container object + * @return the layout from 'lv_cont_layout_t' + */ +lv_layout_t lv_cont_get_layout(const lv_obj_t * cont); + +/** + * Get horizontal fit enable attribute of a container + * @param cont pointer to a container object + * @return true: horizontal fit is enabled; false: disabled + */ +bool lv_cont_get_hor_fit(const lv_obj_t * cont); + +/** + * Get vertical fit enable attribute of a container + * @param cont pointer to a container object + * @return true: vertical fit is enabled; false: disabled + */ +bool lv_cont_get_ver_fit(const lv_obj_t * cont); + + +/** + * Get that width reduced by the horizontal padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the width which still fits into the container + */ +lv_coord_t lv_cont_get_fit_width(lv_obj_t * cont); + +/** + * Get that height reduced by the vertical padding. Useful if a layout is used. + * @param cont pointer to a container object + * @return the height which still fits into the container + */ +lv_coord_t lv_cont_get_fit_height(lv_obj_t * cont); + +/** + * Get the style of a container + * @param cont pointer to a container object + * @return pointer to the container's style + */ +static inline lv_style_t * lv_cont_get_style(const lv_obj_t *cont) +{ + return lv_obj_get_style(cont); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_CONT*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_CONT_H*/ diff --git a/include/display/lv_objx/lv_ddlist.h b/include/display/lv_objx/lv_ddlist.h new file mode 100644 index 0000000..cd9de97 --- /dev/null +++ b/include/display/lv_objx/lv_ddlist.h @@ -0,0 +1,265 @@ +/** + * @file lv_ddlist.h + * + */ + +#ifndef LV_DDLIST_H +#define LV_DDLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_DDLIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ddlist: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ddlist: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_page.h" +#include "display/lv_objx/lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of drop down list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *label; /*Label for the options*/ + lv_style_t * sel_style; /*Style of the selected option*/ + lv_action_t action; /*Pointer to function to call when an option is selected*/ + 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*/ + uint16_t anim_time; /*Open/Close animation time [ms]*/ + uint8_t opened :1; /*1: The list is opened (handled by the library)*/ + uint8_t draw_arrow :1; /*1: Draw arrow*/ + + lv_coord_t fix_height; /*Height of the ddlist when opened. (0: auto-size)*/ +} lv_ddlist_ext_t; + +enum { + LV_DDLIST_STYLE_BG, + LV_DDLIST_STYLE_SEL, + LV_DDLIST_STYLE_SB, +}; +typedef uint8_t lv_ddlist_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Create a drop down list objects + * @param par pointer to an object, it will be the parent of the new drop down list + * @param copy pointer to a drop down list object, if not NULL then the new object will be copied from it + * @return pointer to the created drop down list + */ +lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set arrow draw in a drop down list + * @param ddlist pointer to drop down list object + * @param en enable/disable a arrow draw. E.g. "true" for draw. + */ +void lv_ddlist_set_draw_arrow(lv_obj_t * ddlist, bool en); + +/** + * Set the options in a drop down list from a string + * @param ddlist pointer to drop down list object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options); + +/** + * Set the selected option + * @param ddlist pointer to drop down list object + * @param sel_opt id of the selected option (0 ... number of option - 1); + */ +void lv_ddlist_set_selected(lv_obj_t * ddlist, uint16_t sel_opt); + +/** + * Set a function to call when a new option is chosen + * @param ddlist pointer to a drop down list + * @param action pointer to a call back function + */ +void lv_ddlist_set_action(lv_obj_t * ddlist, lv_action_t action); + +/** + * Set the fix height for the drop down list + * If 0 then the opened ddlist will be auto. sized else the set height will be applied. + * @param ddlist pointer to a drop down list + * @param h the height when the list is opened (0: auto size) + */ +void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h); + +/** + * Enable or disable the horizontal fit to the content + * @param ddlist pointer to a drop down list + * @param en true: enable auto fit; false: disable auto fit + */ +void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, bool en); + +/** + * Set the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ddlist_set_sb_mode(lv_obj_t * ddlist, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ddlist, mode); +} + +/** + * Set the open/close animation time. + * @param ddlist pointer to a drop down list + * @param anim_time: open/close animation time [ms] + */ +void lv_ddlist_set_anim_time(lv_obj_t * ddlist, uint16_t anim_time); + + +/** + * Set a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_ddlist_set_style(lv_obj_t *ddlist, lv_ddlist_style_t type, lv_style_t *style); + +/** + * Set the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @param align alignment of labels + */ +void lv_ddlist_set_align(lv_obj_t *ddlist, lv_label_align_t align); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get arrow draw in a drop down list + * @param ddlist pointer to drop down list object + */ +bool lv_ddlist_get_draw_arrow(lv_obj_t * ddlist); + +/** + * Get the options of a drop down list + * @param ddlist pointer to drop down list object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +const char * lv_ddlist_get_options(const lv_obj_t * ddlist); + +/** + * Get the selected option + * @param ddlist pointer to drop down list object + * @return id of the selected option (0 ... number of option - 1); + */ +uint16_t lv_ddlist_get_selected(const lv_obj_t * ddlist); + +/** + * Get the current selected option as a string + * @param ddlist pointer to ddlist object + * @param buf pointer to an array to store the string + */ +void lv_ddlist_get_selected_str(const lv_obj_t * ddlist, char * buf); + +/** + * Get the "option selected" callback function + * @param ddlist pointer to a drop down list + * @return pointer to the call back function + */ +lv_action_t lv_ddlist_get_action(const lv_obj_t * ddlist); + +/** + * Get the fix height value. + * @param ddlist pointer to a drop down list object + * @return the height if the ddlist is opened (0: auto size) + */ +lv_coord_t lv_ddlist_get_fix_height(const lv_obj_t * ddlist); + +/** + * Get the scroll bar mode of a drop down list + * @param ddlist pointer to a drop down list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ddlist_get_sb_mode(const lv_obj_t * ddlist) +{ + return lv_page_get_sb_mode(ddlist); +} + +/** + * Get the open/close animation time. + * @param ddlist pointer to a drop down list + * @return open/close animation time [ms] + */ +uint16_t lv_ddlist_get_anim_time(const lv_obj_t * ddlist); + +/** + * Get a style of a drop down list + * @param ddlist pointer to a drop down list object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ddlist_get_style(const lv_obj_t *ddlist, lv_ddlist_style_t type); + +/** + * Get the alignment of the labels in a drop down list + * @param ddlist pointer to a drop down list object + * @return alignment of labels + */ +lv_label_align_t lv_ddlist_get_align(const lv_obj_t *ddlist); + +/*===================== + * Other functions + *====================*/ + +/** + * Open the drop down list with or without animation + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_open(lv_obj_t * ddlist, bool anim_en); + +/** + * Close (Collapse) the drop down list + * @param ddlist pointer to drop down list object + * @param anim_en true: use animation; false: not use animations + */ +void lv_ddlist_close(lv_obj_t * ddlist, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_DDLIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_DDLIST_H*/ diff --git a/include/display/lv_objx/lv_gauge.h b/include/display/lv_objx/lv_gauge.h new file mode 100644 index 0000000..3f269cd --- /dev/null +++ b/include/display/lv_objx/lv_gauge.h @@ -0,0 +1,222 @@ +/** + * @file lv_gauge.h + * + */ + +#ifndef LV_GAUGE_H +#define LV_GAUGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_GAUGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LMETER == 0 +#error "lv_gauge: lv_lmeter is required. Enable it in lv_conf.h (USE_LV_LMETER 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_lmeter.h" +#include "lv_label.h" +#include "lv_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of gauge*/ +typedef struct +{ + lv_lmeter_ext_t lmeter; /*Ext. of ancestor*/ + /*New data for this type */ + int16_t * values; /*Array of the set values (for needles) */ + const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ + uint8_t needle_count; /*Number of needles*/ + uint8_t label_count; /*Number of labels on the scale*/ +} lv_gauge_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a gauge objects + * @param par pointer to an object, it will be the parent of the new gauge + * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it + * @return pointer to the created gauge + */ +lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the number of needles + * @param gauge pointer to gauge object + * @param needle_cnt new count of needles + * @param colors an array of colors for needles (with 'num' elements) + */ +void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t * colors); + +/** + * Set the value of a needle + * @param gauge pointer to a gauge + * @param needle_id the id of the needle + * @param value the new value + */ +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); + +/** + * Set minimum and the maximum values of a gauge + * @param gauge pointer to he gauge object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_gauge_set_range(lv_obj_t *gauge, int16_t min, int16_t max) +{ + lv_lmeter_set_range(gauge, min, max); +} + +/** + * Set a critical value on the scale. After this value 'line.color' scale lines will be drawn + * @param gauge pointer to a gauge object + * @param value the critical value + */ +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +{ + lv_lmeter_set_value(gauge, value); +} + +/** + * Set the scale settings of a gauge + * @param gauge pointer to a gauge object + * @param angle angle of the scale (0..360) + * @param line_cnt count of scale lines. + * The get a given "subdivision" lines between label, `line_cnt` = (sub_div + 1) * (label_cnt - 1) + 1 + * @param label_cnt count of scale labels. + */ +void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt); + +/** + * Set the styles of a gauge + * @param gauge pointer to a gauge object + * @param bg set the style of the gauge + * */ +static inline void lv_gauge_set_style(lv_obj_t *gauge, lv_style_t *bg) +{ + lv_obj_set_style(gauge, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a needle + * @param gauge pointer to gauge object + * @param needle the id of the needle + * @return the value of the needle [min,max] + */ +int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); + +/** + * Get the count of needles on a gauge + * @param gauge pointer to gauge + * @return count of needles + */ +uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); + +/** + * Get the minimum value of a gauge + * @param gauge pointer to a gauge object + * @return the minimum value of the gauge + */ +static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_min_value(lmeter); +} + +/** + * Get the maximum value of a gauge + * @param gauge pointer to a gauge object + * @return the maximum value of the gauge + */ +static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +{ + return lv_lmeter_get_max_value(lmeter); +} + +/** + * Get a critical value on the scale. + * @param gauge pointer to a gauge object + * @return the critical value + */ +static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +{ + return lv_lmeter_get_value(gauge); +} + +/** + * Set the number of labels (and the thicker lines too) + * @param gauge pointer to a gauge object + * @return count of labels + */ +uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge); + +/** + * Get the scale number of a gauge + * @param gauge pointer to a gauge object + * @return number of the scale units + */ +static inline uint8_t lv_gauge_get_line_count(const lv_obj_t * gauge) +{ + return lv_lmeter_get_line_count(gauge); +} + +/** + * Get the scale angle of a gauge + * @param gauge pointer to a gauge object + * @return angle of the scale + */ +static inline uint16_t lv_gauge_get_scale_angle(const lv_obj_t * gauge) +{ + return lv_lmeter_get_scale_angle(gauge); +} + +/** + * Get the style of a gauge + * @param gauge pointer to a gauge object + * @return pointer to the gauge's style + */ +static inline lv_style_t * lv_gauge_get_style(const lv_obj_t *gauge) +{ + return lv_obj_get_style(gauge); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_GAUGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GAUGE_H*/ diff --git a/include/display/lv_objx/lv_img.h b/include/display/lv_objx/lv_img.h new file mode 100644 index 0000000..03eca24 --- /dev/null +++ b/include/display/lv_objx/lv_img.h @@ -0,0 +1,195 @@ +/** + * @file lv_img.h + * + */ + +#ifndef LV_IMG_H +#define LV_IMG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMG != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_fs.h" +#include "display/lv_misc/lv_symbol_def.h" +#include "lv_label.h" +#include "display/lv_draw/lv_draw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image*/ +typedef struct +{ + /*No inherited ext. because inherited from the base object*/ /*Ext. of ancestor*/ + /*New data for this type */ + const void * src; /*Image source: Pointer to an array or a file or a symbol*/ + + lv_coord_t w; /*Width of the image (Handled by the library)*/ + lv_coord_t h; /*Height of the image (Handled by the library)*/ +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the image to display. */ +#endif + uint8_t src_type :2; /*See: lv_img_src_t*/ + uint8_t auto_size :1; /*1: automatically set the object size to the image size*/ + uint8_t cf :5; /*Color format from `lv_img_color_format_t`*/ +} lv_img_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create an image objects + * @param par pointer to an object, it will be the parent of the new button + * @param copy pointer to a image object, if not NULL then the new object will be copied from it + * @return pointer to the created image + */ +lv_obj_t * lv_img_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the pixel map to display by the image + * @param img pointer to an image object + * @param data the image data + */ +void lv_img_set_src(lv_obj_t * img, const void * src_img); + +#if USE_LV_MULTI_LANG +/** + * Set an ID which means a the same source but on different languages + * @param img pointer to an image object + * @param src_id ID of the source + */ +void lv_img_set_src_id(lv_obj_t * img, uint32_t txt_id); +#endif + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0. + * Use 'lv_img_set_src()' instead. + * @param img - + * @param fn - + */ +static inline void lv_img_set_file(lv_obj_t * img, const char * fn) +{ + (void) img; + (void) fn; +} + +/** + * Enable the auto size feature. + * If enabled the object size will be same as the picture size. + * @param img pointer to an image + * @param en true: auto size enable, false: auto size disable + */ +void lv_img_set_auto_size(lv_obj_t * img, bool autosize_en); + +/** + * Set the style of an image + * @param img pointer to an image object + * @param style pointer to a style + */ +static inline void lv_img_set_style(lv_obj_t *img, lv_style_t *style) +{ + lv_obj_set_style(img, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @param upscale - + */ +static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale) +{ + (void) img; + (void) upcale; +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the source of the image + * @param img pointer to an image object + * @return the image source (symbol, file name or C array) + */ +const void * lv_img_get_src(lv_obj_t * img); + +/** + * Get the name of the file set for an image + * @param img pointer to an image + * @return file name + */ +const char * lv_img_get_file_name(const lv_obj_t * img); + +#if USE_LV_MULTI_LANG +/** + * Get the source ID of the image. (Used by the multi-language feature) + * @param img pointer to an image + * @return ID of the source + */ +uint16_t lv_img_get_src_id(lv_obj_t * img); +#endif + +/** + * Get the auto size enable attribute + * @param img pointer to an image + * @return true: auto size is enabled, false: auto size is disabled + */ +bool lv_img_get_auto_size(const lv_obj_t * img); + +/** + * Get the style of an image object + * @param img pointer to an image object + * @return pointer to the image's style + */ +static inline lv_style_t* lv_img_get_style(const lv_obj_t *img) +{ + return lv_obj_get_style(img); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param img - + * @return false + */ +static inline bool lv_img_get_upscale(const lv_obj_t * img) +{ + (void)img; + return false; +} + +/********************** + * 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 /*USE_LV_IMG*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMG_H*/ diff --git a/include/display/lv_objx/lv_imgbtn.h b/include/display/lv_objx/lv_imgbtn.h new file mode 100644 index 0000000..295be8f --- /dev/null +++ b/include/display/lv_objx/lv_imgbtn.h @@ -0,0 +1,248 @@ +/** + * @file lv_imgbtn.h + * + */ + +#ifndef LV_IMGBTN_H +#define LV_IMGBTN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_IMGBTN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_imgbtn: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btn.h" +#include "display/lv_draw/lv_draw_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of image button*/ +typedef struct { + lv_btn_ext_t btn; /*Ext. of ancestor*/ + /*New data for this type */ +#if LV_IMGBTN_TILED == 0 + const void * img_src[LV_BTN_STATE_NUM]; /*Store images to each state*/ +#else + const void * img_src_left[LV_BTN_STATE_NUM]; /*Store left side images to each state*/ + const void * img_src_mid[LV_BTN_STATE_NUM]; /*Store center images to each state*/ + const void * img_src_right[LV_BTN_STATE_NUM]; /*Store right side images to each state*/ +#endif + lv_img_cf_t act_cf; /*Color format of the currently active image*/ +} lv_imgbtn_ext_t; + + +/*Styles*/ +enum { + LV_IMGBTN_STYLE_REL, + LV_IMGBTN_STYLE_PR, + LV_IMGBTN_STYLE_TGL_REL, + LV_IMGBTN_STYLE_TGL_PR, + LV_IMGBTN_STYLE_INA, +}; +typedef uint8_t lv_imgbtn_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a image button objects + * @param par pointer to an object, it will be the parent of the new image button + * @param copy pointer to a image button object, if not NULL then the new object will be copied from it + * @return pointer to the created image button + */ +lv_obj_t * lv_imgbtn_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +#if LV_IMGBTN_TILED == 0 +/** + * 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 (from `lv_btn_state_t`) ` + * @param src pointer to an image source (a C array or path to a file) + */ +void lv_imgbtn_set_src(lv_obj_t * imgbtn, lv_btn_state_t state, const void * src); +#else +/** + * 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 (from `lv_btn_state_t`) ` + * @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_btn_state_t state, const void * src_left, const void * src_mid, const void * src_right); + +#endif + +/** + * Enable the toggled states. On release the button will change from/to toggled state. + * @param imgbtn pointer to an image button object + * @param tgl true: enable toggled states, false: disable + */ +static inline void lv_imgbtn_set_toggle(lv_obj_t * imgbtn, bool tgl) +{ + lv_btn_set_toggle(imgbtn, tgl); +} + +/** + * Set the state of the image button + * @param imgbtn pointer to an image button object + * @param state the new state of the button (from lv_btn_state_t enum) + */ +static inline void lv_imgbtn_set_state(lv_obj_t * imgbtn, lv_btn_state_t state) +{ + lv_btn_set_state(imgbtn, state); +} + +/** + * Toggle the state of the image button (ON->OFF, OFF->ON) + * @param imgbtn pointer to a image button object + */ +static inline void lv_imgbtn_toggle(lv_obj_t * imgbtn) +{ + lv_btn_toggle(imgbtn); +} + +/** + * Set a function to call when a button event happens + * @param imgbtn pointer to an image button object + * @param action type of event form 'lv_action_t' (press, release, long press, long press repeat) + */ +static inline void lv_imgbtn_set_action(lv_obj_t * imgbtn, lv_btn_action_t type, lv_action_t action) +{ + lv_btn_set_action(imgbtn, type, action); +} + +/** + * Set a style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_imgbtn_set_style(lv_obj_t * imgbtn, lv_imgbtn_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + + +#if LV_IMGBTN_TILED == 0 +/** + * Get the images 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 an image source (a C array or path to a file) + */ +const void * lv_imgbtn_get_src(lv_obj_t * imgbtn, lv_btn_state_t state); + +#else + +/** + * 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_btn_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_btn_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_btn_state_t state); + +#endif +/** + * Get the current state of the image button + * @param imgbtn pointer to a image button object + * @return the state of the button (from lv_btn_state_t enum) + */ +static inline lv_btn_state_t lv_imgbtn_get_state(const lv_obj_t * imgbtn) +{ + return lv_btn_get_state(imgbtn); +} + +/** + * Get the toggle enable attribute of the image button + * @param imgbtn pointer to a image button object + * @return ture: toggle enabled, false: disabled + */ +static inline bool lv_imgbtn_get_toggle(const lv_obj_t * imgbtn) +{ + return lv_btn_get_toggle(imgbtn); +} + +/** + * Get the release action of a image button + * @param imgbtn pointer to a image button object + * @return pointer to the release action function + */ +static inline lv_action_t lv_imgbtn_get_action(const lv_obj_t * imgbtn, lv_btn_action_t type) +{ + return lv_btn_get_action(imgbtn, type); +} + +/** + * Get style of a image button. + * @param imgbtn pointer to image button object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_imgbtn_get_style(const lv_obj_t * imgbtn, lv_imgbtn_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_IMGBTN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_IMGBTN_H*/ diff --git a/include/display/lv_objx/lv_kb.h b/include/display/lv_objx/lv_kb.h new file mode 100644 index 0000000..d6ab979 --- /dev/null +++ b/include/display/lv_objx/lv_kb.h @@ -0,0 +1,199 @@ +/** + * @file lv_kb.h + * + */ + +#ifndef LV_KB_H +#define LV_KB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_KB != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_kb: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_TA == 0 +#error "lv_kb: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_btnm.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_KB_MODE_TEXT, + LV_KB_MODE_NUM, +}; +typedef uint8_t lv_kb_mode_t; + +/*Data of keyboard*/ +typedef struct { + lv_btnm_ext_t btnm; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *ta; /*Pointer to the assigned text area*/ + lv_kb_mode_t mode; /*Key map type*/ + uint8_t cursor_mng :1; /*1: automatically show/hide cursor when a text area is assigned or left*/ + lv_action_t ok_action; /*Called when the "Ok" button is clicked*/ + lv_action_t hide_action; /*Called when the "Hide" button is clicked*/ +} lv_kb_ext_t; + +enum { + LV_KB_STYLE_BG, + LV_KB_STYLE_BTN_REL, + LV_KB_STYLE_BTN_PR, + LV_KB_STYLE_BTN_TGL_REL, + LV_KB_STYLE_BTN_TGL_PR, + LV_KB_STYLE_BTN_INA, +}; +typedef uint8_t lv_kb_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a keyboard objects + * @param par pointer to an object, it will be the parent of the new keyboard + * @param copy pointer to a keyboard object, if not NULL then the new object will be copied from it + * @return pointer to the created keyboard + */ +lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * 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_kb_set_ta(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_kb_mode_t' + */ +void lv_kb_set_mode(lv_obj_t * kb, lv_kb_mode_t mode); + +/** + * Automatically hide or show the cursor of the current Text Area + * @param kb pointer to a Keyboard object + * @param en true: show cursor on the current text area, false: hide cursor + */ +void lv_kb_set_cursor_manage(lv_obj_t * kb, bool en); + +/** + * Set call back to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_ok_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set call back to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @param action a callback with 'lv_action_t' type + */ +void lv_kb_set_hide_action(lv_obj_t * kb, lv_action_t action); + +/** + * Set a new map for the keyboard + * @param kb pointer to a Keyboard object + * @param map pointer to a string array to describe the map. + * See 'lv_btnm_set_map()' for more info. + */ +static inline void lv_kb_set_map(lv_obj_t *kb, const char ** map) +{ + lv_btnm_set_map(kb, map); +} + +/** + * Set a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_kb_set_style(lv_obj_t *kb, lv_kb_style_t type, lv_style_t *style); + +/*===================== + * 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_kb_get_ta(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_kb_mode_t' + */ +lv_kb_mode_t lv_kb_get_mode(const lv_obj_t * kb); + +/** + * Get the current cursor manage mode. + * @param kb pointer to a Keyboard object + * @return true: show cursor on the current text area, false: hide cursor + */ +bool lv_kb_get_cursor_manage(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Ok" button is pressed + * @param kb pointer to Keyboard object + * @return the ok callback + */ +lv_action_t lv_kb_get_ok_action(const lv_obj_t * kb); + +/** + * Get the callback to call when the "Hide" button is pressed + * @param kb pointer to Keyboard object + * @return the close callback + */ +lv_action_t lv_kb_get_hide_action(const lv_obj_t * kb); + +/** + * Get a style of a keyboard + * @param kb pointer to a keyboard object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_kb_get_style(const lv_obj_t *kb, lv_kb_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_KB*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_KB_H*/ diff --git a/include/display/lv_objx/lv_label.h b/include/display/lv_objx/lv_label.h new file mode 100644 index 0000000..abd176a --- /dev/null +++ b/include/display/lv_objx/lv_label.h @@ -0,0 +1,295 @@ +/** + * @file lv_rect.h + * + */ + +#ifndef LV_LABEL_H +#define LV_LABEL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LABEL != 0 + +#include "display/lv_core/lv_obj.h" +#include "display/lv_misc/lv_font.h" +#include "display/lv_misc/lv_txt.h" +#include "display/lv_misc/lv_symbol_def.h" + +/********************* + * DEFINES + *********************/ +#define LV_LABEL_DOT_NUM 3 +#define LV_LABEL_POS_LAST 0xFFFF + +/********************** + * TYPEDEFS + **********************/ + +/*Long mode behaviors. Used in 'lv_label_ext_t' */ +enum +{ + LV_LABEL_LONG_EXPAND, /*Expand the object size to the text size*/ + LV_LABEL_LONG_BREAK, /*Keep the object width, break the too long lines and expand the object height*/ + LV_LABEL_LONG_SCROLL, /*Expand the object size and scroll the text on the parent (move the label object)*/ + LV_LABEL_LONG_DOT, /*Keep the size and write dots at the end if the text is too long*/ + LV_LABEL_LONG_ROLL, /*Keep the size and roll the text infinitely*/ + LV_LABEL_LONG_CROP, /*Keep the size and crop the text out of it*/ +}; +typedef uint8_t lv_label_long_mode_t; + +/*Label align policy*/ +enum { + LV_LABEL_ALIGN_LEFT, + LV_LABEL_ALIGN_CENTER, + LV_LABEL_ALIGN_RIGHT, +}; +typedef uint8_t lv_label_align_t; + +/*Data of label*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + char * text; /*Text of the label*/ + lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/ +#if LV_TXT_UTF8 == 0 + char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#else + char dot_tmp[LV_LABEL_DOT_NUM * 4 + 1]; /*Store the character which are replaced by dots (Handled by the library)*/ +#endif + +#if USE_LV_MULTI_LANG + uint16_t lang_txt_id; /*The ID of the text to display*/ +#endif + uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ + uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/ + lv_point_t offset; /*Text draw position offset*/ + uint8_t static_txt :1; /*Flag to indicate the text is static*/ + uint8_t align :2; /*Align type from 'lv_label_align_t'*/ + 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_ROLL)*/ + uint8_t body_draw :1; /*Draw background body*/ +} lv_label_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a label objects + * @param par pointer to an object, it will be the parent of the new label + * @param copy pointer to a button object, if not NULL then the new object will be copied from it + * @return pointer to the created button + */ +lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new text for a label. Memory will be allocated to store the text by the label. + * @param label 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 * label, const char * text); + +/** + * Set a new text for a label from a character array. The array don't has to be '\0' terminated. + * Memory will be allocated to store the array by the label. + * @param label pointer to a label object + * @param array array of characters or NULL to refresh the label + * @param size the size of 'array' in bytes + */ +void lv_label_set_array_text(lv_obj_t * label, const char * array, uint16_t size); + +/** + * Set a static text. It will not be saved by the label so the 'text' variable + * has to be 'alive' while the label exist. + * @param label pointer to a label object + * @param text pointer to a text. NULL to refresh with the current text. + */ +void lv_label_set_static_text(lv_obj_t * label, const char * text); + +/** + *Set a text ID which means a the same text but on different languages + * @param label pointer to a label object + * @param txt_id ID of the text + */ +#if USE_LV_MULTI_LANG +void lv_label_set_text_id(lv_obj_t * label, uint32_t txt_id); +#endif + +/** + * Set the behavior of the label with longer text then the object size + * @param label pointer to a label object + * @param long_mode the new mode from 'lv_label_long_mode' enum. + * In LV_LONG_BREAK/LONG/ROLL the size of the label should be set AFTER this function + */ +void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode); + +/** + * Set the align of the label (left or center) + * @param label pointer to a label object + * @param align 'LV_LABEL_ALIGN_LEFT' or 'LV_LABEL_ALIGN_LEFT' + */ +void lv_label_set_align(lv_obj_t *label, lv_label_align_t align); + +/** + * Enable the recoloring by in-line commands + * @param label pointer to a label object + * @param en true: enable recoloring, false: disable + */ +void lv_label_set_recolor(lv_obj_t * label, bool en); + +/** + * Set the label to draw (or not draw) background specified in its style's body + * @param label pointer to a label object + * @param en true: draw body; false: don't draw body + */ +void lv_label_set_body_draw(lv_obj_t *label, bool en); + +/** + * Set the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @param anim_speed speed of animation in px/sec unit + */ +void lv_label_set_anim_speed(lv_obj_t *label, uint16_t anim_speed); + +/** + * Set the style of an label + * @param label pointer to an label object + * @param style pointer to a style + */ +static inline void lv_label_set_style(lv_obj_t *label, lv_style_t *style) +{ + lv_obj_set_style(label, style); +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a label + * @param label pointer to a label object + * @return the text of the label + */ +char * lv_label_get_text(const lv_obj_t * label); + +#if USE_LV_MULTI_LANG +/** + * Get the text ID of the label. (Used by the multi-language feature) + * @param label pointer to a label object + * @return ID of the text + */ +uint16_t lv_label_get_text_id(lv_obj_t * label); +#endif + +/** + * Get the long mode of a label + * @param label pointer to a label object + * @return the long mode + */ +lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label); + +/** + * Get the align attribute + * @param label pointer to a label object + * @return LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_label_get_align(const lv_obj_t * label); + +/** + * Get the recoloring attribute + * @param label pointer to a label object + * @return true: recoloring is enabled, false: disable + */ +bool lv_label_get_recolor(const lv_obj_t * label); + +/** + * Get the body draw attribute + * @param label pointer to a label object + * @return true: draw body; false: don't draw body + */ +bool lv_label_get_body_draw(const lv_obj_t *label); + +/** + * Get the label's animation speed in LV_LABEL_LONG_ROLL and SCROLL modes + * @param label pointer to a label object + * @return speed of animation in px/sec unit + */ +uint16_t lv_label_get_anim_speed(const lv_obj_t *label); + +/** + * Get the relative x and y coordinates of a letter + * @param label pointer to a label object + * @param index index of the letter [0 ... text length]. 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) + */ +void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t * pos); + +/** + * Get the index of letter on a relative point of a label + * @param label 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) + * Expressed in character index and not byte index (different in UTF-8) + */ +uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos); + +/** + * Get the style of an label object + * @param label pointer to an label object + * @return pointer to the label's style + */ +static inline lv_style_t* lv_label_get_style(const lv_obj_t *label) +{ + return lv_obj_get_style(label); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Insert a text to the label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 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 * label, uint32_t pos, const char * txt); + +/** + * Delete characters from a label. The label text can not be static. + * @param label pointer to a label object + * @param pos character index to insert. Expressed in character index and not byte index (Different in UTF-8) + * 0: before first char. + * @param cnt number of characters to cut + */ +void lv_label_cut_text(lv_obj_t * label, uint32_t pos, uint32_t cnt); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LABEL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LABEL_H*/ diff --git a/include/display/lv_objx/lv_led.h b/include/display/lv_objx/lv_led.h new file mode 100644 index 0000000..f6a18ac --- /dev/null +++ b/include/display/lv_objx/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 + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LED != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of led*/ +typedef struct +{ + /*No inherited ext.*/ + /*New data for this type */ + uint8_t bright; /*Current brightness of the LED (0..255)*/ +} lv_led_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a led objects + * @param par pointer to an object, it will be the parent of the new led + * @param copy pointer to a led object, if not NULL then the new object will be copied from it + * @return pointer to the created led + */ +lv_obj_t * lv_led_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Set the brightness of a LED object + * @param led pointer to a LED object + * @param bright 0 (max. dark) ... 255 (max. light) + */ +void lv_led_set_bright(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); + +/** + * Set the style of a led + * @param led pointer to a led object + * @param style pointer to a style + */ +static inline void lv_led_set_style(lv_obj_t *led, lv_style_t *style) +{ + lv_obj_set_style(led, style); +} + +/** + * 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_bright(const lv_obj_t * led); + +/** + * Get the style of an led object + * @param led pointer to an led object + * @return pointer to the led's style + */ +static inline lv_style_t* lv_led_get_style(const lv_obj_t *led) +{ + return lv_obj_get_style(led); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LED*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LED_H*/ diff --git a/include/display/lv_objx/lv_line.h b/include/display/lv_objx/lv_line.h new file mode 100644 index 0000000..e7be8a3 --- /dev/null +++ b/include/display/lv_objx/lv_line.h @@ -0,0 +1,158 @@ +/** + * @file lv_line.h + * + */ + +#ifndef LV_LINE_H +#define LV_LINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LINE != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of line*/ +typedef struct +{ + /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ + 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 auto_size :1; /*1: set obj. width to x max and obj. height to y max */ + uint8_t y_inv :1; /*1: y == 0 will be on the bottom*/ +} lv_line_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a line objects + * @param par 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 * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set an array of points. The line object will connect these points. + * @param line pointer to a line object + * @param point_a an array of points. Only the address is saved, + * so the array can NOT be a local variable which will be destroyed + * @param point_num number of points in 'point_a' + */ +void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num); + +/** + * Enable (or disable) the auto-size option. The size of the object will fit to its points. + * (set width to x max and height to y max) + * @param line pointer to a line object + * @param en true: auto size is enabled, false: auto size is disabled + */ +void lv_line_set_auto_size(lv_obj_t * line, bool en); + +/** + * 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 line 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 * line, bool en); + +#define lv_line_set_y_inv lv_line_set_y_invert /*The name was inconsistent. In v.6.0 only `lv_line_set_y_invert`will work */ + +/** + * Set the style of a line + * @param line pointer to a line object + * @param style pointer to a style + */ +static inline void lv_line_set_style(lv_obj_t *line, lv_style_t *style) +{ + lv_obj_set_style(line, style); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @param upscale - + */ +static inline void lv_line_set_upscale(lv_obj_t * line, bool upcale) +{ + (void) line; + (void) upcale; +} +/*===================== + * Getter functions + *====================*/ + +/** + * Get the auto size attribute + * @param line pointer to a line object + * @return true: auto size is enabled, false: disabled + */ +bool lv_line_get_auto_size(const lv_obj_t * line); + +/** + * Get the y inversion attribute + * @param line pointer to a line object + * @return true: y inversion is enabled, false: disabled + */ +bool lv_line_get_y_invert(const lv_obj_t * line); + +/** + * Get the style of an line object + * @param line pointer to an line object + * @return pointer to the line's style + */ +static inline lv_style_t* lv_line_get_style(const lv_obj_t *line) +{ + return lv_obj_get_style(line); +} + +/** + * Obsolete since v5.1. Just for compatibility with v5.0. Will be removed in v6.0 + * @param line - + * @return false + */ +static inline bool lv_line_get_upscale(const lv_obj_t * line) +{ + (void) line; + return false; +} + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LINE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LINE_H*/ diff --git a/include/display/lv_objx/lv_list.h b/include/display/lv_objx/lv_list.h new file mode 100644 index 0000000..397059a --- /dev/null +++ b/include/display/lv_objx/lv_list.h @@ -0,0 +1,336 @@ +/** + * @file lv_list.h + * + */ + +#ifndef LV_LIST_H +#define LV_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LIST != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_list: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_BTN == 0 +#error "lv_list: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_list: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of list*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t anim_time; /*Scroll animation time*/ + lv_style_t *styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/ + lv_style_t *style_img; /*Style of the list element images on buttons*/ + uint32_t size; /*the number of items(buttons) in the list*/ + bool single_mode; /* whether single selected mode is enabled */ +#if USE_LV_GROUP + lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */ + lv_obj_t * selected_btn; /* The button is currently being selected*/ +#endif +} lv_list_ext_t; + +enum { + LV_LIST_STYLE_BG, + LV_LIST_STYLE_SCRL, + LV_LIST_STYLE_SB, + LV_LIST_STYLE_EDGE_FLASH, + LV_LIST_STYLE_BTN_REL, + LV_LIST_STYLE_BTN_PR, + LV_LIST_STYLE_BTN_TGL_REL, + LV_LIST_STYLE_BTN_TGL_PR, + LV_LIST_STYLE_BTN_INA, +}; +typedef uint8_t lv_list_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a list objects + * @param par pointer to an object, it will be the parent of the new list + * @param copy pointer to a list object, if not NULL then the new object will be copied from it + * @return pointer to the created list + */ +lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_list_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a list element to the list + * @param list pointer to list object + * @param img_fn file name of an image before the text (NULL if unused) + * @param txt text of the list element (NULL if unused) + * @param rel_action pointer to release action function (like with lv_btn) + * @return pointer to the new list element which can be customized (a button) + */ +lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt, lv_action_t rel_action); + +/** + * Remove the index of the button in the list + * @param list pointer to a list object + * @param index pointer to a the button's index in the list, index must be 0 <= index < lv_list_ext_t.size + * @return true: successfully deleted + */ +bool lv_list_remove(const lv_obj_t * list, uint32_t index); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set single button selected mode, only one button will be selected if enabled. + * @param list pointer to the currently pressed list object + * @param mode, enable(true)/disable(false) single selected mode. + */ +void lv_list_set_single_mode(lv_obj_t *list, bool mode); + +#if USE_LV_GROUP + +/** + * Make a button selected. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @param btn pointer to a button to select + */ +void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn); +#endif + +/** + * Set scroll animation duration on 'list_up()' 'list_down()' 'list_focus()' + * @param list pointer to a list object + * @param anim_time duration of animation [ms] + */ +void lv_list_set_anim_time(lv_obj_t *list, uint16_t anim_time); + +/** + * Set the scroll bar mode of a list + * @param list pointer to a list object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_list_set_sb_mode(lv_obj_t * list, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(list, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the List will move its parent if there is no more space to scroll. + * @param list pointer to a List + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_list_set_scroll_propagation(lv_obj_t * list, bool en) +{ + lv_page_set_scroll_propagation(list, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param list pointer to a List + * @param en true or false to enable/disable end flash + */ +static inline void lv_list_set_edge_flash(lv_obj_t * list, bool en) +{ + lv_page_set_edge_flash(list, en); +} + +/** + * Set a style of a list + * @param list pointer to a list object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_list_set_style(lv_obj_t *list, lv_list_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get single button selected mode. + * @param list pointer to the currently pressed list object. + */ +bool lv_list_get_single_mode(lv_obj_t *list); + +/** + * Get the text of a list element + * @param btn pointer to list element + * @return pointer to the text + */ +const char * lv_list_get_btn_text(const lv_obj_t * btn); +/** + * Get the label object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the label from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_label(const lv_obj_t * btn); + +/** + * Get the image object from a list element + * @param btn pointer to a list element (button) + * @return pointer to the image from the list element or NULL if not found + */ +lv_obj_t * lv_list_get_btn_img(const lv_obj_t * btn); + +/** + * Get the next button from list. (Starts from the bottom button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the next after it. + * @return pointer to the next button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_prev_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the previous button from list. (Starts from the top button) + * @param list pointer to a list object + * @param prev_btn pointer to button. Search the previous before it. + * @return pointer to the previous button or NULL when no more buttons + */ +lv_obj_t * lv_list_get_next_btn(const lv_obj_t * list, lv_obj_t * prev_btn); + +/** + * Get the index of the button in the list + * @param list pointer to a list object. If NULL, assumes btn is part of a list. + * @param btn pointer to a list element (button) + * @return the index of the button in the list, or -1 of the button not in this list + */ +int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn); + +/** + * Get the number of buttons in the list + * @param list pointer to a list object + * @return the number of buttons in the list + */ +uint32_t lv_list_get_size(const lv_obj_t * list); + +#if USE_LV_GROUP +/** + * Get the currently selected button. Can be used while navigating in the list with a keypad. + * @param list pointer to a list object + * @return pointer to the selected button + */ +lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list); +#endif + + +/** + * Get scroll animation duration + * @param list pointer to a list object + * @return duration of animation [ms] + */ +uint16_t lv_list_get_anim_time(const lv_obj_t *list); + + +/** + * Get the scroll bar mode of a list + * @param list pointer to a list object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_list_get_sb_mode(const lv_obj_t * list) +{ + return lv_page_get_sb_mode(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_scroll_propagation(lv_obj_t * list) +{ + return lv_page_get_scroll_propagation(list); +} + +/** + * Get the scroll propagation property + * @param list pointer to a List + * @return true or false + */ +static inline bool lv_list_get_edge_flash(lv_obj_t * list) +{ + return lv_page_get_edge_flash(list); +} + +/** + * Get a style of a list + * @param list pointer to a list object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_list_get_style(const lv_obj_t *list, lv_list_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the list elements up by one + * @param list pointer a to list object + */ +void lv_list_up(const lv_obj_t * list); +/** + * Move the list elements down by one + * @param list pointer to a list object + */ +void lv_list_down(const lv_obj_t * list); + +/** + * Focus on a list button. It ensures that the button will be visible on the list. + * @param btn pointer to a list button to focus + * @param anim_en true: scroll with animation, false: without animation + */ +void lv_list_focus(const lv_obj_t *btn, bool anim_en); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LIST*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LIST_H*/ diff --git a/include/display/lv_objx/lv_lmeter.h b/include/display/lv_objx/lv_lmeter.h new file mode 100644 index 0000000..dcb42bf --- /dev/null +++ b/include/display/lv_objx/lv_lmeter.h @@ -0,0 +1,153 @@ +/** + * @file lv_lmeter.h + * + */ + +#ifndef LV_LMETER_H +#define LV_LMETER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_LMETER != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of line meter*/ +typedef struct +{ + /*No inherited ext.*/ /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ + uint8_t line_cnt; /*Count of lines */ + int16_t cur_value; + int16_t min_value; + int16_t max_value; +} lv_lmeter_ext_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a line meter objects + * @param par pointer to an object, it will be the parent of the new line meter + * @param copy pointer to a line meter object, if not NULL then the new object will be copied from it + * @return pointer to the created line meter + */ +lv_obj_t * lv_lmeter_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the line meter + * @param lmeter pointer to a line meter object + * @param value new value + */ +void lv_lmeter_set_value(lv_obj_t *lmeter, int16_t value); + +/** + * Set minimum and the maximum values of a line meter + * @param lmeter pointer to he line meter object + * @param min minimum value + * @param max maximum value + */ +void lv_lmeter_set_range(lv_obj_t *lmeter, int16_t min, int16_t max); + +/** + * Set the scale settings of a line meter + * @param lmeter pointer to a line meter object + * @param angle angle of the scale (0..360) + * @param line_cnt number of lines + */ +void lv_lmeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint8_t line_cnt); + +/** + * Set the styles of a line meter + * @param lmeter pointer to a line meter object + * @param bg set the style of the line meter + */ +static inline void lv_lmeter_set_style(lv_obj_t *lmeter, lv_style_t *bg) +{ + lv_obj_set_style(lmeter, bg); +} + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a line meter + * @param lmeter pointer to a line meter object + * @return the value of the line meter + */ +int16_t lv_lmeter_get_value(const lv_obj_t *lmeter); + +/** + * Get the minimum value of a line meter + * @param lmeter pointer to a line meter object + * @return the minimum value of the line meter + */ +int16_t lv_lmeter_get_min_value(const lv_obj_t * lmeter); + +/** + * Get the maximum value of a line meter + * @param lmeter pointer to a line meter object + * @return the maximum value of the line meter + */ +int16_t lv_lmeter_get_max_value(const lv_obj_t * lmeter); + +/** + * Get the scale number of a line meter + * @param lmeter pointer to a line meter object + * @return number of the scale units + */ +uint8_t lv_lmeter_get_line_count(const lv_obj_t * lmeter); + +/** + * Get the scale angle of a line meter + * @param lmeter pointer to a line meter object + * @return angle of the scale + */ +uint16_t lv_lmeter_get_scale_angle(const lv_obj_t * lmeter); + +/** + * Get the style of a line meter + * @param lmeter pointer to a line meter object + * @return pointer to the line meter's style + */ +static inline lv_style_t * lv_lmeter_get_style(const lv_obj_t * lmeter) +{ + return lv_obj_get_style(lmeter); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_LMETER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_LMETER_H*/ diff --git a/include/display/lv_objx/lv_mbox.h b/include/display/lv_objx/lv_mbox.h new file mode 100644 index 0000000..2dc0c6d --- /dev/null +++ b/include/display/lv_objx/lv_mbox.h @@ -0,0 +1,203 @@ +/** + * @file lv_mbox.h + * + */ + +#ifndef LV_MBOX_H +#define LV_MBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_MBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_mbox: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#if USE_LV_BTNM == 0 +#error "lv_mbox: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_mbox: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btnm.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of message box*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t *text; /*Text of the message box*/ + lv_obj_t *btnm; /*Button matrix for the buttons*/ + uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/ +} lv_mbox_ext_t; + +enum { + LV_MBOX_STYLE_BG, + LV_MBOX_STYLE_BTN_BG, + LV_MBOX_STYLE_BTN_REL, + LV_MBOX_STYLE_BTN_PR, + LV_MBOX_STYLE_BTN_TGL_REL, + LV_MBOX_STYLE_BTN_TGL_PR, + LV_MBOX_STYLE_BTN_INA, +}; +typedef uint8_t lv_mbox_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a message box objects + * @param par pointer to an object, it will be the parent of the new message box + * @param copy pointer to a message box object, if not NULL then the new object will be copied from it + * @return pointer to the created message box + */ +lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add button to the message box + * @param mbox pointer to message box object + * @param btn_map button descriptor (button matrix map). + * E.g. a const char *txt[] = {"ok", "close", ""} (Can not be local variable) + * @param action a function which will be called when a button is released + */ +void lv_mbox_add_btns(lv_obj_t * mbox, const char **btn_map, lv_btnm_action_t action); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of the message box + * @param mbox pointer to a message box + * @param txt a '\0' terminated character string which will be the message box text + */ +void lv_mbox_set_text(lv_obj_t * mbox, const char * txt); + +/** + * Stop the action to call when button is released + * @param mbox pointer to a message box object + * @param pointer to an 'lv_btnm_action_t' action. In the action you need to use `lv_mbox_get_from_btn()` to get the `mbox`. + */ +void lv_mbox_set_action(lv_obj_t * mbox, lv_btnm_action_t action); + +/** + * Set animation duration + * @param mbox pointer to a message box object + * @param anim_time animation length in milliseconds (0: no animation) + */ +void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time); + +/** + * Automatically delete the message box after a given time + * @param mbox pointer to a message box object + * @param delay a time (in milliseconds) to wait before delete the message box + */ +void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay); + +/** + * Stop the auto. closing of message box + * @param mbox pointer to a message box object + */ +void lv_mbox_stop_auto_close(lv_obj_t * mbox); + +/** + * Set a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_mbox_set_style(lv_obj_t *mbox, lv_mbox_style_t type, lv_style_t *style); + +/** + * Set whether recoloring is enabled. Must be called after `lv_mbox_add_btns`. + * @param btnm pointer to button matrix object + * @param en whether recoloring is enabled + */ +void lv_mbox_set_recolor(lv_obj_t * mbox, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of the message box + * @param mbox pointer to a message box object + * @return pointer to the text of the message box + */ +const char * lv_mbox_get_text(const lv_obj_t * mbox); + +/** + * Get the message box object from one of its button. + * It is useful in the button release actions where only the button is known + * @param btn pointer to a button of a message box + * @return pointer to the button's message box + */ +lv_obj_t * lv_mbox_get_from_btn(const lv_obj_t * btn); + +/** + * Get the animation duration (close animation time) + * @param mbox pointer to a message box object + * @return animation length in milliseconds (0: no animation) + */ +uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox); + + +/** + * Get a style of a message box + * @param mbox pointer to a message box object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_mbox_get_style(const lv_obj_t *mbox, lv_mbox_style_t type); + +/** + * Get whether recoloring is enabled + * @param btnm pointer to button matrix object + * @return whether recoloring is enabled + */ +bool lv_mbox_get_recolor(const lv_obj_t * mbox); + +/********************** + * MACROS + **********************/ + + +#endif /*USE_LV_MBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_MBOX_H*/ diff --git a/include/display/lv_objx/lv_objx.mk b/include/display/lv_objx/lv_objx.mk new file mode 100644 index 0000000..d35252b --- /dev/null +++ b/include/display/lv_objx/lv_objx.mk @@ -0,0 +1,36 @@ +CSRCS += lv_arc.c +CSRCS += lv_bar.c +CSRCS += lv_cb.c +CSRCS += lv_ddlist.c +CSRCS += lv_kb.c +CSRCS += lv_line.c +CSRCS += lv_mbox.c +CSRCS += lv_preload.c +CSRCS += lv_roller.c +CSRCS += lv_table.c +CSRCS += lv_tabview.c +CSRCS += lv_tileview.c +CSRCS += lv_btn.c +CSRCS += lv_calendar.c +CSRCS += lv_chart.c +CSRCS += lv_canvas.c +CSRCS += lv_gauge.c +CSRCS += lv_label.c +CSRCS += lv_list.c +CSRCS += lv_slider.c +CSRCS += lv_ta.c +CSRCS += lv_spinbox.c +CSRCS += lv_btnm.c +CSRCS += lv_cont.c +CSRCS += lv_img.c +CSRCS += lv_imgbtn.c +CSRCS += lv_led.c +CSRCS += lv_lmeter.c +CSRCS += lv_page.c +CSRCS += lv_sw.c +CSRCS += lv_win.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_objx +VPATH += :$(LVGL_DIR)/lvgl/lv_objx + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_objx" diff --git a/include/display/lv_objx/lv_objx_templ.h b/include/display/lv_objx/lv_objx_templ.h new file mode 100644 index 0000000..b8473df --- /dev/null +++ b/include/display/lv_objx/lv_objx_templ.h @@ -0,0 +1,111 @@ +/** + * @file lv_templ.h + * + */ + + +/* TODO Remove these instructions + * Search an replace: template -> object normal name with lower case (e.g. button, label etc.) + * 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 + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TEMPL != 0 + +#include "display/lv_core/lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of template*/ +typedef struct { + lv_ANCESTOR_ext_t ANCESTOR; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_templ_ext_t; + + +/*Styles*/ +enum { + LV_TEMPL_STYLE_X, + LV_TEMPL_STYLE_Y, +}; +typedef uint8_t lv_templ_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a template objects + * @param par pointer to an object, it will be the parent of the new template + * @param copy pointer to a template object, if not NULL then the new object will be copied from it + * @return pointer to the created template + */ +lv_obj_t * lv_templ_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a template. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_templ_set_style(lv_obj_t * templ, lv_templ_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a template. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_templ_get_style(const lv_obj_t * templ, lv_templ_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TEMPL*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TEMPL_H*/ diff --git a/include/display/lv_objx/lv_page.h b/include/display/lv_objx/lv_page.h new file mode 100644 index 0000000..d01de35 --- /dev/null +++ b/include/display/lv_objx/lv_page.h @@ -0,0 +1,382 @@ +/** + * @file lv_page.h + * + */ + +#ifndef LV_PAGE_H +#define LV_PAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PAGE != 0 + +/*Testing of dependencies*/ +#if USE_LV_CONT == 0 +#error "lv_page: lv_cont is required. Enable it in lv_conf.h (USE_LV_CONT 1) " +#endif + +#include "lv_cont.h" +#include "display/lv_core/lv_indev.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Scrollbar modes: shows when should the scrollbars be visible*/ +enum +{ + LV_SB_MODE_OFF = 0x0, /*Never show scrollbars*/ + LV_SB_MODE_ON = 0x1, /*Always show scrollbars*/ + LV_SB_MODE_DRAG = 0x2, /*Show scrollbars when page is being dragged*/ + LV_SB_MODE_AUTO = 0x3, /*Show scrollbars when the scrollable container is large enough to be scrolled*/ + LV_SB_MODE_HIDE = 0x4, /*Hide the scroll bar temporally*/ + LV_SB_MODE_UNHIDE = 0x5, /*Unhide the previously hidden scrollbar. Recover it's type too*/ +}; +typedef uint8_t lv_sb_mode_t; + +/*Data of page*/ +typedef struct +{ + lv_cont_ext_t bg; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * scrl; /*The scrollable object on the background*/ + lv_action_t rel_action; /*Function to call when the page is released*/ + lv_action_t pr_action; /*Function to call when the page is pressed*/ + struct { + lv_style_t *style; /*Style of scrollbars*/ + lv_area_t hor_area; /*Horizontal scrollbar area relative to the page. (Handled by the library) */ + lv_area_t ver_area; /*Vertical scrollbar area relative to the page (Handled by the library)*/ + uint8_t hor_draw :1; /*1: horizontal scrollbar is visible now (Handled by the library)*/ + uint8_t ver_draw :1; /*1: vertical scrollbar is visible now (Handled by the library)*/ + lv_sb_mode_t mode:3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/ + } sb; + struct { + uint16_t state; /*Store the current size of the edge flash effect*/ + lv_style_t *style; /*Style of edge flash effect (usually homogeneous circle)*/ + uint8_t enabled :1; /*1: Show a flash animation on the edge*/ + uint8_t top_ip :1; /*Used internally to show that top most position is reached (flash is In Progress)*/ + uint8_t bottom_ip :1; /*Used internally to show that bottom most position is reached (flash is In Progress)*/ + uint8_t right_ip :1; /*Used internally to show that right most position is reached (flash is In Progress)*/ + uint8_t left_ip :1; /*Used internally to show that left most position is reached (flash is In Progress)*/ + }edge_flash; + + uint8_t arrow_scroll :1; /*1: Enable scrolling with LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN*/ + uint8_t scroll_prop :1; /*1: Propagate the scrolling the the parent if the edge is reached*/ + uint8_t scroll_prop_ip :1; /*1: Scroll propagation is in progress (used by the library)*/ +} lv_page_ext_t; + +enum { + LV_PAGE_STYLE_BG, + LV_PAGE_STYLE_SCRL, + LV_PAGE_STYLE_SB, + LV_PAGE_STYLE_EDGE_FLASH, +}; +typedef uint8_t lv_page_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a page objects + * @param par pointer to an object, it will be the parent of the new page + * @param copy pointer to a page object, if not NULL then the new object will be copied from it + * @return pointer to the created page + */ +lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_page_clean(lv_obj_t *obj); + +/** + * Get the press action of the page + * @param page pointer to a page object + * @return a function to call when the page is pressed + */ +lv_action_t lv_page_get_pr_action(lv_obj_t * page); + +/** + * Get the release action of the page + * @param page pointer to a page object + * @return a function to call when the page is released + */ +lv_action_t lv_page_get_rel_action(lv_obj_t * page); + +/** + * Get the scrollable object of a page + * @param page pointer to a page object + * @return pointer to a container which is the scrollable part of the page + */ +lv_obj_t * lv_page_get_scrl(const lv_obj_t * page); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a release action for the page + * @param page pointer to a page object + * @param rel_action a function to call when the page is released + */ +void lv_page_set_rel_action(lv_obj_t * page, lv_action_t rel_action); + +/** + * Set a press action for the page + * @param page pointer to a page object + * @param pr_action a function to call when the page is pressed + */ +void lv_page_set_pr_action(lv_obj_t * page, lv_action_t pr_action); + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @param sb_mode the new mode from 'lv_page_sb.mode_t' enum + */ +void lv_page_set_sb_mode(lv_obj_t * page, lv_sb_mode_t sb_mode); + +/** + * Enable/Disable scrolling with arrows if the page is in group (arrows: LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) + * @param page pointer to a page object + * @param en true: enable scrolling with arrows + */ +void lv_page_set_arrow_scroll(lv_obj_t * page, bool en); + +/** + * Enable the scroll propagation feature. If enabled then the page will move its parent if there is no more space to scroll. + * @param page pointer to a Page + * @param en true or false to enable/disable scroll propagation + */ +void lv_page_set_scroll_propagation(lv_obj_t * page, bool en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Page + * @param en true or false to enable/disable end flash + */ +void lv_page_set_edge_flash(lv_obj_t * page, bool en); + +/** + * Set the fit attribute of the scrollable part of a page. + * It means it can set its size automatically to involve all children. + * (Can be set separately horizontally and vertically) + * @param page pointer to a page object + * @param hor_en true: enable horizontal fit + * @param ver_en true: enable vertical fit + */ +static inline void lv_page_set_scrl_fit(lv_obj_t *page, bool hor_en, bool ver_en) +{ + lv_cont_set_fit(lv_page_get_scrl(page), hor_en, ver_en); +} + +/** + * Set width of the scrollable part of a page + * @param page pointer to a page object + * @param w the new width of the scrollable (it ha no effect is horizontal fit is enabled) + */ +static inline void lv_page_set_scrl_width(lv_obj_t *page, lv_coord_t w) +{ + lv_obj_set_width(lv_page_get_scrl(page), w); +} + +/** + * Set height of the scrollable part of a page + * @param page pointer to a page object + * @param h the new height of the scrollable (it ha no effect is vertical fit is enabled) + */ +static inline void lv_page_set_scrl_height(lv_obj_t *page, lv_coord_t h) +{ + lv_obj_set_height(lv_page_get_scrl(page), h); + +} + +/** +* Set the layout of the scrollable part of the page +* @param page pointer to a page object +* @param layout a layout from 'lv_cont_layout_t' +*/ +static inline void lv_page_set_scrl_layout(lv_obj_t * page, lv_layout_t layout) +{ + lv_cont_set_layout(lv_page_get_scrl(page), layout); +} + +/** + * Set a style of a page + * @param page pointer to a page object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_page_set_style(lv_obj_t *page, lv_page_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Set the scroll bar mode on a page + * @param page pointer to a page object + * @return the mode from 'lv_page_sb.mode_t' enum + */ +lv_sb_mode_t lv_page_get_sb_mode(const lv_obj_t * page); + + +/** + * Get the the scrolling with arrows (LV_GROUP_KEY_LEFT/RIGHT/UP/DOWN) is enabled or not + * @param page pointer to a page object + * @return true: scrolling with arrows is enabled + */ +bool lv_page_get_arrow_scroll(const lv_obj_t * page); + +/** + * Get the scroll propagation property + * @param page pointer to a Page + * @return true or false + */ +bool lv_page_get_scroll_propagation(lv_obj_t * page); + +/** + * Get the edge flash effect property. + * @param page pointer to a Page + * return true or false + */ +bool lv_page_get_edge_flash(lv_obj_t * page); + +/** + * Get that width which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the width which still fits into the page + */ +lv_coord_t lv_page_get_fit_width(lv_obj_t * page); + +/** + * Get that height which can be set to the children to still not cause overflow (show scrollbars) + * @param page pointer to a page object + * @return the height which still fits into the page + */ +lv_coord_t lv_page_get_fit_height(lv_obj_t * page); + +/** + * Get width of the scrollable part of a page + * @param page pointer to a page object + * @return the width of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_width(const lv_obj_t *page) +{ + return lv_obj_get_width(lv_page_get_scrl(page)); +} + +/** + * Get height of the scrollable part of a page + * @param page pointer to a page object + * @return the height of the scrollable + */ +static inline lv_coord_t lv_page_get_scrl_height(const lv_obj_t *page) +{ + return lv_obj_get_height(lv_page_get_scrl(page)); +} + +/** +* Get the layout of the scrollable part of a page +* @param page pointer to page object +* @return the layout from 'lv_cont_layout_t' +*/ +static inline lv_layout_t lv_page_get_scrl_layout(const lv_obj_t * page) +{ + return lv_cont_get_layout(lv_page_get_scrl(page)); +} + +/** +* Get horizontal fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: horizontal fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_hor_fit(const lv_obj_t * page) +{ + return lv_cont_get_hor_fit(lv_page_get_scrl(page)); +} + +/** +* Get vertical fit attribute of the scrollable part of a page +* @param page pointer to a page object +* @return true: vertical fit is enabled; false: disabled +*/ +static inline bool lv_page_get_scrl_fit_ver(const lv_obj_t * page) +{ + return lv_cont_get_ver_fit(lv_page_get_scrl(page)); +} + +/** + * Get a style of a page + * @param page pointer to page object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_page_get_style(const lv_obj_t *page, lv_page_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Glue the object to the page. After it the page can be moved (dragged) with this object too. + * @param obj pointer to an object on a page + * @param glue true: enable glue, false: disable glue + */ +void lv_page_glue_obj(lv_obj_t * obj, bool glue); + +/** + * Focus on an object. It ensures that the object will be visible on the page. + * @param page pointer to a page object + * @param obj pointer to an object to focus (must be on the page) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the page horizontally + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll left; > 0 scroll right) + */ +void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist); + +/** + * Scroll the page vertically + * @param page pointer to a page object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist); + +/** + * Not intended to use directly by the user but by other object types internally. + * Start an edge flash animation. Exactly one `ext->edge_flash.xxx_ip` should be set + * @param page + */ +void lv_page_start_edge_flash(lv_obj_t * page); +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PAGE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PAGE_H*/ diff --git a/include/display/lv_objx/lv_preload.h b/include/display/lv_objx/lv_preload.h new file mode 100644 index 0000000..7e22890 --- /dev/null +++ b/include/display/lv_objx/lv_preload.h @@ -0,0 +1,168 @@ +/** + * @file lv_preload.h + * + */ + +#ifndef LV_PRELOAD_H +#define LV_PRELOAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_PRELOAD != 0 + +/*Testing of dependencies*/ +#if USE_LV_ARC == 0 +#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (USE_LV_ARC 1) " +#endif + +#if USE_LV_ANIMATION == 0 +#error "lv_preload: animations are required. Enable it in lv_conf.h (USE_LV_ANIMATION 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_arc.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, +}; +typedef uint8_t lv_preloader_type_t; + +/*Data of pre loader*/ +typedef struct { + lv_arc_ext_t arc; /*Ext. of ancestor*/ + /*New data for this type */ + uint16_t arc_length; /*Length of the spinning indicator in degree*/ + uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ +} lv_preload_ext_t; + + +/*Styles*/ +enum { + LV_PRELOAD_STYLE_MAIN, +}; +typedef uint8_t lv_preload_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a pre loader objects + * @param par pointer to an object, it will be the parent of the new pre loader + * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from it + * @return pointer to the created pre loader + */ +lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Set the length of the spinning arc in degrees + * @param preload pointer to a preload object + * @param deg length of the arc + */ +void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg); + +/** + * Set the spin time of the arc + * @param preload pointer to a preload object + * @param time time of one round in milliseconds + */ +void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be set + * @param style pointer to a style + * */ +void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); + +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the arc length [degree] of the a pre loader + * @param preload pointer to a pre loader object + */ +uint16_t lv_preload_get_arc_length(const lv_obj_t * preload); + +/** + * Get the spin time of the arc + * @param preload pointer to a pre loader object [milliseconds] + */ +uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); + +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + +/*===================== + * Other functions + *====================*/ + +/** + * Get style of a pre loader. + * @param preload pointer to pre loader object + * @param type which style should be get + * @return style pointer to the style + * */ +void lv_preload_spinner_animation(void * ptr, int32_t val); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_PRELOAD*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_PRELOAD_H*/ diff --git a/include/display/lv_objx/lv_roller.h b/include/display/lv_objx/lv_roller.h new file mode 100644 index 0000000..232f552 --- /dev/null +++ b/include/display/lv_objx/lv_roller.h @@ -0,0 +1,224 @@ +/** + * @file lv_roller.h + * + */ + +#ifndef LV_ROLLER_H +#define LV_ROLLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_ROLLER != 0 + +/*Testing of dependencies*/ +#if USE_LV_DDLIST == 0 +#error "lv_roller: lv_ddlist is required. Enable it in lv_conf.h (USE_LV_DDLIST 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_ddlist.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of roller*/ +typedef struct { + lv_ddlist_ext_t ddlist; /*Ext. of ancestor*/ + /*New data for this type */ +} lv_roller_ext_t; + +enum { + LV_ROLLER_STYLE_BG, + LV_ROLLER_STYLE_SEL, +}; +typedef uint8_t lv_roller_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a roller object + * @param par pointer to an object, it will be the parent of the new roller + * @param copy pointer to a roller object, if not NULL then the new object will be copied from it + * @return pointer to the created roller + */ +lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the align of the roller's options (left, right or center[default]) + * @param roller - pointer to a roller object + * @param align - one of lv_label_align_t values (left, right, center) + */ +void lv_roller_set_align(lv_obj_t * roller, lv_label_align_t align); + +/** + * Set the options on a roller + * @param roller pointer to roller object + * @param options a string with '\n' separated options. E.g. "One\nTwo\nThree" + */ +static inline void lv_roller_set_options(lv_obj_t * roller, const char * options) +{ + lv_ddlist_set_options(roller, options); +} + +/** + * Set the selected option + * @param roller pointer to a roller object + * @param sel_opt id of the selected option (0 ... number of option - 1); + * @param anim_en true: set with animation; false set immediately + */ +void lv_roller_set_selected(lv_obj_t *roller, uint16_t sel_opt, bool anim_en); + +/** + * Set a function to call when a new option is chosen + * @param roller pointer to a roller + * @param action pointer to a callback function + */ +static inline void lv_roller_set_action(lv_obj_t * roller, lv_action_t action) +{ + lv_ddlist_set_action(roller, action); +} + +/** + * Set the height to show the given number of rows (options) + * @param roller pointer to a roller object + * @param row_cnt number of desired visible rows + */ +void lv_roller_set_visible_row_count(lv_obj_t *roller, uint8_t row_cnt); + +/** + * Enable or disable the horizontal fit to the content + * @param roller pointer to a roller + * @param en true: enable auto fit; false: disable auto fit + */ +static inline void lv_roller_set_hor_fit(lv_obj_t * roller, bool en) +{ + lv_ddlist_set_hor_fit(roller, en); +} + +/** + * Set the open/close animation time. + * @param roller pointer to a roller object + * @param anim_time: open/close animation time [ms] + */ +static inline void lv_roller_set_anim_time(lv_obj_t *roller, uint16_t anim_time) +{ + lv_ddlist_set_anim_time(roller, anim_time); +} + +/** + * Set a style of a roller + * @param roller pointer to a roller object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_roller_set_style(lv_obj_t *roller, lv_roller_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the align attribute. Default alignment after _create is LV_LABEL_ALIGN_CENTER + * @param roller pointer to a roller object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_roller_get_align(const lv_obj_t * roller); + +/** + * Get the options of a roller + * @param roller pointer to roller object + * @return the options separated by '\n'-s (E.g. "Option1\nOption2\nOption3") + */ +static inline const char * lv_roller_get_options(const lv_obj_t *roller) +{ + return lv_ddlist_get_options(roller); +} + +/** + * Get the id of the selected option + * @param roller pointer to a roller object + * @return id of the selected option (0 ... number of option - 1); + */ +static inline uint16_t lv_roller_get_selected(const lv_obj_t *roller) +{ + return lv_ddlist_get_selected(roller); +} + +/** + * Get the current selected option as a string + * @param roller pointer to roller object + * @param buf pointer to an array to store the string + */ +static inline void lv_roller_get_selected_str(const lv_obj_t * roller, char * buf) +{ + lv_ddlist_get_selected_str(roller, buf); +} + +/** + * Get the "option selected" callback function + * @param roller pointer to a roller + * @return pointer to the call back function + */ +static inline lv_action_t lv_roller_get_action(const lv_obj_t * roller) +{ + return lv_ddlist_get_action(roller); +} + +/** + * Get the open/close animation time. + * @param roller pointer to a roller + * @return open/close animation time [ms] + */ +static inline uint16_t lv_roller_get_anim_time(const lv_obj_t * roller) +{ + return lv_ddlist_get_anim_time(roller); +} + +/** + * Get the auto width set attribute + * @param roller pointer to a roller object + * @return true: auto size enabled; false: manual width settings enabled + */ +bool lv_roller_get_hor_fit(const lv_obj_t *roller); + +/** + * Get a style of a roller + * @param roller pointer to a roller object + * @param type which style should be get + * @return style pointer to a style + * */ +lv_style_t * lv_roller_get_style(const lv_obj_t *roller, lv_roller_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_ROLLER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_ROLLER_H*/ diff --git a/include/display/lv_objx/lv_slider.h b/include/display/lv_objx/lv_slider.h new file mode 100644 index 0000000..8d0d9d6 --- /dev/null +++ b/include/display/lv_objx/lv_slider.h @@ -0,0 +1,202 @@ +/** + * @file lv_slider.h + * + */ + +#ifndef LV_SLIDER_H +#define LV_SLIDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SLIDER != 0 + +/*Testing of dependencies*/ +#if USE_LV_BAR == 0 +#error "lv_slider: lv_bar is required. Enable it in lv_conf.h (USE_LV_BAR 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_bar.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +/*Data of slider*/ +typedef struct +{ + lv_bar_ext_t bar; /*Ext. of ancestor*/ + /*New data for this type */ + lv_action_t action; /*Function to call when a new value is set*/ + lv_style_t *style_knob; /*Style of the knob*/ + int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/ + uint8_t knob_in :1; /*1: Draw the knob inside the bar*/ +} lv_slider_ext_t; + +/*Built-in styles of slider*/ +enum +{ + LV_SLIDER_STYLE_BG, + LV_SLIDER_STYLE_INDIC, + LV_SLIDER_STYLE_KNOB, +}; +typedef uint8_t lv_slider_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a slider objects + * @param par pointer to an object, it will be the parent of the new slider + * @param copy pointer to a slider object, if not NULL then the new object will be copied from it + * @return pointer to the created slider + */ +lv_obj_t * lv_slider_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new value on the slider + * @param slider pointer to a slider object + * @param value new value + */ +static inline void lv_slider_set_value(lv_obj_t * slider, int16_t value) +{ + lv_bar_set_value(slider, value); +} + +/** + * Set a new value with animation on a slider + * @param slider pointer to a slider object + * @param value new value + * @param anim_time animation time in milliseconds + */ +static inline void lv_slider_set_value_anim(lv_obj_t * slider, int16_t value, uint16_t anim_time) +{ + lv_bar_set_value_anim(slider, value, anim_time); +} + +/** + * Set minimum and the maximum values of a bar + * @param slider pointer to the slider object + * @param min minimum value + * @param max maximum value + */ +static inline void lv_slider_set_range(lv_obj_t *slider, int16_t min, int16_t max) +{ + lv_bar_set_range(slider, min, max); +} + +/** + * Set a function which will be called when a new value is set on the slider + * @param slider pointer to slider object + * @param action a callback function + */ +void lv_slider_set_action(lv_obj_t * slider, lv_action_t action); + +/** + * Set the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @param in true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +void lv_slider_set_knob_in(lv_obj_t * slider, bool in); + +/** + * Set a style of a slider + * @param slider pointer to a slider object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_slider_set_style(lv_obj_t *slider, lv_slider_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a slider + * @param slider pointer to a slider object + * @return the value of the slider + */ +int16_t lv_slider_get_value(const lv_obj_t * slider); + +/** + * Get the minimum value of a slider + * @param slider pointer to a slider object + * @return the minimum value of the slider + */ +static inline int16_t lv_slider_get_min_value(const lv_obj_t * slider) +{ + return lv_bar_get_min_value(slider); +} + +/** + * Get the maximum value of a slider + * @param slider pointer to a slider object + * @return the maximum value of the slider + */ +static inline int16_t lv_slider_get_max_value(const lv_obj_t * slider) +{ + return lv_bar_get_max_value(slider); +} + +/** + * Get the slider action function + * @param slider pointer to slider object + * @return the callback function + */ +lv_action_t lv_slider_get_action(const lv_obj_t * slider); + +/** + * Give the slider is being dragged or not + * @param slider pointer to a slider object + * @return true: drag in progress false: not dragged + */ +bool lv_slider_is_dragged(const lv_obj_t * slider); + +/** + * Get the 'knob in' attribute of a slider + * @param slider pointer to slider object + * @return true: the knob is drawn always in the slider; + * false: the knob can be out on the edges + */ +bool lv_slider_get_knob_in(const lv_obj_t * slider); + + +/** + * Get a style of a slider + * @param slider pointer to a slider object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_slider_get_style(const lv_obj_t *slider, lv_slider_style_t type); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SLIDER*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SLIDER_H*/ diff --git a/include/display/lv_objx/lv_spinbox.h b/include/display/lv_objx/lv_spinbox.h new file mode 100644 index 0000000..6ec1e66 --- /dev/null +++ b/include/display/lv_objx/lv_spinbox.h @@ -0,0 +1,201 @@ +/** + * @file lv_spinbox.h + * + */ + + +#ifndef LV_SPINBOX_H +#define LV_SPINBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SPINBOX != 0 + +/*Testing of dependencies*/ +#if USE_LV_TA == 0 +#error "lv_spinbox: lv_ta is required. Enable it in lv_conf.h (USE_LV_TA 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_ta.h" + +/********************* + * DEFINES + *********************/ +#define LV_SPINBOX_MAX_DIGIT_COUNT 16 + +/********************** + * TYPEDEFS + **********************/ + +/*callback on value change*/ +typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value); + +/*Data of spinbox*/ +typedef struct { + lv_ta_ext_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 digit_padding_left:4; + lv_spinbox_value_changed_cb_t value_changed_cb; +} lv_spinbox_ext_t; + + +/*Styles*/ +enum { + LV_SPINBOX_STYLE_BG, + LV_SPINBOX_STYLE_SB, + LV_SPINBOX_STYLE_CURSOR, +}; +typedef uint8_t lv_spinbox_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a spinbox objects + * @param par pointer to an object, it will be the parent of the new spinbox + * @param copy pointer to a spinbox object, if not NULL then the new object will be copied from it + * @return pointer to the created spinbox + */ +lv_obj_t * lv_spinbox_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a style of a spinbox. + * @param templ pointer to template object + * @param type which style should be set + * @param style pointer to a style + */ +static inline void lv_spinbox_set_style(lv_obj_t * spinbox, lv_spinbox_style_t type, lv_style_t *style) +{ + lv_ta_set_style(spinbox, type, style); +} + +/** + * Set spinbox value + * @param spinbox pointer to spinbox + * @param i value to be set + */ +void lv_spinbox_set_value(lv_obj_t * spinbox, int32_t i); + +/** + * Set spinbox digit format (digit count and decimal format) + * @param spinbox 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 * spinbox, uint8_t digit_count, uint8_t separator_position); + +/** + * Set spinbox step + * @param spinbox pointer to spinbox + * @param step steps on increment/decrement + */ +void lv_spinbox_set_step(lv_obj_t * spinbox, uint32_t step); + +/** + * Set spinbox value range + * @param spinbox pointer to spinbox + * @param range_min maximum value, inclusive + * @param range_max minimum value, inclusive + */ +void lv_spinbox_set_range(lv_obj_t * spinbox, int32_t range_min, int32_t range_max); + +/** + * Set spinbox callback on calue change + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_value_changed_cb(lv_obj_t * spinbox, lv_spinbox_value_changed_cb_t cb); + +/** + * Set spinbox left padding in digits count (added between sign and first digit) + * @param spinbox pointer to spinbox + * @param cb Callback function called on value change event + */ +void lv_spinbox_set_padding_left(lv_obj_t * spinbox, uint8_t padding); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get style of a spinbox. + * @param templ pointer to template object + * @param type which style should be get + * @return style pointer to the style + */ +static inline lv_style_t * lv_spinbox_get_style(lv_obj_t * spinbox, lv_spinbox_style_t type) +{ + return lv_ta_get_style(spinbox, type); +} + +/** + * Get the spinbox numeral value (user has to convert to float according to its digit format) + * @param spinbox pointer to spinbox + * @return value integer value of the spinbox + */ +int32_t lv_spinbox_get_value(lv_obj_t * spinbox); + +/*===================== + * Other functions + *====================*/ + +/** + * Select next lower digit for edition by dividing the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_next(lv_obj_t * spinbox); + +/** + * Select next higher digit for edition by multiplying the step by 10 + * @param spinbox pointer to spinbox + */ +void lv_spinbox_step_previous(lv_obj_t * spinbox); + +/** + * Increment spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_increment(lv_obj_t * spinbox); + +/** + * Decrement spinbox value by one step + * @param spinbox pointer to spinbox + */ +void lv_spinbox_decrement(lv_obj_t * spinbox); + + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SPINBOX*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SPINBOX_H*/ diff --git a/include/display/lv_objx/lv_sw.h b/include/display/lv_objx/lv_sw.h new file mode 100644 index 0000000..7f4513c --- /dev/null +++ b/include/display/lv_objx/lv_sw.h @@ -0,0 +1,194 @@ +/** + * @file lv_sw.h + * + */ + +#ifndef LV_SW_H +#define LV_SW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_SW != 0 + +/*Testing of dependencies*/ +#if USE_LV_SLIDER == 0 +#error "lv_sw: lv_slider is required. Enable it in lv_conf.h (USE_LV_SLIDER 1)" +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_slider.h" + +/********************* + * DEFINES + *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 + +/********************** + * TYPEDEFS + **********************/ +/*Data of switch*/ +typedef struct +{ + lv_slider_ext_t slider; /*Ext. of ancestor*/ + /*New data for this type */ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; +#if USE_LV_ANIMATION + uint16_t anim_time; /*switch animation time */ +#endif +} lv_sw_ext_t; + +enum { + LV_SW_STYLE_BG, + LV_SW_STYLE_INDIC, + LV_SW_STYLE_KNOB_OFF, + LV_SW_STYLE_KNOB_ON, +}; +typedef uint8_t lv_sw_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a switch objects + * @param par pointer to an object, it will be the parent of the new switch + * @param copy pointer to a switch object, if not NULL then the new object will be copied from it + * @return pointer to the created switch + */ +lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Turn ON the switch + * @param sw pointer to a switch object + */ +void lv_sw_on(lv_obj_t *sw); + +/** + * Turn OFF the switch + * @param sw pointer to a switch object + */ +void lv_sw_off(lv_obj_t *sw); + +/** + * Toggle the position of the switch + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle(lv_obj_t *sw); + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + +/** + * Toggle the position of the switch with an animation + * @param sw pointer to a switch object + * @return resulting state of the switch. + */ +bool lv_sw_toggle_anim(lv_obj_t *sw); + +/** + * Set a function which will be called when the switch is toggled by the user + * @param sw pointer to switch object + * @param action a callback function + */ +static inline void lv_sw_set_action(lv_obj_t * sw, lv_action_t action) +{ + lv_slider_set_action(sw, action); +} + +/** + * Set a style of a switch + * @param sw pointer to a switch object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_sw_set_style(lv_obj_t *sw, lv_sw_style_t type, lv_style_t *style); + +#if USE_LV_ANIMATION +/** + * Set the animation time of the switch + * @param sw pointer to a switch object + * @param anim_time animation time + * @return style pointer to a style + */ +void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); +#endif + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the state of a switch + * @param sw pointer to a switch object + * @return false: OFF; true: ON + */ +static inline bool lv_sw_get_state(const lv_obj_t *sw) +{ + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; +} + +/** + * Get the switch action function + * @param slider pointer to a switch object + * @return the callback function + */ +static inline lv_action_t lv_sw_get_action(const lv_obj_t * slider) +{ + return lv_slider_get_action(slider); +} + +/** + * Get a style of a switch + * @param sw pointer to a switch object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_sw_get_style(const lv_obj_t *sw, lv_sw_style_t type); + +/** + * Get the animation time of the switch + * @param sw pointer to a switch object + * @return style pointer to a style + */ +uint16_t lv_sw_get_anim_time(const lv_obj_t *sw); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_SW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_SW_H*/ diff --git a/include/display/lv_objx/lv_ta.h b/include/display/lv_objx/lv_ta.h new file mode 100644 index 0000000..8e12314 --- /dev/null +++ b/include/display/lv_objx/lv_ta.h @@ -0,0 +1,390 @@ +/** + * @file lv_ta.h + * + */ + +#ifndef LV_TA_H +#define LV_TA_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TA != 0 + +/*Testing of dependencies*/ +#if USE_LV_PAGE == 0 +#error "lv_ta: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_ta: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_page.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ + +/********************** + * TYPEDEFS + **********************/ + +enum { + LV_CURSOR_NONE, + LV_CURSOR_LINE, + LV_CURSOR_BLOCK, + LV_CURSOR_OUTLINE, + LV_CURSOR_UNDERLINE, + LV_CURSOR_HIDDEN = 0x08, /*Or it to any value to hide the cursor temporally*/ +}; +typedef uint8_t lv_cursor_type_t; + +/*Data of text area*/ +typedef struct +{ + lv_page_ext_t page; /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * label; /*Label of the text area*/ + char * pwd_tmp; /*Used to store the original text in password mode*/ + const char * accapted_chars;/*Only these characters will be accepted. NULL: accept all*/ + uint16_t max_length; /*The max. number of characters. 0: no limit*/ + uint8_t pwd_mode :1; /*Replace characters with '*' */ + uint8_t one_line :1; /*One line mode (ignore line breaks)*/ + struct { + lv_style_t *style; /*Style of the cursor (NULL to use label's style)*/ + lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter line. (Handled by the library)*/ + uint16_t pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/ + lv_area_t area; /*Cursor area relative to the Text Area*/ + uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/ + lv_cursor_type_t type:4; /*Shape of the cursor*/ + uint8_t state :1; /*Indicates that the cursor is visible now or not (Handled by the library)*/ + } cursor; +} lv_ta_ext_t; + +enum { + LV_TA_STYLE_BG, + LV_TA_STYLE_SB, + LV_TA_STYLE_EDGE_FLASH, + LV_TA_STYLE_CURSOR, +}; +typedef uint8_t lv_ta_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a text area objects + * @param par pointer to an object, it will be the parent of the new text area + * @param copy pointer to a text area object, if not NULL then the new object will be copied from it + * @return pointer to the created text area + */ +lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy); + + +/*====================== + * 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 ta pointer to a text area object + * @param c a character (e.g. 'a') + */ +void lv_ta_add_char(lv_obj_t * ta, uint32_t c); + +/** + * Insert a text to the current cursor position + * @param ta pointer to a text area object + * @param txt a '\0' terminated string to insert + */ +void lv_ta_add_text(lv_obj_t * ta, const char * txt); + +/** + * Delete a the left character from the current cursor position + * @param ta pointer to a text area object + */ +void lv_ta_del_char(lv_obj_t * ta); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the text of a text area + * @param ta pointer to a text area + * @param txt pointer to the text + */ +void lv_ta_set_text(lv_obj_t * ta, 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_TA_CURSOR_LAST: go after the last character + */ +void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos); + +/** + * Set the cursor type. + * @param ta pointer to a text area object + * @param cur_type: element of 'lv_cursor_type_t' + */ +void lv_ta_set_cursor_type(lv_obj_t * ta, lv_cursor_type_t cur_type); + +/** + * Enable/Disable password mode + * @param ta pointer to a text area object + * @param en true: enable, false: disable + */ +void lv_ta_set_pwd_mode(lv_obj_t * ta, bool en); + +/** + * Configure the text area to one line or back to normal + * @param ta pointer to a Text area object + * @param en true: one line, false: normal + */ +void lv_ta_set_one_line(lv_obj_t * ta, bool en); + +/** + * Set the alignment of the text area. + * In one line mode the text can be scrolled only with `LV_LABEL_ALIGN_LEFT`. + * This function should be called if the size of text area changes. + * @param ta pointer to a text are object + * @param align the desired alignment from `lv_label_align_t`. (LV_LABEL_ALIGN_LEFT/CENTER/RIGHT) + */ +void lv_ta_set_text_align(lv_obj_t * ta, lv_label_align_t align); + +/** + * Set a list of characters. Only these characters will be accepted by the text area + * @param ta pointer to Text Area + * @param list list of characters. Only the pointer is saved. E.g. "+-.,0123456789" + */ +void lv_ta_set_accepted_chars(lv_obj_t * ta, const char * list); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @param num the maximal number of characters can be added (`lv_ta_set_text` ignores it) + */ +void lv_ta_set_max_length(lv_obj_t * ta, uint16_t num); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline void lv_ta_set_action(lv_obj_t * ta, lv_action_t action) +{ + lv_page_set_rel_action(ta, action); +} + +/** + * Set the scroll bar mode of a text area + * @param ta pointer to a text area object + * @param sb_mode the new mode from 'lv_page_sb_mode_t' enum + */ +static inline void lv_ta_set_sb_mode(lv_obj_t * ta, lv_sb_mode_t mode) +{ + lv_page_set_sb_mode(ta, mode); +} + +/** + * Enable the scroll propagation feature. If enabled then the Text area will move its parent if there is no more space to scroll. + * @param ta pointer to a Text area + * @param en true or false to enable/disable scroll propagation + */ +static inline void lv_ta_set_scroll_propagation(lv_obj_t * ta, bool en) +{ + lv_page_set_scroll_propagation(ta, en); +} + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param page pointer to a Text Area + * @param en true or false to enable/disable end flash + */ +static inline void lv_ta_set_edge_flash(lv_obj_t * ta, bool en) +{ + lv_page_set_edge_flash(ta, en); +} + +/** + * Set a style of a text area + * @param ta pointer to a text area object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_ta_set_style(lv_obj_t *ta, lv_ta_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the text of a text area. In password mode it gives the real text (not '*'s). + * @param ta pointer to a text area object + * @return pointer to the text + */ +const char * lv_ta_get_text(const lv_obj_t * ta); + +/** + * Get the label of a text area + * @param ta pointer to a text area object + * @return pointer to the label object + */ +lv_obj_t * lv_ta_get_label(const lv_obj_t * ta); + +/** + * Get the current cursor position in character index + * @param ta pointer to a text area object + * @return the cursor position + */ +uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta); + +/** + * Get the current cursor visibility. + * @param ta pointer to a text area object + * @return true: the cursor is drawn, false: the cursor is hidden + */ +//bool lv_ta_get_cursor_show(const lv_obj_t * ta); + +/** + * Get the current cursor type. + * @param ta pointer to a text area object + * @return element of 'lv_cursor_type_t' + */ +lv_cursor_type_t lv_ta_get_cursor_type(const lv_obj_t * ta); + +/** + * Get the password mode attribute + * @param ta pointer to a text area object + * @return true: password mode is enabled, false: disabled + */ +bool lv_ta_get_pwd_mode(const lv_obj_t * ta); + +/** + * Get the one line configuration attribute + * @param ta pointer to a text area object + * @return true: one line configuration is enabled, false: disabled + */ +bool lv_ta_get_one_line(const lv_obj_t * ta); + +/** + * Get a list of accepted characters. + * @param ta pointer to Text Area + * @return list of accented characters. + */ +const char * lv_ta_get_accepted_chars(lv_obj_t * ta); + +/** + * Set max length of a Text Area. + * @param ta pointer to Text Area + * @return the maximal number of characters to be add + */ +uint16_t lv_ta_get_max_length(lv_obj_t * ta); + +/** + * Set an action to call when the Text area is clicked + * @param ta pointer to a Text area + * @param action a function pointer + */ +static inline lv_action_t lv_ta_get_action(lv_obj_t * ta) +{ + return lv_page_get_rel_action(ta); +} + +/** + * Get the scroll bar mode of a text area + * @param ta pointer to a text area object + * @return scrollbar mode from 'lv_page_sb_mode_t' enum + */ +static inline lv_sb_mode_t lv_ta_get_sb_mode(const lv_obj_t * ta) +{ + return lv_page_get_sb_mode(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_scroll_propagation(lv_obj_t * ta) +{ + return lv_page_get_scroll_propagation(ta); +} + +/** + * Get the scroll propagation property + * @param ta pointer to a Text area + * @return true or false + */ +static inline bool lv_ta_get_edge_flash(lv_obj_t * ta) +{ + return lv_page_get_edge_flash(ta); +} + +/** + * Get a style of a text area + * @param ta pointer to a text area object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_ta_get_style(const lv_obj_t *ta, lv_ta_style_t type); + +/*===================== + * Other functions + *====================*/ + +/** + * Move the cursor one character right + * @param ta pointer to a text area object + */ +void lv_ta_cursor_right(lv_obj_t * ta); + +/** + * Move the cursor one character left + * @param ta pointer to a text area object + */ +void lv_ta_cursor_left(lv_obj_t * ta); + +/** + * Move the cursor one line down + * @param ta pointer to a text area object + */ +void lv_ta_cursor_down(lv_obj_t * ta); + +/** + * Move the cursor one line up + * @param ta pointer to a text area object + */ +void lv_ta_cursor_up(lv_obj_t * ta); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TA_H*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TA_H*/ diff --git a/include/display/lv_objx/lv_table.h b/include/display/lv_objx/lv_table.h new file mode 100644 index 0000000..79ba22d --- /dev/null +++ b/include/display/lv_objx/lv_table.h @@ -0,0 +1,261 @@ +/** + * @file lv_table.h + * + */ + +#ifndef LV_TABLE_H +#define LV_TABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABLE != 0 + +/*Testing of dependencies*/ +#if USE_LV_LABEL == 0 +#error "lv_table: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_label.h" + +/********************* + * DEFINES + *********************/ +#ifndef LV_TABLE_COL_MAX +#define LV_TABLE_COL_MAX 12 +#endif + +#define LV_TABLE_CELL_STYLE_CNT 4 +/********************** + * TYPEDEFS + **********************/ + +typedef union { + struct { + uint8_t align:2; + uint8_t right_merge:1; + uint8_t type:2; + uint8_t crop:1; + }; + uint8_t format_byte; +}lv_table_cell_format_t; + +/*Data of table*/ +typedef struct { + /*New data for this type */ + uint16_t col_cnt; + uint16_t row_cnt; + char ** cell_data; + lv_style_t * cell_style[LV_TABLE_CELL_STYLE_CNT]; + lv_coord_t col_w[LV_TABLE_COL_MAX]; +} lv_table_ext_t; + + +/*Styles*/ +enum { + LV_TABLE_STYLE_BG, + LV_TABLE_STYLE_CELL1, + LV_TABLE_STYLE_CELL2, + LV_TABLE_STYLE_CELL3, + LV_TABLE_STYLE_CELL4, +}; +typedef uint8_t lv_table_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a table object + * @param par pointer to an object, it will be the parent of the new table + * @param copy pointer to a table object, if not NULL then the new object will be copied from it + * @return pointer to the created table + */ +lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set the value of a cell. + * @param table 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. + */ +void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); + +/** + * Set the number of rows + * @param table table pointer to a Table object + * @param row_cnt number of rows + */ +void lv_table_set_row_cnt(lv_obj_t * table, uint16_t row_cnt); + +/** + * Set the number of columns + * @param table table pointer to a Table object + * @param col_cnt number of columns. Must be < LV_TABLE_COL_MAX + */ +void lv_table_set_col_cnt(lv_obj_t * table, uint16_t col_cnt); + +/** + * Set the width of a column + * @param table 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 * table, uint16_t col_id, lv_coord_t w); + +/** + * Set the text align in a cell + * @param table 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 align LV_LABEL_ALIGN_LEFT or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +void lv_table_set_cell_align(lv_obj_t * table, uint16_t row, uint16_t col, lv_label_align_t align); + +/** + * Set the type of a cell. + * @param table 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 type 1,2,3 or 4. The cell style will be chosen accordingly. + */ +void lv_table_set_cell_type(lv_obj_t * table, uint16_t row, uint16_t col, uint8_t type); + +/** + * Set the cell crop. (Don't adjust the height of the cell according to its content) + * @param table 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 crop true: crop the cell content; false: set the cell height to the content. + */ +void lv_table_set_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col, bool crop); + +/** + * Merge a cell with the right neighbor. The value of the cell to the right won't be displayed. + * @param table table 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 en true: merge right; false: don't merge right + */ +void lv_table_set_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col, bool en); + +/** + * Set a style of a table. + * @param table pointer to table object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_table_set_style(lv_obj_t * table, lv_table_style_t type, lv_style_t * style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the value of a cell. + * @param table 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 * table, uint16_t row, uint16_t col); + +/** + * Get the number of rows. + * @param table table pointer to a Table object + * @return number of rows. + */ +uint16_t lv_table_get_row_cnt(lv_obj_t * table); + +/** + * Get the number of columns. + * @param table table pointer to a Table object + * @return number of columns. + */ +uint16_t lv_table_get_col_cnt(lv_obj_t * table); + +/** + * Get the width of a column + * @param table table pointer to a Table object + * @param col_id 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 * table, uint16_t col_id); + +/** + * Get the text align of a cell + * @param table 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 LV_LABEL_ALIGN_LEFT (default in case of error) or LV_LABEL_ALIGN_CENTER or LV_LABEL_ALIGN_RIGHT + */ +lv_label_align_t lv_table_get_cell_align(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the type of a cell + * @param table 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 1,2,3 or 4 + */ +lv_label_align_t lv_table_get_cell_type(lv_obj_t * table, uint16_t row, uint16_t col); + + +/** + * Get the crop property of a cell + * @param table 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 true: text crop enabled; false: disabled + */ +lv_label_align_t lv_table_get_cell_crop(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get the cell merge attribute. + * @param table table 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 true: merge right; false: don't merge right + */ +bool lv_table_get_cell_merge_right(lv_obj_t * table, uint16_t row, uint16_t col); + +/** + * Get style of a table. + * @param table pointer to table object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_table_get_style(const lv_obj_t * table, lv_table_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABLE*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABLE_H*/ diff --git a/include/display/lv_objx/lv_tabview.h b/include/display/lv_objx/lv_tabview.h new file mode 100644 index 0000000..73d8b17 --- /dev/null +++ b/include/display/lv_objx/lv_tabview.h @@ -0,0 +1,252 @@ +/** + * @file lv_tabview.h + * + */ + +#ifndef LV_TABVIEW_H +#define LV_TABVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TABVIEW != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTNM == 0 +#error "lv_tabview: lv_btnm is required. Enable it in lv_conf.h (USE_LV_BTNM 1) " +#endif + +#if USE_LV_PAGE == 0 +#error "lv_tabview: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "display/lv_objx/lv_win.h" +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/* parametes: pointer to a tabview object, tab_id + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tabview_action_t)(lv_obj_t *, uint16_t); + + +enum { + LV_TABVIEW_BTNS_POS_TOP, + LV_TABVIEW_BTNS_POS_BOTTOM, +}; +typedef uint8_t lv_tabview_btns_pos_t; + +/*Data of tab*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * btns; + lv_obj_t * indic; + lv_obj_t * content; /*A rectangle to show the current tab*/ + const char ** tab_name_ptr; + lv_point_t point_last; + uint16_t tab_cur; + uint16_t tab_cnt; + uint16_t anim_time; + uint8_t slide_enable :1; /*1: enable horizontal sliding by touch pad*/ + uint8_t draging :1; + uint8_t drag_hor :1; + uint8_t btns_hide :1; + lv_tabview_btns_pos_t btns_pos :1; + lv_tabview_action_t tab_load_action; +} lv_tabview_ext_t; + +enum { + LV_TABVIEW_STYLE_BG, + LV_TABVIEW_STYLE_INDIC, + LV_TABVIEW_STYLE_BTN_BG, + LV_TABVIEW_STYLE_BTN_REL, + LV_TABVIEW_STYLE_BTN_PR, + LV_TABVIEW_STYLE_BTN_TGL_REL, + LV_TABVIEW_STYLE_BTN_TGL_PR, +}; +typedef uint8_t lv_tabview_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + + +/** + * Create a Tab view object + * @param par pointer to an object, it will be the parent of the new tab + * @param copy pointer to a tab object, if not NULL then the new object will be copied from it + * @return pointer to the created tab + */ +lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_tabview_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add a new tab with the given name + * @param tabview pointer to Tab view object where to ass the new tab + * @param name the text on the tab button + * @return pointer to the created page object (lv_page). You can create your content here + */ +lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name); + +/*===================== + * Setter functions + *====================*/ + +/** + * Set a new tab + * @param tabview pointer to Tab view object + * @param id index of a tab to load + * @param anim_en true: set with sliding animation; false: set immediately + */ +void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en); + +/** + * Set an action to call when a tab is loaded (Good to create content only if required) + * lv_tabview_get_act() still gives the current (old) tab (to remove content from here) + * @param tabview pointer to a tabview object + * @param action pointer to a function to call when a tab is loaded + */ +void lv_tabview_set_tab_load_action(lv_obj_t *tabview, lv_tabview_action_t action); + +/** + * Enable horizontal sliding with touch pad + * @param tabview pointer to Tab view object + * @param en true: enable sliding; false: disable sliding + */ +void lv_tabview_set_sliding(lv_obj_t * tabview, bool en); + +/** + * Set the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @param anim_time time of animation in milliseconds + */ +void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time); + +/** + * Set the style of a tab view + * @param tabview pointer to a tan view object + * @param type which style should be set + * @param style pointer to the new style + */ +void lv_tabview_set_style(lv_obj_t *tabview, lv_tabview_style_t type, lv_style_t *style); + +/** + * Set the position of tab select buttons + * @param tabview pointer to a tab view object + * @param btns_pos which button position + */ +void lv_tabview_set_btns_pos(lv_obj_t *tabview, lv_tabview_btns_pos_t btns_pos); + +/** + * Set whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @param en whether tab buttons are hidden + */ +void lv_tabview_set_btns_hidden(lv_obj_t *tabview, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the index of the currently active tab + * @param tabview pointer to Tab view object + * @return the active tab index + */ +uint16_t lv_tabview_get_tab_act(const lv_obj_t * tabview); + +/** + * Get the number of tabs + * @param tabview pointer to Tab view object + * @return tab count + */ +uint16_t lv_tabview_get_tab_count(const lv_obj_t * tabview); +/** + * Get the page (content area) of a tab + * @param tabview pointer to Tab view object + * @param id index of the tab (>= 0) + * @return pointer to page (lv_page) object + */ +lv_obj_t * lv_tabview_get_tab(const lv_obj_t * tabview, uint16_t id); + +/** + * Get the tab load action + * @param tabview pointer to a tabview object + * @param return the current tab load action + */ +lv_tabview_action_t lv_tabview_get_tab_load_action(const lv_obj_t *tabview); + +/** + * Get horizontal sliding is enabled or not + * @param tabview pointer to Tab view object + * @return true: enable sliding; false: disable sliding + */ +bool lv_tabview_get_sliding(const lv_obj_t * tabview); + +/** + * Get the animation time of tab view when a new tab is loaded + * @param tabview pointer to Tab view object + * @return time of animation in milliseconds + */ +uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview); + +/** + * Get a style of a tab view + * @param tabview pointer to a ab view object + * @param type which style should be get + * @return style pointer to a style + */ +lv_style_t * lv_tabview_get_style(const lv_obj_t *tabview, lv_tabview_style_t type); + +/** + * Get position of tab select buttons + * @param tabview pointer to a ab view object + */ +lv_tabview_btns_pos_t lv_tabview_get_btns_pos(const lv_obj_t *tabview); + +/** + * Get whether tab buttons are hidden + * @param tabview pointer to a tab view object + * @return whether tab buttons are hidden + */ +bool lv_tabview_get_btns_hidden(const lv_obj_t *tabview); + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TABVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TABVIEW_H*/ diff --git a/include/display/lv_objx/lv_tileview.h b/include/display/lv_objx/lv_tileview.h new file mode 100644 index 0000000..b869e7c --- /dev/null +++ b/include/display/lv_objx/lv_tileview.h @@ -0,0 +1,163 @@ +/** + * @file lv_tileview.h + * + */ + + +#ifndef LV_TILEVIEW_H +#define LV_TILEVIEW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_TILEVIEW != 0 + +#include "display/lv_objx/lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + + + +/* parametes: pointer to a tileview object, x, y (tile coordinates to load) + * return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/ +typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t); + +/*Data of tileview*/ +typedef struct { + lv_page_ext_t page; + /*New data for this type */ + const lv_point_t * valid_pos; + uint16_t anim_time; + lv_tileview_action_t action; + lv_point_t act_id; + uint8_t drag_top_en :1; + uint8_t drag_bottom_en :1; + uint8_t drag_left_en :1; + uint8_t drag_right_en :1; + uint8_t drag_hor :1; + uint8_t drag_ver :1; +} lv_tileview_ext_t; + + +/*Styles*/ +enum { + LV_TILEVIEW_STYLE_BG, +}; +typedef uint8_t lv_tileview_style_t; + + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a tileview objects + * @param par pointer to an object, it will be the parent of the new tileview + * @param copy pointer to a tileview object, if not NULL then the new object will be copied from it + * @return pointer to the created tileview + */ +lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Register an object on the tileview. The register object will able to slide the tileview + * @param element pointer to an object + */ +void lv_tileview_add_element(lv_obj_t * element); + +/*===================== + * Setter functions + *====================*/ + + +/** + * Set the valid position's indices. The scrolling will be possible only to these positions. + * @param tileview pointer to a Tileview object + * @param valid_pos array width the indices. E.g. `lv_point_t p[] = {{0,0}, {1,0}, {1,1}, {LV_COORD_MIN, LV_COORD_MIN}};` + * Must be closed with `{LV_COORD_MIN, LV_COORD_MIN}`. Only the pointer is saved so can't be a local variable. + */ +void lv_tileview_set_valid_positions(lv_obj_t * tileview, const lv_point_t * valid_pos); + +/** + * Set the tile to be shown + * @param tileview pointer to a tileview object + * @param x column id (0, 1, 2...) + * @param y line id (0, 1, 2...) + * @param anim_en true: move with animation + */ +void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, bool anim_en); + +/** + * Enable the edge flash effect. (Show an arc when the an edge is reached) + * @param tileview pointer to a Tileview + * @param en true or false to enable/disable end flash + */ +static inline void lv_tileview_set_edge_flash(lv_obj_t * tileview, bool en) +{ + lv_page_set_edge_flash(tileview, en); +} + +/** + * Set a style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_tileview_set_style(lv_obj_t * tileview, lv_tileview_style_t type, lv_style_t *style); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the scroll propagation property + * @param tileview pointer to a Tileview + * @return true or false + */ +static inline bool lv_tileview_get_edge_flash(lv_obj_t * tileview) +{ + return lv_page_get_edge_flash(tileview); +} + +/** + * Get style of a tileview. + * @param tileview pointer to tileview object + * @param type which style should be get + * @return style pointer to the style + */ +lv_style_t * lv_tileview_get_style(const lv_obj_t * tileview, lv_tileview_style_t type); + +/*===================== + * Other functions + *====================*/ + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_TILEVIEW*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_TILEVIEW_H*/ diff --git a/include/display/lv_objx/lv_win.h b/include/display/lv_objx/lv_win.h new file mode 100644 index 0000000..4a64aa8 --- /dev/null +++ b/include/display/lv_objx/lv_win.h @@ -0,0 +1,282 @@ +/** + * @file lv_win.h + * + */ + +#ifndef LV_WIN_H +#define LV_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_WIN != 0 + +/*Testing of dependencies*/ +#if USE_LV_BTN == 0 +#error "lv_win: lv_btn is required. Enable it in lv_conf.h (USE_LV_BTN 1) " +#endif + +#if USE_LV_LABEL == 0 +#error "lv_win: lv_label is required. Enable it in lv_conf.h (USE_LV_LABEL 1) " +#endif + +#if USE_LV_IMG == 0 +#error "lv_win: lv_img is required. Enable it in lv_conf.h (USE_LV_IMG 1) " +#endif + + +#if USE_LV_PAGE == 0 +#error "lv_win: lv_page is required. Enable it in lv_conf.h (USE_LV_PAGE 1) " +#endif + +#include "display/lv_core/lv_obj.h" +#include "lv_cont.h" +#include "lv_btn.h" +#include "lv_label.h" +#include "lv_img.h" +#include "lv_page.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/*Data of window*/ +typedef struct +{ + /*Ext. of ancestor*/ + /*New data for this type */ + lv_obj_t * page; /*Pointer to a page which holds the content*/ + lv_obj_t * header; /*Pointer to the header container of the window*/ + lv_obj_t * title; /*Pointer to the title label of the window*/ + lv_style_t * style_header; /*Style of the header container*/ + lv_style_t * style_btn_rel; /*Control button releases style*/ + lv_style_t * style_btn_pr; /*Control button pressed style*/ + lv_coord_t btn_size; /*Size of the control buttons (square)*/ +} lv_win_ext_t; + +enum { + LV_WIN_STYLE_BG, + LV_WIN_STYLE_CONTENT_BG, + LV_WIN_STYLE_CONTENT_SCRL, + LV_WIN_STYLE_SB, + LV_WIN_STYLE_HEADER, + LV_WIN_STYLE_BTN_REL, + LV_WIN_STYLE_BTN_PR, +}; +typedef uint8_t lv_win_style_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a window objects + * @param par pointer to an object, it will be the parent of the new window + * @param copy pointer to a window object, if not NULL then the new object will be copied from it + * @return pointer to the created window + */ +lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy); + +/** + * Delete all children of the scrl object, without deleting scrl child. + * @param obj pointer to an object + */ +void lv_win_clean(lv_obj_t *obj); + +/*====================== + * Add/remove functions + *=====================*/ + +/** + * Add control button to the header of the window + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param rel_action a function pointer to call when the button is released + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src, lv_action_t rel_action); + +/*===================== + * Setter functions + *====================*/ + +/** + * A release action which can be assigned to a window control button to close it + * @param btn pointer to the released button + * @return always LV_ACTION_RES_INV because the button is deleted with the window + */ +lv_res_t lv_win_close_action(lv_obj_t * btn); + +/** + * Set the title of a window + * @param win pointer to a window object + * @param title string of the new title + */ +void lv_win_set_title(lv_obj_t * win, const char * title); + +/** + * Set the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +void lv_win_set_btn_size(lv_obj_t * win, lv_coord_t size); + +/** + * Set the layout of the window + * @param win pointer to a window object + * @param layout the layout from 'lv_layout_t' + */ +void lv_win_set_layout(lv_obj_t *win, lv_layout_t layout); + +/** + * Set the scroll bar mode of a window + * @param win pointer to a window object + * @param sb_mode the new scroll bar mode from 'lv_sb_mode_t' + */ +void lv_win_set_sb_mode(lv_obj_t *win, lv_sb_mode_t sb_mode); + +/** + * Set a style of a window + * @param win pointer to a window object + * @param type which style should be set + * @param style pointer to a style + */ +void lv_win_set_style(lv_obj_t *win, lv_win_style_t type, lv_style_t *style); + +/** + * Set drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @param en whether dragging is enabled + */ +void lv_win_set_drag(lv_obj_t *win, bool en); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the title of a window + * @param win pointer to a window object + * @return title string of the window + */ +const char * lv_win_get_title(const lv_obj_t * win); + +/** +* Get the content holder object of window (`lv_page`) to allow additional customization +* @param win pointer to a window object +* @return the Page object where the window's content is +*/ +lv_obj_t * lv_win_get_content(const lv_obj_t * win); + +/** + * Get the control button size of a window + * @param win pointer to a window object + * @return control button size + */ +lv_coord_t lv_win_get_btn_size(const lv_obj_t * win); + +/** + * Get the pointer of a widow from one of its control button. + * It is useful in the action of the control buttons where only button is known. + * @param ctrl_btn pointer to a control button of a window + * @return pointer to the window of 'ctrl_btn' + */ +lv_obj_t * lv_win_get_from_btn(const lv_obj_t * ctrl_btn); + +/** + * Get the layout of a window + * @param win pointer to a window object + * @return the layout of the window (from 'lv_layout_t') + */ +lv_layout_t lv_win_get_layout(lv_obj_t *win); + +/** + * Get the scroll bar mode of a window + * @param win pointer to a window object + * @return the scroll bar mode of the window (from 'lv_sb_mode_t') + */ +lv_sb_mode_t lv_win_get_sb_mode(lv_obj_t *win); + +/** + * Get width of the content area (page scrollable) of the window + * @param win pointer to a window object + * @return the width of the content area + */ +lv_coord_t lv_win_get_width(lv_obj_t * win); + +/** + * Get a style of a window + * @param win pointer to a button object + * @param type which style window be get + * @return style pointer to a style + */ +lv_style_t * lv_win_get_style(const lv_obj_t *win, lv_win_style_t type); + +/** + * Get drag status of a window. If set to 'true' window can be dragged like on a PC. + * @param win pointer to a window object + * @return whether window is draggable + */ +static inline bool lv_win_get_drag(const lv_obj_t *win) +{ + return lv_obj_get_drag(win); +} + +/*===================== + * Other functions + *====================*/ + +/** + * Focus on an object. It ensures that the object will be visible in the window. + * @param win pointer to a window object + * @param obj pointer to an object to focus (must be in the window) + * @param anim_time scroll animation time in milliseconds (0: no animation) + */ +void lv_win_focus(lv_obj_t * win, lv_obj_t * obj, uint16_t anim_time); + +/** + * Scroll the window horizontally + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll right; > 0 scroll left) + */ +static inline void lv_win_scroll_hor(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_hor(ext->page, dist); +} +/** + * Scroll the window vertically + * @param win pointer to a window object + * @param dist the distance to scroll (< 0: scroll down; > 0 scroll up) + */ +static inline void lv_win_scroll_ver(lv_obj_t * win, lv_coord_t dist) +{ + lv_win_ext_t * ext = (lv_win_ext_t *)lv_obj_get_ext_attr(win); + lv_page_scroll_ver(ext->page, dist); +} + +/********************** + * MACROS + **********************/ + +#endif /*USE_LV_WIN*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_WIN_H*/ diff --git a/include/display/lv_themes/lv_theme.h b/include/display/lv_themes/lv_theme.h new file mode 100644 index 0000000..69aae29 --- /dev/null +++ b/include/display/lv_themes/lv_theme.h @@ -0,0 +1,332 @@ +/** + *@file lv_themes.h + * + */ + +#ifndef LV_THEMES_H +#define LV_THEMES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#include "display/lv_core/lv_style.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + lv_style_t *bg; + lv_style_t *panel; + +#if USE_LV_CONT != 0 + lv_style_t *cont; +#endif + +#if USE_LV_BTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; +#endif + + +#if USE_LV_IMGBTN != 0 + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } imgbtn; +#endif + +#if USE_LV_LABEL != 0 + struct { + lv_style_t *prim; + lv_style_t *sec; + lv_style_t *hint; + } label; +#endif + +#if USE_LV_IMG != 0 + struct { + lv_style_t *light; + lv_style_t *dark; + } img; +#endif + +#if USE_LV_LINE != 0 + struct { + lv_style_t *decor; + } line; +#endif + +#if USE_LV_LED != 0 + lv_style_t *led; +#endif + +#if USE_LV_BAR != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + } bar; +#endif + +#if USE_LV_SLIDER != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob; + } slider; +#endif + +#if USE_LV_LMETER != 0 + lv_style_t *lmeter; +#endif + +#if USE_LV_GAUGE != 0 + lv_style_t *gauge; +#endif + +#if USE_LV_ARC != 0 + lv_style_t *arc; +#endif + +#if USE_LV_PRELOAD != 0 + lv_style_t *preload; +#endif + +#if USE_LV_SW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + lv_style_t *knob_off; + lv_style_t *knob_on; + } sw; +#endif + +#if USE_LV_CHART != 0 + lv_style_t *chart; +#endif + +#if USE_LV_CALENDAR != 0 + struct { + lv_style_t *bg; + lv_style_t *header; + lv_style_t *header_pr; + lv_style_t *day_names; + lv_style_t *highlighted_days; + lv_style_t *inactive_days; + lv_style_t *week_box; + lv_style_t *today_box; + } calendar; +#endif + +#if USE_LV_CB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } box; + } cb; +#endif + +#if USE_LV_BTNM != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } btnm; +#endif + +#if USE_LV_KB != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } kb; +#endif + +#if USE_LV_MBOX != 0 + struct { + lv_style_t *bg; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + } btn; + } mbox; +#endif + +#if USE_LV_PAGE != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } page; +#endif + +#if USE_LV_TA != 0 + struct { + lv_style_t *area; + lv_style_t *oneline; + lv_style_t *cursor; + lv_style_t *sb; + } ta; +#endif + +#if USE_LV_SPINBOX != 0 + struct { + lv_style_t *bg; + lv_style_t *cursor; + lv_style_t *sb; + } spinbox; +#endif + +#if USE_LV_LIST + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + struct { + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + lv_style_t *ina; + } btn; + } list; +#endif + +#if USE_LV_DDLIST != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + lv_style_t *sb; + } ddlist; +#endif + +#if USE_LV_ROLLER != 0 + struct { + lv_style_t *bg; + lv_style_t *sel; + } roller; +#endif + +#if USE_LV_TABVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *indic; + struct { + lv_style_t *bg; + lv_style_t *rel; + lv_style_t *pr; + lv_style_t *tgl_rel; + lv_style_t *tgl_pr; + } btn; + } tabview; +#endif + +#if USE_LV_TILEVIEW != 0 + struct { + lv_style_t *bg; + lv_style_t *scrl; + lv_style_t *sb; + } tileview; +#endif + +#if USE_LV_TABLE != 0 + struct { + lv_style_t *bg; + lv_style_t *cell; + } table; +#endif + +#if USE_LV_WIN != 0 + struct { + lv_style_t *bg; + lv_style_t *sb; + lv_style_t *header; + struct { + lv_style_t *bg; + lv_style_t *scrl; + } content; + struct { + lv_style_t *rel; + lv_style_t *pr; + } btn; + } win; +#endif +} lv_theme_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Set a theme for the system. + * From now, all the created objects will use styles from this theme by default + * @param th pointer to theme (return value of: 'lv_theme_init_xxx()') + */ +void lv_theme_set_current(lv_theme_t *th); + +/** + * Get the current system theme. + * @return pointer to the current system theme. NULL if not set. + */ +lv_theme_t * lv_theme_get_current(void); + +/********************** + * MACROS + **********************/ + +/********************** + * POST INCLUDE + *********************/ +#include "lv_theme_templ.h" +#include "lv_theme_default.h" +#include "lv_theme_alien.h" +#include "lv_theme_night.h" +#include "lv_theme_zen.h" +#include "lv_theme_mono.h" +#include "lv_theme_nemo.h" +#include "lv_theme_material.h" + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEMES_H*/ diff --git a/include/display/lv_themes/lv_theme_alien.h b/include/display/lv_themes/lv_theme_alien.h new file mode 100644 index 0000000..1f62315 --- /dev/null +++ b/include/display/lv_themes/lv_theme_alien.h @@ -0,0 +1,59 @@ +/** + * @file lv_theme_alien.h + * + */ + +#ifndef LV_THEME_ALIEN_H +#define LV_THEME_ALIEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ALIEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the alien theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_alien_init(uint16_t hue, lv_font_t *font); +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_alien(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ALIEN_H*/ diff --git a/include/display/lv_themes/lv_theme_default.h b/include/display/lv_themes/lv_theme_default.h new file mode 100644 index 0000000..1348f1f --- /dev/null +++ b/include/display/lv_themes/lv_theme_default.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_default.h + * + */ + +#ifndef LV_THEME_DEFAULT_H +#define LV_THEME_DEFAULT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_DEFAULT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the default theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_default_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_default(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/include/display/lv_themes/lv_theme_material.h b/include/display/lv_themes/lv_theme_material.h new file mode 100644 index 0000000..d9da664 --- /dev/null +++ b/include/display/lv_themes/lv_theme_material.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_material.h + * + */ + +#ifndef LV_THEME_MATERIAL_H +#define LV_THEME_MATERIAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MATERIAL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_material_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_material(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MATERIAL_H*/ diff --git a/include/display/lv_themes/lv_theme_mono.h b/include/display/lv_themes/lv_theme_mono.h new file mode 100644 index 0000000..63039fa --- /dev/null +++ b/include/display/lv_themes/lv_theme_mono.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_mono.h + * + */ + +#ifndef LV_THEME_MONO_H +#define LV_THEME_MONO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_MONO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the mono theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_mono_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_mono(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_MONO_H*/ diff --git a/include/display/lv_themes/lv_theme_nemo.h b/include/display/lv_themes/lv_theme_nemo.h new file mode 100644 index 0000000..46d43bd --- /dev/null +++ b/include/display/lv_themes/lv_theme_nemo.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_nemo.h + * + */ + +#ifndef LV_THEME_NEMO_H +#define LV_THEME_NEMO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NEMO + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the material theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_nemo_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_nemo(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NEMO_H*/ diff --git a/include/display/lv_themes/lv_theme_night.h b/include/display/lv_themes/lv_theme_night.h new file mode 100644 index 0000000..3e5efb8 --- /dev/null +++ b/include/display/lv_themes/lv_theme_night.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_night.h + * + */ + +#ifndef LV_THEME_NIGHT_H +#define LV_THEME_NIGHT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_NIGHT + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the night theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_night_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_night(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_NIGHT_H*/ diff --git a/include/display/lv_themes/lv_theme_templ.h b/include/display/lv_themes/lv_theme_templ.h new file mode 100644 index 0000000..e717663 --- /dev/null +++ b/include/display/lv_themes/lv_theme_templ.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_templ.h + * + */ + +#ifndef LV_THEME_TEMPL_H +#define LV_THEME_TEMPL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_TEMPL + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the templ theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_templ_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_templ(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_TEMPL_H*/ diff --git a/include/display/lv_themes/lv_theme_zen.h b/include/display/lv_themes/lv_theme_zen.h new file mode 100644 index 0000000..ddd7cb3 --- /dev/null +++ b/include/display/lv_themes/lv_theme_zen.h @@ -0,0 +1,60 @@ +/** + * @file lv_theme_zen.h + * + */ + +#ifndef LV_THEME_ZEN_H +#define LV_THEME_ZEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#ifdef LV_CONF_INCLUDE_SIMPLE +#include "lv_conf.h" +#else +#include "display/lv_conf.h" +#endif + +#if USE_LV_THEME_ZEN + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the zen theme + * @param hue [0..360] hue value from HSV color space to define the theme's base color + * @param font pointer to a font (NULL to use the default) + * @return pointer to the initialized theme + */ +lv_theme_t * lv_theme_zen_init(uint16_t hue, lv_font_t *font); + +/** + * Get a pointer to the theme + * @return pointer to the theme + */ +lv_theme_t * lv_theme_get_zen(void); + +/********************** + * MACROS + **********************/ + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_THEME_ZEN_H*/ diff --git a/include/display/lv_themes/lv_themes.mk b/include/display/lv_themes/lv_themes.mk new file mode 100644 index 0000000..0e4a81a --- /dev/null +++ b/include/display/lv_themes/lv_themes.mk @@ -0,0 +1,14 @@ +CSRCS += lv_theme_alien.c +CSRCS += lv_theme.c +CSRCS += lv_theme_default.c +CSRCS += lv_theme_night.c +CSRCS += lv_theme_templ.c +CSRCS += lv_theme_zen.c +CSRCS += lv_theme_material.c +CSRCS += lv_theme_nemo.c +CSRCS += lv_theme_mono.c + +DEPPATH += --dep-path $(LVGL_DIR)/lvgl/lv_themes +VPATH += :$(LVGL_DIR)/lvgl/lv_themes + +CFLAGS += "-I$(LVGL_DIR)/lvgl/lv_themes" diff --git a/include/display/lv_version.h b/include/display/lv_version.h new file mode 100644 index 0000000..1e62e1e --- /dev/null +++ b/include/display/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/display/lvgl.h b/include/display/lvgl.h new file mode 100644 index 0000000..d2c93b4 --- /dev/null +++ b/include/display/lvgl.h @@ -0,0 +1,88 @@ +/** + * @file lvgl.h + * Include all LittleV GL related headers + */ + +#ifndef LVGL_H +#define LVGL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "lv_version.h" + +#include "lv_misc/lv_log.h" +#include "lv_misc/lv_task.h" + +#include "lv_hal/lv_hal.h" + +#include "lv_core/lv_obj.h" +#include "lv_core/lv_group.h" +#include "lv_core/lv_lang.h" +#include "lv_core/lv_vdb.h" +#include "lv_core/lv_refr.h" + +#include "lv_themes/lv_theme.h" + +#include "lv_objx/lv_btn.h" +#include "lv_objx/lv_imgbtn.h" +#include "lv_objx/lv_img.h" +#include "lv_objx/lv_label.h" +#include "lv_objx/lv_line.h" +#include "lv_objx/lv_page.h" +#include "lv_objx/lv_cont.h" +#include "lv_objx/lv_list.h" +#include "lv_objx/lv_chart.h" +#include "lv_objx/lv_table.h" +#include "lv_objx/lv_cb.h" +#include "lv_objx/lv_bar.h" +#include "lv_objx/lv_slider.h" +#include "lv_objx/lv_led.h" +#include "lv_objx/lv_btnm.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_ddlist.h" +#include "lv_objx/lv_roller.h" +#include "lv_objx/lv_ta.h" +#include "lv_objx/lv_canvas.h" +#include "lv_objx/lv_win.h" +#include "lv_objx/lv_tabview.h" +#include "lv_objx/lv_tileview.h" +#include "lv_objx/lv_mbox.h" +#include "lv_objx/lv_gauge.h" +#include "lv_objx/lv_lmeter.h" +#include "lv_objx/lv_sw.h" +#include "lv_objx/lv_kb.h" +#include "lv_objx/lv_arc.h" +#include "lv_objx/lv_preload.h" +#include "lv_objx/lv_calendar.h" +#include "lv_objx/lv_spinbox.h" +#pragma GCC diagnostic pop + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} +#endif + +#endif /*LVGL_H*/ diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..bc408a8 --- /dev/null +++ b/include/main.h @@ -0,0 +1,81 @@ +/** + * \file main.h + * + * Contains common definitions and header files used throughout your PROS + * project. + * + * Copyright (c) 2017-2022, 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" +//#include "pros/api_legacy.h" + +/** + * 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..ab1aa69 --- /dev/null +++ b/include/okapi/api/coreProsAPI.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 +#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..78c5b3b --- /dev/null +++ b/include/okapi/impl/device/motor/motor.hpp @@ -0,0 +1,457 @@ +/* + * 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; + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setPosPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @return `1` if the operation was successful or `PROS_ERR` if the operation failed, setting + * errno. + */ + virtual std::int32_t setVelPID(double ikF, double ikP, double ikI, double ikD); + + /** + * Sets new PID constants. + * + * @param ikF the feed-forward constant + * @param ikP the proportional constant + * @param ikI the integral constant + * @param ikD the derivative constant + * @param ifilter a constant used for filtering the profile acceleration + * @param ilimit the integral limit + * @param ithreshold the threshold for determining if a position movement has reached its goal + * @param iloopSpeed the rate at which the PID computation is run (in ms) + * @return 1 if the operation was successful or PROS_ERR if the operation failed, setting errno. + */ + virtual std::int32_t setVelPIDFull(double ikF, + double ikP, + double ikI, + double ikD, + double ifilter, + double ilimit, + double ithreshold, + double iloopSpeed); + + /** + * 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/adi.h b/include/pros/adi.h new file mode 100644 index 0000000..abe7544 --- /dev/null +++ b/include/pros/adi.h @@ -0,0 +1,766 @@ +/** + * \file pros/adi.h + * + * Contains prototypes for interfacing with the ADI. + * + * 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-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/. + */ + +#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 + +/** + * 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; + +/** + * 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 + +/******************************************************************************/ +/** 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 - 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 + */ +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 + */ +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. + */ +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. + */ +int32_t adi_port_set_value(uint8_t port, int32_t value); + +/******************************************************************************/ +/** PROS 2 Compatibility Functions **/ +/** **/ +/** These functions provide similar functionality to the PROS 2 API **/ +/******************************************************************************/ + +/** + * 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 + +/** + * 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 - 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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +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. + */ +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. + */ +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. + */ +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. + */ +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 + */ +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. + */ +int32_t adi_motor_stop(uint8_t port); + +/** + * Reference type for an initialized encoder. + * + * This merely contains the port number for the encoder, unlike its use as an + * object to store encoder data in PROS 2. + */ +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 + */ +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 + */ +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. + */ +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. + */ +int32_t adi_encoder_shutdown(adi_encoder_t enc); + +/** + * Reference type for an initialized ultrasonic. + * + * This merely contains the port number for the ultrasonic, unlike its use as an + * object to store ultrasonic data in PROS 2. + */ +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. + */ +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 + */ +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. + */ +int32_t adi_ultrasonic_shutdown(adi_ultrasonic_t ult); + +/** + * Reference type for an initialized gyroscope. + * + * This merely contains the port number for the gyroscope, unlike its use as an + * object to store gyro data in PROS 2. + */ +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. + */ +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. + */ +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. + */ +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. + */ +int32_t adi_gyro_shutdown(adi_gyro_t gyro); + +/** + * Reference type for an initialized potentiometer. + * + * This merely contains the port number for the potentiometer, unlike its use as an + * object to store gyro data in PROS 2. + */ +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. + */ +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. + */ +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. + */ +double adi_potentiometer_get_angle(adi_potentiometer_t potentiometer); + +#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..d91ff7e --- /dev/null +++ b/include/pros/adi.hpp @@ -0,0 +1,765 @@ +/** + * \file pros/adi.hpp + * + * Contains prototypes for interfacing with the ADI. + * + * 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-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/. + */ + +#ifndef _PROS_ADI_HPP_ +#define _PROS_ADI_HPP_ + +#include +#include +#include + +#include "pros/adi.h" + +namespace pros { + +/** 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; + +class ADIPort { + 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 + */ + explicit ADIPort(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 + */ + ADIPort(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 + */ + std::int32_t get_config() const; + + /** + * Gets the value for the given ADI port. + * + * \return The value stored for the given port + */ + 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. + */ + 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. + */ + std::int32_t set_value(std::int32_t value) const; + + protected: + std::uint8_t _smart_port; + std::uint8_t _adi_port; +}; + +class ADIAnalogIn : protected ADIPort { + 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. + */ + explicit ADIAnalogIn(std::uint8_t adi_port); + + /** + * Configures an ADI port on an adi expander 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 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 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + ADIAnalogIn(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::ADIAnalogIn::get_value_calibrated() and + * pros::ADIAnalogIn::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). + * + * 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 + */ + std::int32_t calibrate() const; + + /** + * Gets the 12 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::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::ADIAnalogIn::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 + */ + std::int32_t get_value_calibrated() const; + + /** + * Gets the 16 bit calibrated value of an analog input port. + * + * The pros::ADIAnalogIn::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 + */ + std::int32_t get_value_calibrated_HR() 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 an analog input + * + * \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 ADIPort::get_value; +}; + +// using ADIPotentiometer = ADIAnalogIn; +using ADILineSensor = ADIAnalogIn; +using ADILightSensor = ADIAnalogIn; +using ADIAccelerometer = ADIAnalogIn; + +class ADIAnalogOut : private ADIPort { + 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 + */ + explicit ADIAnalogOut(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 + * + */ + ADIAnalogOut(ext_adi_port_pair_t port_pair); + + /** + * 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: + * ENODEV - The port is not configured as an analog output + * + * \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. + */ + using ADIPort::set_value; +}; + +class ADIDigitalOut : private ADIPort { + 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 + */ + explicit ADIDigitalOut(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 + */ + ADIDigitalOut(ext_adi_port_pair_t port_pair, bool init_state = LOW); + + /** + * 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: + * ENODEV - The port is not configured as a digital output + * + * \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. + */ + using ADIPort::set_value; +}; + +class ADIDigitalIn : private ADIPort { + 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 + */ + explicit ADIDigitalIn(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 + */ + ADIDigitalIn(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. + */ + std::int32_t get_new_press() const; + + /** + * Gets the value for the given ADI port. + * + * 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 The value stored for the given port + */ + using ADIPort::get_value; +}; + +using ADIButton = ADIDigitalIn; + +class ADIMotor : private ADIPort { + 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 + */ + explicit ADIMotor(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 + */ + ADIMotor(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. + */ + 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. + */ + using ADIPort::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 port + */ + using ADIPort::get_value; +}; + +class ADIEncoder : private ADIPort { + 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 + */ + ADIEncoder(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 + */ + ADIEncoder(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. + */ + 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 + * reset + */ + std::int32_t get_value() const; +}; + +class ADIUltrasonic : private ADIPort { + 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. + */ + ADIUltrasonic(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). + */ + ADIUltrasonic(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. + */ + std::int32_t get_value() const; +}; + +class ADIGyro : private ADIPort { + 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 ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * 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 ADI + */ + explicit ADIGyro(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 ADIGyro object be created in initialize() + * when the robot is stationary to ensure proper calibration. If an ADIGyro + * 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 ADI + */ + ADIGyro(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. + */ + 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. + */ + std::int32_t reset() const; +}; + +class ADIPotentiometer : public ADIAnalogIn { + 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 + */ + ADIPotentiometer(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 + */ + ADIPotentiometer(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. + */ + 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 ADIAnalogIn::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::ADIPotentiometer::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 ADIAnalogIn::calibrate; + + /** + * Gets the 12 bit calibrated value of a potentiometer port. + * + * The pros::ADIPotentiometer::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 ADIAnalogIn::get_value_calibrated; +}; + +} // namespace pros + +#endif // _PROS_ADI_HPP_ diff --git a/include/pros/api_legacy.h b/include/pros/api_legacy.h new file mode 100644 index 0000000..068f7e8 --- /dev/null +++ b/include/pros/api_legacy.h @@ -0,0 +1,108 @@ +/** + * \file pros/api_legacy.h + * + * PROS 2 Legacy API header + * + * Contains declarations for functions that are name-compatible with the PROS 2 + * API. Some functions from the PROS 2 API are not useful or cannot be + * implemented in PROS 3, but most common functions are available. + * + * 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. + * 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_LEGACY_H_ +#define _PROS_API_LEGACY_H_ + +#include "api.h" + +#ifdef __cplusplus +#define _NAMESPACE pros:: +#define _CNAMESPACE pros::c:: +#else +#define _NAMESPACE +#define _CNAMESPACE +#endif + +/** + * From adi.h + */ +#define analogCalibrate(port) adi_analog_calibrate(port) +#define analogRead(port) adi_analog_read(port) +#define analogReadCalibrated(port) adi_analog_read_calibrated(port) +#define analogReadCalibratedHR(port) adi_analog_read_calibrated_HR(port) +#define digitalRead(port) adi_digital_read(port) +#define digitalWrite(port, value) adi_digital_write(port, value) +#define pinMode(port, mode) adi_pin_mode(port, mode) +#define adiMotorSet(port, speed) adi_motor_set(port, speed) +#define adiMotorGet(port) adi_motor_get(port) +#define adiMotorStop(port) adi_motor_stop(port) +#define encoderGet(enc) adi_encoder_get(enc) +#define encoderInit(portTop, portBottom, reverse) adi_encoder_init(portTop, portBottom, reverse) +#define encoderShutdown(enc) adi_encoder_shutdown(enc) +#define ultrasonicGet(ult) adi_ultrasonic_get(ult) +#define ultrasonicInit(portEcho, portPing) adi_ultrasonic_init(portEcho, portPing) +#define ultrasonicShutdown(ult) adi_ultrasonic_shutdown(ult) + +typedef _CNAMESPACE adi_encoder_t Encoder; +typedef _CNAMESPACE adi_ultrasonic_t Ultrasonic; + +/** + * From llemu.h + */ +#define lcdInit lcd_initialize +#define lcdReadButtons lcd_read_buttons +#define lcdClear lcd_clear +#define lcdClearLine lcd_clear_line +#define lcdShutdown lcd_shutdown +#define lcdPrint(line, fmt, ...) lcd_print(line, fmt, __VA_ARGS__) +#define lcdSetText(line, text) lcd_set_text(line, text) + +/** + * From misc.h + */ +#define isEnabled() (!competition_is_disabled()) +#define isAutonomous competition_is_autonomous +#define isOnline competition_is_connected +#define isJoystickConnected(id) controller_is_connected(id) +#define joystickGetAnalog(id, channel) controller_get_analog(id, channel) + +/** + * From rtos.h + */ +#define taskCreate(taskCode, stackDepth, parameters, priority) \ + task_create(taskCode, parameters, priority, stackDepth, "") +#define taskDelete(task) task_delete(task) +#define taskDelay task_delay +#define taskDelayUntil(previousWakeTime, cycleTime) task_delay_until(previousWakeTime, cycleTime) +#define taskPriorityGet(task) task_get_priority(task) +#define taskPrioritySet(task, newPriority) task_priority_set(task, newPriority) +#define taskGetState(task) task_get_state(task) +#define taskSuspend(task) task_suspend(task) +#define taskResume(task) task_resume(task) +#define taskGetCount task_get_count +#define mutexCreate mutex_create +#define mutexTake(mutex, blockTime) mutex_take(mutex, blockTime) +#define mutexGive(mutex) mutex_give(mutex) + +typedef _NAMESPACE task_t TaskHandle; +typedef _NAMESPACE mutex_t Mutex; + +/** + * From motors.h + */ +#define motorSet(port, speed) motor_move(port, speed) +#define motorGet(port) motor_get_voltage(port) +#define motorStop(port) motor_move(port, 0) + +#undef _NAMESPACE +#undef _CNAMESPACE + +#endif // _PROS_API_LEGACY_H_ diff --git a/include/pros/apix.h b/include/pros/apix.h new file mode 100644 index 0000000..8e7d306 --- /dev/null +++ b/include/pros/apix.h @@ -0,0 +1,593 @@ +/** + * \file pros/apix.h + * + * 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. + * + * Visit https://pros.cs.purdue.edu/v5/extended/api.html to learn more. + * + * 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. + * 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_EXTENDED_H_ +#define _PROS_API_EXTENDED_H_ + +#include "api.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wall" +#include "display/lvgl.h" +#pragma GCC diagnostic pop +#include "pros/serial.h" + +#ifdef __cplusplus +#include "pros/serial.hpp" +namespace pros::c { +extern "C" { +#endif + +/******************************************************************************/ +/** RTOS FACILITIES **/ +/** **/ +/** **/ +/**See https://pros.cs.purdue.edu/v5/extended/multitasking.html to learn more**/ +/******************************************************************************/ + +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.). + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#abort_delay for + * details. + */ +bool task_abort_delay(task_t task); + +/** + * Notify a task when a target task is being deleted. + * + * This function will configure the PROS kernel to call + * task_notify_ext(task_to_notify, value, action, NULL) when target_task is + * 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 + */ +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. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \return A newly created recursive mutex. + */ +mutex_t mutex_recursive_create(void); + +/** + * Takes a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \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 + */ +bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); + +/** + * Gives a recursive mutex. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking.html#recursive_mutexes + * for details. + * + * \param mutex + * A mutex handle created by mutex_recursive_create + * + * \return 1 if the mutex was obtained, 0 otherwise + */ +bool mutex_recursive_give(mutex_t mutex); + +/** + * Returns a handle to the current owner of a mutex. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param mutex + * A mutex handle + * + * \return A handle to the current task that owns the mutex, or NULL if the + * mutex isn't owned. + */ +task_t mutex_get_owner(mutex_t mutex); + +/** + * Creates a counting sempahore. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + *details. + * + * \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. + */ +sem_t sem_create(uint32_t max_count, uint32_t init_count); + +/** + * Deletes a semaphore (or binary semaphore) + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#semaphores for + * details. + * + * \param sem + * Semaphore to delete + */ +void sem_delete(sem_t sem); + +/** + * Creates a binary semaphore. + * + * See + * https://pros.cs.purdue.edu/v5/extended/multitasking#.htmlbinary_semaphores + * for details. + * + * \return A newly created semaphore. + */ +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. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \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. + */ +bool sem_wait(sem_t sem, uint32_t timeout); + +/** + * Increments a semaphore's value. + * + * See https://pros.cs.purdue.edu/v5/tutorials/multitasking.html#semaphores for + * details. + * + * \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. + */ +bool sem_post(sem_t sem); + +/** + * Returns the current value of the semaphore. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#extra for + * details. + * + * \param sem + * A semaphore handle + * + * \return The current value of the semaphore (e.g. the number of resources + * available) + */ +uint32_t sem_get_count(sem_t sem); + +/** + * Creates a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \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. + */ +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. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \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. + */ +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. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \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. + */ +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. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \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. + */ +bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Receive an item from the queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \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. + */ +bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); + +/** + * Return the number of messages stored in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of messages available in the queue. + */ +uint32_t queue_get_waiting(const queue_t queue); + +/** + * Return the number of spaces left in a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * The queue handle. + * + * \return The number of spaces available in the queue. + */ +uint32_t queue_get_available(const queue_t queue); + +/** + * Delete a queue. + * + * See https://pros.cs.purdue.edu/v5/extended/multitasking.html#queues for + * details. + * + * \param queue + * Queue handle to delete + */ +void queue_delete(queue_t queue); + +/** + * Resets a queue to an empty state + * + * \param queue + * Queue handle to reset + */ +void queue_reset(queue_t queue); + +/******************************************************************************/ +/** Device Registration **/ +/******************************************************************************/ + +/* + * 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, + E_DEVICE_MOTOR = 2, + E_DEVICE_ROTATION = 4, + E_DEVICE_IMU = 6, + E_DEVICE_DISTANCE = 7, + E_DEVICE_RADIO = 8, + E_DEVICE_VISION = 11, + E_DEVICE_ADI = 12, + E_DEVICE_OPTICAL = 16, + E_DEVICE_GPS = 20, + E_DEVICE_SERIAL = 129, + E_DEVICE_GENERIC __attribute__((deprecated("use E_DEVICE_SERIAL instead"))) = E_DEVICE_SERIAL, + E_DEVICE_UNDEFINED = 255 +} v5_device_e_t; + +/* + * 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 + */ +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 + */ +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) + */ +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) + */ +v5_device_e_t registry_get_plugged_type(uint8_t port); + +/******************************************************************************/ +/** 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 + */ +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 + */ +int32_t fdctl(int file, const uint32_t action, void* const extra_arg); + +/** + * 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) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#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) + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#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 + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#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 + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#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 + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#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 + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/filesystem.html#serial + * to learn more. + */ +#define SERCTL_DISABLE_COBS 15 + +/** + * Action macro to check if there is data available from the Generic Serial + * Device + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#define DEVCTL_FIONREAD 16 + +/** + * Action macro to check if there is space available in the Generic Serial + * Device's output buffer + * + * The extra argument is not used with this action, provide any value (e.g. + * NULL) instead + */ +#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..0f5e3b9 --- /dev/null +++ b/include/pros/colors.h @@ -0,0 +1,171 @@ +/* + * \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/. + */ + +#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) + +#define COLOR_ALICE_BLUE 0x00F0F8FF +#define COLOR_ANTIQUE_WHITE 0x00FAEBD7 +#define COLOR_AQUA 0x0000FFFF +#define COLOR_AQUAMARINE 0x007FFFD4 +#define COLOR_AZURE 0x00F0FFFF +#define COLOR_BEIGE 0x00F5F5DC +#define COLOR_BISQUE 0x00FFE4C4 +#define COLOR_BLACK 0x00000000 +#define COLOR_BLANCHED_ALMOND 0x00FFEBCD +#define COLOR_BLUE 0x000000FF +#define COLOR_BLUE_VIOLET 0x008A2BE2 +#define COLOR_BROWN 0x00A52A2A +#define COLOR_BURLY_WOOD 0x00DEB887 +#define COLOR_CADET_BLUE 0x005F9EA0 +#define COLOR_CHARTREUSE 0x007FFF00 +#define COLOR_CHOCOLATE 0x00D2691E +#define COLOR_CORAL 0x00FF7F50 +#define COLOR_CORNFLOWER_BLUE 0x006495ED +#define COLOR_CORNSILK 0x00FFF8DC +#define COLOR_CRIMSON 0x00DC143C +#define COLOR_CYAN 0x0000FFFF +#define COLOR_DARK_BLUE 0x0000008B +#define COLOR_DARK_CYAN 0x00008B8B +#define COLOR_DARK_GOLDENROD 0x00B8860B +#define COLOR_DARK_GRAY 0x00A9A9A9 +#define COLOR_DARK_GREEN 0x00006400 +#define COLOR_DARK_KHAKI 0x00BDB76B +#define COLOR_DARK_MAGENTA 0x008B008B +#define COLOR_DARK_OLIVE_GREEN 0x00556B2F +#define COLOR_DARK_ORANGE 0x00FF8C00 +#define COLOR_DARK_ORCHID 0x009932CC +#define COLOR_DARK_RED 0x008B0000 +#define COLOR_DARK_SALMON 0x00E9967A +#define COLOR_DARK_SEA_GREEN 0x008FBC8F +#define COLOR_DARK_SLATE_GRAY 0x002F4F4F +#define COLOR_DARK_TURQUOISE 0x0000CED1 +#define COLOR_DARK_VIOLET 0x009400D3 +#define COLOR_DEEP_PINK 0x00FF1493 +#define COLOR_DEEP_SKY_BLUE 0x0000BFFF +#define COLOR_DIM_GRAY 0x00696969 +#define COLOR_DODGER_BLUE 0x001E90FF +#define COLOR_FIRE_BRICK 0x00B22222 +#define COLOR_FLORAL_WHITE 0x00FFFAF0 +#define COLOR_FOREST_GREEN 0x00228B22 +#define COLOR_FUCHSIA 0x00FF00FF +#define COLOR_GAINSBORO 0x00DCDCDC +#define COLOR_GHOST_WHITE 0x00F8F8FF +#define COLOR_GOLD 0x00FFD700 +#define COLOR_GOLDENROD 0x00DAA520 +#define COLOR_GRAY 0x00808080 +#define COLOR_GREEN 0x00008000 +#define COLOR_GREEN_YELLOW 0x00ADFF2F +#define COLOR_HONEYDEW 0x00F0FFF0 +#define COLOR_HOT_PINK 0x00FF69B4 +#define COLOR_INDIAN_RED 0x00CD5C5C +#define COLOR_INDIGO 0x004B0082 +#define COLOR_IVORY 0x00FFFFF0 +#define COLOR_KHAKI 0x00F0E68C +#define COLOR_LAVENDER 0x00E6E6FA +#define COLOR_LAVENDER_BLUSH 0x00FFF0F5 +#define COLOR_LAWN_GREEN 0x007CFC00 +#define COLOR_LEMON_CHIFFON 0x00FFFACD +#define COLOR_LIGHT_BLUE 0x00ADD8E6 +#define COLOR_LIGHT_CORAL 0x00F08080 +#define COLOR_LIGHT_CYAN 0x00E0FFFF +#define COLOR_LIGHT_GOLDENROD_YELLOW 0x00FAFAD2 +#define COLOR_LIGHT_GREEN 0x0090EE90 +#define COLOR_LIGHT_GRAY 0x00D3D3D3 +#define COLOR_LIGHT_PINK 0x00FFB6C1 +#define COLOR_LIGHT_SALMON 0x00FFA07A +#define COLOR_LIGHT_SEA_GREEN 0x0020B2AA +#define COLOR_LIGHT_SKY_BLUE 0x0087CEFA +#define COLOR_LIGHT_SLATE_GRAY 0x00778899 +#define COLOR_LIGHT_STEEL_BLUE 0x00B0C4DE +#define COLOR_LIGHT_YELLOW 0x00FFFFE0 +#define COLOR_LIME 0x0000FF00 +#define COLOR_LIME_GREEN 0x0032CD32 +#define COLOR_LINEN 0x00FAF0E6 +#define COLOR_MAGENTA 0x00FF00FF +#define COLOR_MAROON 0x00800000 +#define COLOR_MEDIUM_AQUAMARINE 0x0066CDAA +#define COLOR_MEDIUM_BLUE 0x000000CD +#define COLOR_MEDIUM_ORCHID 0x00BA55D3 +#define COLOR_MEDIUM_PURPLE 0x009370DB +#define COLOR_MEDIUM_SEA_GREEN 0x003CB371 +#define COLOR_MEDIUM_SLATE_BLUE 0x007B68EE +#define COLOR_MEDIUM_SPRING_GREEN 0x0000FA9A +#define COLOR_MEDIUM_TURQUOISE 0x0048D1CC +#define COLOR_MEDIUM_VIOLET_RED 0x00C71585 +#define COLOR_MIDNIGHT_BLUE 0x00191970 +#define COLOR_MINT_CREAM 0x00F5FFFA +#define COLOR_MISTY_ROSE 0x00FFE4E1 +#define COLOR_MOCCASIN 0x00FFE4B5 +#define COLOR_NAVAJO_WHITE 0x00FFDEAD +#define COLOR_NAVY 0x00000080 +#define COLOR_OLD_LACE 0x00FDF5E6 +#define COLOR_OLIVE 0x00808000 +#define COLOR_OLIVE_DRAB 0x006B8E23 +#define COLOR_ORANGE 0x00FFA500 +#define COLOR_ORANGE_RED 0x00FF4500 +#define COLOR_ORCHID 0x00DA70D6 +#define COLOR_PALE_GOLDENROD 0x00EEE8AA +#define COLOR_PALE_GREEN 0x0098FB98 +#define COLOR_PALE_TURQUOISE 0x00AFEEEE +#define COLOR_PALE_VIOLET_RED 0x00DB7093 +#define COLOR_PAPAY_WHIP 0x00FFEFD5 +#define COLOR_PEACH_PUFF 0x00FFDAB9 +#define COLOR_PERU 0x00CD853F +#define COLOR_PINK 0x00FFC0CB +#define COLOR_PLUM 0x00DDA0DD +#define COLOR_POWDER_BLUE 0x00B0E0E6 +#define COLOR_PURPLE 0x00800080 +#define COLOR_RED 0x00FF0000 +#define COLOR_ROSY_BROWN 0x00BC8F8F +#define COLOR_ROYAL_BLUE 0x004169E1 +#define COLOR_SADDLE_BROWN 0x008B4513 +#define COLOR_SALMON 0x00FA8072 +#define COLOR_SANDY_BROWN 0x00F4A460 +#define COLOR_SEA_GREEN 0x002E8B57 +#define COLOR_SEASHELL 0x00FFF5EE +#define COLOR_SIENNA 0x00A0522D +#define COLOR_SILVER 0x00C0C0C0 +#define COLOR_SKY_BLUE 0x0087CEEB +#define COLOR_SLATE_BLUE 0x006A5ACD +#define COLOR_SLATE_GRAY 0x00708090 +#define COLOR_SNOW 0x00FFFAFA +#define COLOR_SPRING_GREEN 0x0000FF7F +#define COLOR_STEEL_BLUE 0x004682B4 +#define COLOR_TAN 0x00D2B48C +#define COLOR_TEAL 0x00008080 +#define COLOR_THISTLE 0x00D8BFD8 +#define COLOR_TOMATO 0x00FF6347 +#define COLOR_TURQUOISE 0x0040E0D0 +#define COLOR_VIOLET 0x00EE82EE +#define COLOR_WHEAT 0x00F5DEB3 +#define COLOR_WHITE 0x00FFFFFF +#define COLOR_WHITE_SMOKE 0x00F5F5F5 +#define COLOR_YELLOW 0x00FFFF00 +#define COLOR_YELLOW_GREEN 0x009ACD32 +#define COLOR_DARK_GREY COLOR_DARK_GRAY +#define COLOR_DARK_SLATE_GREY COLOR_DARK_SLATE_GRAY +#define COLOR_DIM_GREY COLOR_DIM_GRAY +#define COLOR_GREY COLOR_GRAY +#define COLOR_LIGHT_GREY COLOR_LIGHT_GRAY +#define COLOR_LIGHT_SLATE_GREY COLOR_LIGHT_SLATE_GRAY +#define COLOR_SLATE_GREY COLOR_SLATE_GRAY + +#endif // _PROS_COLORS_H_ diff --git a/include/pros/distance.h b/include/pros/distance.h new file mode 100644 index 0000000..b7feda1 --- /dev/null +++ b/include/pros/distance.h @@ -0,0 +1,101 @@ +/** + * \file pros/distance.h + * + * Contains prototypes for functions related to the VEX Distance sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_DISTANCE_H_ +#define _PROS_DISTANCE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/** + * 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. + */ +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. + */ +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. + */ +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. + */ +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..0007035 --- /dev/null +++ b/include/pros/distance.hpp @@ -0,0 +1,114 @@ +/** + * \file pros/distance.hpp + * + * Contains prototypes for the V5 Distance Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/distance.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_DISTANCE_HPP_ +#define _PROS_DISTANCE_HPP_ + +#include + +#include "pros/distance.h" + +namespace pros { +class 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual double get_object_velocity(); + + /** + * Gets the port number of the distance sensor. + * + * \return The distance sensor's port number. + */ + std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/include/pros/ext_adi.h b/include/pros/ext_adi.h new file mode 100644 index 0000000..d428276 --- /dev/null +++ b/include/pros/ext_adi.h @@ -0,0 +1,683 @@ +/** + * \file pros/ext_adi.h + * + * Contains prototypes for interfacing with the 3-Wire Expander. + * + * 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-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/. + */ + +#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 + +/******************************************************************************/ +/** 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 + */ +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 + */ +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. + */ +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. + */ +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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +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. + */ +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. + */ +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. + */ +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. + */ +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 + */ +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. + */ +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, unlike its use as an + * object to store encoder data in PROS 2. + */ +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 + */ +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 + */ +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. + */ +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. + */ +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, unlike its use as an + * object to store encoder data in PROS 2. + */ +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. + */ +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 + */ +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. + */ +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, unlike its use as an + * object to store gyro data in PROS 2. + * + * (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. + */ +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. + */ +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. + */ +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. + */ +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, unlike its use as an + * object to store gyro data in PROS 2. + */ +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); + +#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..1af417b --- /dev/null +++ b/include/pros/gps.h @@ -0,0 +1,313 @@ +/** + * \file pros/gps.h + * + * Contains prototypes for functions related to the VEX GPS. + * + * Visit https://pros.cs.purdue.edu/v5/api/c/gps.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_GPS_H_ +#define _PROS_GPS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +typedef struct __attribute__((__packed__)) gps_status_s { + double x; ///< X Position (meters) + double y; ///< Y Position (meters) + double pitch; ///< Percieved Pitch based on GPS + IMU + double roll; ///< Percieved Roll based on GPS + IMU + double yaw; ///< Percieved Yaw based on GPS + IMU +} gps_status_s_t; + +struct gps_raw_s { + double x; ///< Percieved Pitch based on GPS + IMU + double y; ///< Percieved Roll based on GPS + IMU + double z; ///< Percieved Yaw based on GPS + IMU +}; + +typedef struct gps_raw_s gps_accel_s_t; +typedef struct gps_raw_s gps_gyro_s_t; + +/** + * 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. + */ +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. + */ +int32_t gps_set_offset(uint8_t port, double xOffset, double yOffset); + +/** + * Get the GPS's 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 + * \param xOffset + * Pointer to cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Pointer to 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. + */ +int32_t gps_get_offset(uint8_t port, double* xOffset, double* yOffset); + +/** + * 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..0d8b731 --- /dev/null +++ b/include/pros/gps.hpp @@ -0,0 +1,284 @@ +/** + * \file pros/gps.hpp + * + * Contains prototypes for functions related to the VEX GPS. + * + * Visit https://pros.cs.purdue.edu/v5/api/cpp/gps.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_GPS_HPP_ +#define _PROS_GPS_HPP_ + +#include + +#include + +#include "pros/gps.h" + +namespace pros { +class Gps { + const std::uint8_t _port; + + public: + Gps(const std::uint8_t port) : _port(port){}; + + Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial) : _port(port) { + pros::c::gps_set_position(port, xInitial, yInitial, headingInitial); + }; + + Gps(const std::uint8_t port, double xOffset, double yOffset) : _port(port) { + pros::c::gps_set_offset(port, xOffset, yOffset); + }; + + Gps(const std::uint8_t port, double xInitial, double yInitial, double headingInitial, double xOffset, double yOffset) + : _port(port) { + 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. + */ + 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. + */ + virtual std::int32_t set_offset(double xOffset, double yOffset) const; + + /** + * Get the GPS's 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 xOffset + * Pointer to cartesian 4-Quadrant X offset from center of turning (meters) + * \param yOffset + * Pointer to 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. + */ + virtual std::int32_t get_offset(double* xOffset, double* yOffset) 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual pros::c::gps_status_s_t get_status() 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual pros::c::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::c::gps_accel_s_t get_accel() const; + +}; // Gps Class + +using GPS = Gps; + +} // namespace pros +#endif diff --git a/include/pros/imu.h b/include/pros/imu.h new file mode 100644 index 0000000..17f716a --- /dev/null +++ b/include/pros/imu.h @@ -0,0 +1,514 @@ +/** + * \file pros/imu.h + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_IMU_H_ +#define _PROS_IMU_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +typedef enum imu_status_e { + E_IMU_STATUS_CALIBRATING = 0x01, + E_IMU_STATUS_ERROR = 0xFF, // NOTE: used for returning an error from the get_status function, not that the IMU is + // necessarily in an error state +} imu_status_e_t; + +typedef struct __attribute__((__packed__)) quaternion_s { + double x; + double y; + double z; + double w; +} quaternion_s_t; + +struct imu_raw_s { + double x; + double y; + double z; +}; + +typedef struct imu_raw_s imu_gyro_s_t; +typedef struct imu_raw_s imu_accel_s_t; + +typedef struct __attribute__((__packed__)) euler_s { + double pitch; + double roll; + double yaw; +} euler_s_t; + +#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. + */ +int32_t imu_reset(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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +euler_s_t imu_get_euler(uint8_t port); + +/** + * 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. + */ +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 roll angle, or PROS_ERR_F if the operation failed, setting errno. + */ +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); + +/** + * 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. + */ +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 raw accelerometer values. If the operation failed, all the + * structure's members are filled with PROS_ERR_F and errno is set. + */ +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 Inertial Sensor's status code, or PROS_ERR if the operation + * failed, setting errno. + */ +imu_status_e_t imu_get_status(uint8_t port); + +// NOTE: not used +// void imu_set_mode(uint8_t port, uint32_t mode); +// uint32_t imu_get_mode(uint8_t port); + +//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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +int32_t imu_tare(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 + * \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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..dcf21f9 --- /dev/null +++ b/include/pros/imu.hpp @@ -0,0 +1,454 @@ +/** + * \file pros/imu.hpp + * + * Contains prototypes for functions related to the VEX Inertial sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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/. + */ +#ifndef _PROS_IMU_HPP_ +#define _PROS_IMU_HPP_ + +#include +#include "pros/imu.h" + +namespace pros { +class Imu { + const std::uint8_t _port; + + public: + Imu(const std::uint8_t port) : _port(port){}; + + /** + * 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. + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reset() 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual pros::c::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. + */ + virtual pros::c::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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual pros::c::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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual std::int32_t set_euler(const pros::c::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. + */ + virtual pros::c::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. + */ + virtual pros::c::imu_status_e_t 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. + */ + virtual bool is_calibrating() const; +}; + +using IMU = Imu; + +} // namespace pros + +#endif diff --git a/include/pros/link.h b/include/pros/link.h new file mode 100644 index 0000000..26067b8 --- /dev/null +++ b/include/pros/link.h @@ -0,0 +1,257 @@ +/** + * \file pros/link.h + * + * Contains prototypes for functions related to the robot to robot communications. + * + * Visit https://pros.cs.purdue.edu/v5/api/c/link.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_LINK_H_ +#define _PROS_LINK_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef enum link_type_e { + E_LINK_RECIEVER = 0, + E_LINK_TRANSMITTER +} link_type_e_t; + +#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. + * + * 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 reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + */ +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. + * + * 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 reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * end (1040 bytes/s vs 520 bytes/s). + * + * \return PROS_ERR if initialization fails, 1 if the initialization succeeds. + */ +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. + * + * 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. + */ +bool link_connected(uint8_t port); + +/** + * Returns the bytes of data available to be read + * + * 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. + */ +uint32_t link_raw_receivable_size(uint8_t port); + +/** + * Returns the bytes of data available in transmission 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 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, + */ +uint32_t link_raw_transmittable_size(uint8_t port); + +/** + * Send raw serial data through vexlink. + * + * 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. + */ +uint32_t link_transmit_raw(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive raw serial data through vexlink. + * + * 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. + */ +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. + * + * 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. + */ +uint32_t link_transmit(uint8_t port, void* data, uint16_t data_size); + +/** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * 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. + */ +uint32_t link_receive(uint8_t port, void* dest, uint16_t data_size); + +/** + * Clear the receive buffer of the link, and discarding the data. + * + * 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. + */ +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..d44c6bd --- /dev/null +++ b/include/pros/link.hpp @@ -0,0 +1,200 @@ +/** + * \file pros/link.hpp + * + * Contains prototypes for functions related to robot to robot communications. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/link.html to learn + * more. + * + * 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/. + */ +#ifndef _PROS_LINK_HPP_ +#define _PROS_LINK_HPP_ + +#include +#include + +#include "pros/link.h" + +namespace pros { +class Link { + private: + std::uint8_t _port; + + 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. + * + * 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 reciever, + * with the transmitter having double the transmitting bandwidth as the recieving + * 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. + */ + 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. + * + * 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. + */ + bool connected(); + + /** + * Returns the bytes of data number of without protocol available to be read + * + * 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. + */ + std::uint32_t raw_receivable_size(); + + /** + * Returns the bytes of data available in transmission 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 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, + */ + std::uint32_t raw_transmittable_size(); + + /** + * Send raw serial data through vexlink. + * + * 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. + */ + std::uint32_t transmit_raw(void* data, std::uint16_t data_size); + + /** + * Receive raw serial data through vexlink. + * + * 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. + */ + std::uint32_t receive_raw(void* dest, std::uint16_t data_size); + + /** + * Send packeted message through vexlink, with a checksum and start byte. + * + * 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. + */ + std::uint32_t transmit(void* data, std::uint16_t data_size); + + /** + * Receive packeted message through vexlink, with a checksum and start byte. + * + * 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. + */ + std::uint32_t receive(void* dest, std::uint16_t data_size); + + /** + * Clear the receive buffer of the link, and discarding the data. + * + * 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. + */ + 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..4cb792b --- /dev/null +++ b/include/pros/llemu.h @@ -0,0 +1,255 @@ +/* + * \file pros/llemu.h + * + * Legacy LCD Emulator + * + * 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/llemu.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_H_ +#define _PROS_LLEMU_H_ + +#include +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#include "display/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; + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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 color of the LCD background to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void lcd_set_background_color(lv_color_t color); + +/** + * Changes the text color of the LCD to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void lcd_set_text_color(lv_color_t color); + +#ifdef __cplusplus +} // namespace c +} // namespace pros +} +#endif +#endif // _PROS_LLEMU_H_ diff --git a/include/pros/llemu.hpp b/include/pros/llemu.hpp new file mode 100644 index 0000000..8818edd --- /dev/null +++ b/include/pros/llemu.hpp @@ -0,0 +1,262 @@ +/* + * \file pros/llemu.hpp + * + * Legacy LCD Emulator + * + * 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/llemu.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_LLEMU_HPP_ +#define _PROS_LLEMU_HPP_ + +#include +#include + +#include "pros/llemu.h" + +namespace pros { +namespace lcd { +/** + * Checks whether the emulated three-button LCD has already been initialized. + * + * \return True if the LCD has been initialized or false if not. + */ +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. + */ +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. + */ +bool shutdown(void); + +#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 + +/** + * 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. + */ +template +bool print(std::int16_t line, const char* fmt, Params... args) { + return pros::c::lcd_print(line, fmt, convert_args(args)...); +} + +/** + * 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. + */ +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. + */ +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. + */ +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)) + */ +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)) + */ +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)) + */ +void 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 + */ +std::uint8_t read_buttons(void); + +/** + * Changes the color of the LCD background to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void set_background_color(lv_color_t color); + +/** + * Changes the color of the LCD background to a provided color expressed in RGB + * form, with three values of type uint8_t. + * + * \param r + * A value of type uint8_t, with a range of 0 to 255, representing the + * red value of a color + * + * \param g + * A value of type uint8_t, with a range of 0 to 255, representing the + * green value of a color + * + * \param b + * A value of type uint8_t, with a range of 0 to 255, representing the + * blue value of a color + * + * \return void + */ +void set_background_color(std::uint8_t r, std::uint8_t g, std::uint8_t b); + +/** + * Changes the text color of the LCD to a provided color expressed in + * type lv_color_t. + * + * \param color + * A color of type lv_color_t + * + * \return void + */ +void set_text_color(lv_color_t color); + +/** + * Changes the text color of the LCD to a provided color expressed in RGB + * form, with three values of type uint8_t. + * + * \param r + * A value of type uint8_t, with a range of 0 to 255, representing the + * red value of a color + * + * \param g + * A value of type uint8_t, with a range of 0 to 255, representing the + * green value of a color + * + * \param b + * A value of type uint8_t, with a range of 0 to 255, representing the + * blue value of a color + * + * \return void + */ +void set_text_color(std::uint8_t r, std::uint8_t g, std::uint8_t b); + +} // 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..c1a2cd4 --- /dev/null +++ b/include/pros/misc.h @@ -0,0 +1,464 @@ +/** + * \file pros/misc.h + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_H_ +#define _PROS_MISC_H_ + +#include + +#define NUM_V5_PORTS (22) + +/******************************************************************************/ +/** V5 Competition **/ +/******************************************************************************/ +#define COMPETITION_DISABLED (1 << 0) +#define COMPETITION_AUTONOMOUS (1 << 1) +#define COMPETITION_CONNECTED (1 << 2) + +/** + * Get the current status of the competition control. + * + * \return The competition control status as a mask of bits with + * COMPETITION_{ENABLED,AUTONOMOUS,CONNECTED}. + */ +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif +uint8_t competition_get_status(void); +#ifdef __cplusplus +} +} +} +#endif +#define competition_is_disabled() ((competition_get_status() & COMPETITION_DISABLED) != 0) +#define competition_is_connected() ((competition_get_status() & COMPETITION_CONNECTED) != 0) +#define competition_is_autonomous() ((competition_get_status() & COMPETITION_AUTONOMOUS) != 0) + +/******************************************************************************/ +/** V5 Controller **/ +/******************************************************************************/ +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +typedef enum { E_CONTROLLER_MASTER = 0, E_CONTROLLER_PARTNER } controller_id_e_t; + +typedef enum { + E_CONTROLLER_ANALOG_LEFT_X = 0, + E_CONTROLLER_ANALOG_LEFT_Y, + E_CONTROLLER_ANALOG_RIGHT_X, + E_CONTROLLER_ANALOG_RIGHT_Y +} controller_analog_e_t; + +typedef enum { + E_CONTROLLER_DIGITAL_L1 = 6, + E_CONTROLLER_DIGITAL_L2, + E_CONTROLLER_DIGITAL_R1, + E_CONTROLLER_DIGITAL_R2, + E_CONTROLLER_DIGITAL_UP, + E_CONTROLLER_DIGITAL_DOWN, + E_CONTROLLER_DIGITAL_LEFT, + E_CONTROLLER_DIGITAL_RIGHT, + E_CONTROLLER_DIGITAL_X, + E_CONTROLLER_DIGITAL_B, + E_CONTROLLER_DIGITAL_Y, + 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 + +/* +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 + */ +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 + */ +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 + */ +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 + */ +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 + */ +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. + */ +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 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 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. + */ +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 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 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. + */ +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. + */ +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 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: + * 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 operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t controller_clear(controller_id_e_t id); + +/** + * 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: + * 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. + */ +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 + */ +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 + */ +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 + */ +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 + */ +double battery_get_capacity(void); + +/** + * Checks if the SD card is installed. + * + * \return 1 if the SD card is installed, 0 otherwise + */ +int32_t usd_is_installed(void); + +#ifdef __cplusplus +} +} +} +#endif + +#endif // _PROS_MISC_H_ diff --git a/include/pros/misc.hpp b/include/pros/misc.hpp new file mode 100644 index 0000000..2415c2f --- /dev/null +++ b/include/pros/misc.hpp @@ -0,0 +1,331 @@ +/** + * \file pros/misc.hpp + * + * Contains prototypes for miscellaneous functions pertaining to the controller, + * battery, and competition control. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html to + * learn more. + * + * 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. + * 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/. + */ + +#ifndef _PROS_MISC_HPP_ +#define _PROS_MISC_HPP_ + +#include "pros/misc.h" + +#include +#include + +namespace pros { +class Controller { + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + std::int32_t clear(void); + + private: + controller_id_e_t _id; +}; + +namespace battery { +/** + * 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 + */ +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 + */ +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 + */ +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 + */ +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}. + */ +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 + */ +std::int32_t is_installed(void); +} // namespace usd +} // namespace pros + +#endif // _PROS_MISC_HPP_ diff --git a/include/pros/motors.h b/include/pros/motors.h new file mode 100644 index 0000000..d2246f5 --- /dev/null +++ b/include/pros/motors.h @@ -0,0 +1,1122 @@ +/** + * \file pros/motors.h + * + * 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-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/. + */ + +#ifndef _PROS_MOTORS_H_ +#define _PROS_MOTORS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** 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(), or motorSet() from the PROS 2 API. + * + * 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 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. + */ +int32_t motor_move(uint8_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-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_brake(uint8_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. + * + * 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 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. + */ +int32_t motor_move_absolute(uint8_t port, const 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. + * + * 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 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. + */ +int32_t motor_move_relative(uint8_t port, const 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. + * + * 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 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. + */ +int32_t motor_move_velocity(uint8_t port, const int32_t velocity); + +/** + * 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: + * 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 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. + */ +int32_t motor_move_voltage(uint8_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. + * + * 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 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. + */ +int32_t motor_modify_profiled_velocity(uint8_t port, const int32_t velocity); + +/** + * 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: + * 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 The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_target_position(uint8_t port); + +/** + * Gets the velocity commanded to the motor 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 The commanded motor velocity from +-100, +-200, or +-600, or PROS_ERR + * if the operation failed, setting errno. + */ +int32_t motor_get_target_velocity(uint8_t port); + +/******************************************************************************/ +/** Motor telemetry functions **/ +/** **/ +/** 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: + * 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 The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_actual_velocity(uint8_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-21 + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_draw(uint8_t port); + +/** + * Gets the direction of movement 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-21 + * + * \return 1 for moving in the positive direction, -1 for moving in the + * negative direction, or PROS_ERR if the operation failed, setting errno. + */ +int32_t motor_get_direction(uint8_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-21 + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_efficiency(uint8_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-21 + * + * \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. + */ +int32_t motor_is_over_current(uint8_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-21 + * + * \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. + */ +int32_t motor_is_over_temp(uint8_t port); + +/** + * Checks if the motor is stopped. + * + * \note 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. + * + * \param port + * The V5 port number from 1-21 + * + * \return 1 if the motor is not moving, 0 if the motor is moving, or PROS_ERR + * if the operation failed, setting errno + */ +int32_t motor_is_stopped(uint8_t port); + +/** + * Checks if the motor is at its zero position. + * + * \note 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. + * + * \param port + * The V5 port number from 1-21 + * + * \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 + */ +int32_t motor_get_zero_position_flag(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_fault_e { + E_MOTOR_FAULT_NO_FAULTS = 0x00, + E_MOTOR_FAULT_MOTOR_OVER_TEMP = 0x01, // Analogous to motor_is_over_temp() + E_MOTOR_FAULT_DRIVER_FAULT = 0x02, // Indicates a motor h-bridge fault + E_MOTOR_FAULT_OVER_CURRENT = 0x04, // Analogous to motor_is_over_current() + E_MOTOR_FAULT_DRV_OVER_CURRENT = 0x08 // Indicates an h-bridge over current +} 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. + */ +uint32_t motor_get_faults(uint8_t port); + +#ifdef __cplusplus +} // namespace c +#endif + +typedef enum motor_flag_e { + E_MOTOR_FLAGS_NONE = 0x00, + E_MOTOR_FLAGS_BUSY = 0x01, // Cannot currently communicate to the motor + E_MOTOR_FLAGS_ZERO_VELOCITY = 0x02, // Analogous to motor_is_stopped() + E_MOTOR_FLAGS_ZERO_POSITION = 0x04 // Analogous to motor_get_zero_position_flag() +} 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-21 + * + * \return A bitfield containing the motor's flags. + */ +uint32_t motor_get_flags(uint8_t port); + +/** + * 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: + * 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[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. + */ +int32_t motor_get_raw_position(uint8_t port, uint32_t* const timestamp); + +/** + * 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: + * 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 The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ +double motor_get_position(uint8_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-21 + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ +double motor_get_power(uint8_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-21 + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ +double motor_get_temperature(uint8_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-21 + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ +double motor_get_torque(uint8_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-21 + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage(uint8_t port); + +/******************************************************************************/ +/** Motor configuration functions **/ +/** **/ +/** These functions allow programmers to configure the behavior of motors **/ +/******************************************************************************/ + +#ifdef __cplusplus +} // namespace c +#endif + +/** + * Indicates the current 'brake mode' of a motor. + */ +typedef enum motor_brake_mode_e { + E_MOTOR_BRAKE_COAST = 0, // Motor coasts when stopped, traditional behavior + E_MOTOR_BRAKE_BRAKE = 1, // Motor brakes when stopped + E_MOTOR_BRAKE_HOLD = 2, // Motor actively holds position when stopped + E_MOTOR_BRAKE_INVALID = INT32_MAX +} motor_brake_mode_e_t; + +/** + * Indicates the units used by the motor encoders. + */ +typedef enum motor_encoder_units_e { + E_MOTOR_ENCODER_DEGREES = 0, // Position is recorded as angle in degrees + // as a floating point number + E_MOTOR_ENCODER_ROTATIONS = 1, // Position is recorded as angle in rotations + // as a floating point number + E_MOTOR_ENCODER_COUNTS = 2, // Position is recorded as raw encoder ticks + // as a whole number + E_MOTOR_ENCODER_INVALID = INT32_MAX +} motor_encoder_units_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_GEARSET_18 = 1, // 18:1, 200 RPM, Green gear set + E_MOTOR_GEARSET_06 = 2, // 6:1, 600 RPM, Blue gear set + E_MOTOR_GEARSET_INVALID = INT32_MAX +} 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_GEARSET_18 pros::E_MOTOR_GEARSET_18 +#define MOTOR_GEARSET_06 pros::E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 pros::E_MOTOR_GEARSET_06 +#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_GEARSET_18 E_MOTOR_GEARSET_18 +#define MOTOR_GEARSET_06 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_6 E_MOTOR_GEARSET_06 +#define MOTOR_GEARSET_INVALID E_MOTOR_GEARSET_INVALID +#endif +#endif + +/** + * 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 { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant + uint8_t filter; // A constant used for filtering the profile acceleration + uint16_t limit; // The integral limit + uint8_t threshold; // The threshold for determining if a position movement has + // reached its goal. This has no effect for velocity PID + // calculations. + uint8_t loopspeed; // The rate at which the PID computation is run in ms +} motor_pid_full_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 { + uint8_t kf; // The feedforward constant + uint8_t kp; // The proportional constant + uint8_t ki; // The integral constants + uint8_t kd; // The derivative constant +} 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-21 + * \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. + */ +int32_t motor_set_zero_position(uint8_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-21 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_tare_position(uint8_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-21 + * \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. + */ +int32_t motor_set_brake_mode(uint8_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-21 + * \param limit + * The new current limit in mA + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_current_limit(uint8_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-21 + * \param units + * The new motor encoder units + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_encoder_units(uint8_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-21 + * \param gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_gearing(uint8_t port, const motor_gearset_e_t gearset); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_convert_pid(double kf, double kp, double ki, double kd); + +/** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is 2.0625, + * etc. + * This function will convert the floating point values to the nearest 4.4 + * 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 kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, + double threshold, double loopspeed); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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 pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_pos_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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 pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_pos_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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 pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_vel_pid(uint8_t port, const motor_pid_s_t pid); + +/** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor constants. + * + * \note This feature is in beta, it is advised to use caution when modifying + * the PID values. The motor could be damaged by particularly large constants. + * + * 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 pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_set_vel_pid_full(uint8_t port, const motor_pid_full_s_t pid); + +/** + * 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. + */ +int32_t motor_set_reversed(uint8_t port, const bool reverse); + +/** + * 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-21 + * \param limit + * The new voltage limit in Volts + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ +int32_t motor_set_voltage_limit(uint8_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-21 + * + * \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. + */ +motor_brake_mode_e_t motor_get_brake_mode(uint8_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-21 + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_current_limit(uint8_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-21 + * + * \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(uint8_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-21 + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ +motor_gearset_e_t motor_get_gearing(uint8_t port); + +/** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_get_pos_pid(uint8_t port); + +/** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * 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 + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \param port + * The V5 port number from 1-21 + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ +motor_pid_full_s_t __attribute__((deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage."))) motor_get_vel_pid(uint8_t port); + +/** + * 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. + */ +int32_t motor_is_reversed(uint8_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-21 + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t motor_get_voltage_limit(uint8_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..0da9188 --- /dev/null +++ b/include/pros/motors.hpp @@ -0,0 +1,859 @@ +/** + * \file pros/motors.hpp + * + * 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-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/. + */ + +#ifndef _PROS_MOTORS_HPP_ +#define _PROS_MOTORS_HPP_ + +#include + +#include "pros/motors.h" + +namespace pros { +class Motor { + public: + /** + * Creates a Motor object for the given port and specifications. + * + * 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 gearset + * The motor's gearset + * \param reverse + * True reverses the motor, false is default + * \param encoder_units + * The motor's encoder units + */ + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset, const bool reverse, + const motor_encoder_units_e_t encoder_units); + + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset, const bool reverse); + + explicit Motor(const std::uint8_t port, const motor_gearset_e_t gearset); + + explicit Motor(const std::uint8_t port, const bool reverse); + + explicit Motor(const std::uint8_t port); + + /****************************************************************************/ + /** 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(), 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 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(), 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; + + /** + * 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; + + /** + * 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; + + /** + * 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; + + /** + * 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; + + /** + * 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 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. + */ + virtual 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. + */ + virtual std::int32_t modify_profiled_velocity(const std::int32_t velocity) const; + + /** + * 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: + * ENODEV - The port cannot be configured as a motor + * + * \return The target position in its encoder units or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_target_position(void) const; + + /** + * 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 + * + * \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(void) const; + + /****************************************************************************/ + /** Motor telemetry functions **/ + /** **/ + /** 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 + * + * \return The motor's actual velocity in RPM or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_actual_velocity(void) const; + + /** + * 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 + * + * \return The motor's current in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_draw(void) const; + + /** + * 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 + * + * \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(void) 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. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's efficiency in percent or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_efficiency(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 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(void) const; + + /** + * Checks if the motor is stopped. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note 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 is_stopped(void) const; + + /** + * Checks if the motor is at its zero position. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \note 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 get_zero_position_flag(void) const; + + /** + * 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 port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's faults. + */ + virtual std::uint32_t get_faults(void) const; + + /** + * 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 port + * The V5 port number from 1-21 + * + * \return A bitfield containing the motor's flags. + */ + virtual std::uint32_t get_flags(void) const; + + /** + * 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 + * + * \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; + + /** + * 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 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(void) const; + + /** + * 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 + * + * \return The motor's absolute position in its encoder units or PROS_ERR_F + * if the operation failed, setting errno. + */ + virtual double get_position(void) const; + + /** + * 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 + * + * \return The motor's power draw in Watts or PROS_ERR_F if the operation + * failed, setting errno. + */ + virtual double get_power(void) const; + + /** + * 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 + * + * \return The motor's temperature in degrees Celsius or PROS_ERR_F if the + * operation failed, setting errno. + */ + virtual double get_temperature(void) const; + + /** + * 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 + * + * \return The motor's torque in Nm or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual double get_torque(void) const; + + /** + * 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 + * + * \return The motor's voltage in mV or PROS_ERR_F if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage(void) const; + + /****************************************************************************/ + /** Motor configuration functions **/ + /** **/ + /** These functions allow programmers to configure the behavior of motors **/ + /****************************************************************************/ + + /** + * 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. + */ + virtual std::int32_t set_zero_position(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. + */ + virtual std::int32_t tare_position(void) const; + + /** + * 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: + * ENODEV - The port cannot be configured as a motor + * + * \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. + */ + virtual std::int32_t set_brake_mode(const 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. + */ + virtual std::int32_t set_current_limit(const std::int32_t limit) const; + + /** + * 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: + * 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. + */ + virtual std::int32_t set_encoder_units(const motor_encoder_units_e_t units) const; + + /** + * Sets one of motor_gearset_e_t 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 gearset + * The new motor gearset + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t set_gearing(const motor_gearset_e_t gearset) const; + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + static motor_pid_s_t convert_pid(double kf, double kp, double ki, double kd); + + /** + * Takes in floating point values and returns a properly formatted pid struct. + * The motor_pid_s_t struct is in 4.4 format, i.e. 0x20 is 2.0, 0x21 is + * 2.0625, etc. + * This function will convert the floating point values to the nearest 4.4 + * value. + * + * \param kf + * The feedforward constant + * \param kp + * The proportional constant + * \param ki + * The integral constant + * \param kd + * The derivative constant + * \param filter + * A constant used for filtering the profile acceleration + * \param limit + * The integral limit + * \param threshold + * The threshold for determining if a position movement has reached its + * goal. This has no effect for velocity PID calculations. + * \param loopspeed + * The rate at which the PID computation is run in ms + * + * \return A motor_pid_s_t struct formatted properly in 4.4. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + static motor_pid_full_s_t convert_pid_full(double kf, double kp, double ki, double kd, double filter, double limit, double threshold, + double loopspeed); + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual std::int32_t set_pos_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual std::int32_t set_pos_pid_full(const motor_pid_full_s_t pid) const; + + /** + * Sets one of motor_pid_s_t for the motor. This intended to just modify the + * main PID constants. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual std::int32_t set_vel_pid(const motor_pid_s_t pid) const; + + /** + * Sets one of motor_pid_full_s_t for the motor. + * + * Only non-zero values of the struct will change the existing motor + * constants. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \param pid + * The new motor PID constants + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual std::int32_t set_vel_pid_full(const motor_pid_full_s_t pid) const; + + /** + * 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 + * + * \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; + + /** + * 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. + */ + virtual std::int32_t set_voltage_limit(const std::int32_t limit) const; + + /** + * 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 + * + * \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. + */ + virtual motor_brake_mode_e_t get_brake_mode(void) const; + + /** + * 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 + * + * \return The motor's current limit in mA or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_current_limit(void) const; + + /** + * 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 + * + * \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. + */ + virtual motor_encoder_units_e_t get_encoder_units(void) const; + + /** + * 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 + * + * \return One of motor_gearset_e_t according to what is set for the motor, + * or E_GEARSET_INVALID if the operation failed. + */ + virtual motor_gearset_e_t get_gearing(void) const; + + /** + * Gets the position PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_pos_pid() or + * motor_set_pos_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the position PID constants last set + * to the given motor + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual motor_pid_full_s_t get_pos_pid(void) const; + + /** + * Gets the velocity PID that was set for the motor. This function will return + * zero for all of the parameters if the motor_set_vel_pid() or + * motor_set_vel_pid_full() functions have not been used. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * Additionally, in an error state all values of the returned struct are set + * to their negative maximum values. + * + * \return A motor_pid_full_s_t containing the velocity PID constants last set + * to the given motor + */ + [[deprecated("Changing these values is not supported by VEX and may lead to permanent motor damage.")]] + virtual motor_pid_full_s_t get_vel_pid(void) const; + + /** + * 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 + * + * \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(void) 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. + * + * This function uses the following values of errno when an error state is + * reached: + * ENODEV - The port cannot be configured as a motor + * + * \return The motor's voltage limit in V or PROS_ERR if the operation failed, + * setting errno. + */ + virtual std::int32_t get_voltage_limit(void) const; + + /** + * Gets the port number of the motor. + * + * \return The motor's port number. + */ + virtual std::uint8_t get_port(void) const; + + private: + const std::uint8_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 pros +#endif // _PROS_MOTORS_HPP_ diff --git a/include/pros/optical.h b/include/pros/optical.h new file mode 100644 index 0000000..5fd1254 --- /dev/null +++ b/include/pros/optical.h @@ -0,0 +1,267 @@ +/** + * \file pros/optical.h + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_H_ +#define _PROS_OPTICAL_H_ + +#include +#include +#include "api.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 + + +typedef enum optical_direction_e { NO_GESTURE = 0, UP = 1, DOWN = 2, RIGHT = 3, LEFT = 4, ERROR = PROS_ERR } optical_direction_e_t; + +typedef struct optical_rgb_s { + double red; + double green; + double blue; + double brightness; +} optical_rgb_s_t; + +typedef struct optical_raw_s { + uint32_t clear; + uint32_t red; + uint32_t green; + uint32_t blue; +} optical_raw_s_t; + +typedef struct optical_gesture_s { + uint8_t udata; + uint8_t ddata; + uint8_t ldata; + uint8_t rdata; + uint8_t type; + uint8_t pad; + uint16_t count; + uint32_t time; +} optical_gesture_s_t; + +/** + * 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..783520d --- /dev/null +++ b/include/pros/optical.hpp @@ -0,0 +1,234 @@ +/** + * \file pros/optical.hpp + * + * Contains prototypes for functions related to the VEX Optical sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/imu.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_OPTICAL_HPP_ +#define _PROS_OPTICAL_HPP_ + +#include + +#include + +#include "pros/optical.h" + +namespace pros { +class 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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 poximity value if the operation was successful or PROS_ERR if + * the operation failed, setting errno. + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual std::int32_t disable_gesture(); + + /** + * Gets the port number of the Optical Sensor. + * + * \return The Optical Sensor's port number. + */ + virtual std::uint8_t get_port(); + + private: + const std::uint8_t _port; +}; +} // namespace pros + +#endif diff --git a/include/pros/rotation.h b/include/pros/rotation.h new file mode 100644 index 0000000..197936a --- /dev/null +++ b/include/pros/rotation.h @@ -0,0 +1,223 @@ +/** + * \file pros/rotation.h + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_ROTATION_H_ +#define _PROS_ROTATION_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +#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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..c53ab7b --- /dev/null +++ b/include/pros/rotation.hpp @@ -0,0 +1,190 @@ +/** + * \file pros/rotation.hpp + * + * Contains prototypes for functions related to the VEX Rotation Sensor. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/rotation.html to learn + * more. + * + * 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/. + */ +#ifndef _PROS_ROTATION_HPP_ +#define _PROS_ROTATION_HPP_ + +#include + +#include "pros/rotation.h" + +namespace pros { +class Rotation { + const std::uint8_t _port; + + public: + Rotation(const std::uint8_t port) : _port(port){}; + + Rotation(const std::uint8_t port, const bool reverse_flag); + + /** + * 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. + */ + 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. + */ + 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. + */ + virtual std::int32_t set_position(std::uint32_t position); + + /** + * Reset the Rotation Sensor 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. + */ + virtual std::int32_t reset_position(void); + + /** + * 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. + */ + virtual std::int32_t get_position(); + + /** + * 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 + value or PROS_ERR_F if the operation failed, setting + * errno. + */ + virtual std::int32_t get_velocity(); + + /** + * 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. + */ + virtual std::int32_t get_angle(); + + /** + * 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. + */ + virtual std::int32_t set_reversed(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 + * + * \return 1 if the operation was successful or PROS_ERR if the operation + * failed, setting errno. + */ + virtual std::int32_t reverse(); + + /** + * 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. + */ + virtual std::int32_t get_reversed(); +}; +} // namespace pros + +#endif diff --git a/include/pros/rtos.h b/include/pros/rtos.h new file mode 100644 index 0000000..3afdb24 --- /dev/null +++ b/include/pros/rtos.h @@ -0,0 +1,442 @@ +/** + * \file pros/rtos.h + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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_RTOS_H_ +#define _PROS_RTOS_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif + +// The highest priority that can be assigned to a task. Beware of deadlock. +#define TASK_PRIORITY_MAX 16 + +// The lowest priority that can be assigned to a task. +// This may cause severe performance problems and is generally not recommended. +#define TASK_PRIORITY_MIN 1 + +// The default task priority, which should be used for most tasks. +// Default tasks such as autonomous() inherit this priority. +#define TASK_PRIORITY_DEFAULT 8 + +// The recommended stack size for a new task. This stack size is used for +// default tasks such as autonomous(). This equates to 32,768 bytes, or 128 +// times the default stack size for a task in PROS 2. +#define TASK_STACK_DEPTH_DEFAULT 0x2000 + +// The minimal stack size for a task. This equates to 2048 bytes, or 8 times the +// default stack size for a task in PROS 2. +#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) + +typedef void* task_t; +typedef void (*task_fn_t)(void*); + +typedef enum { + E_TASK_STATE_RUNNING = 0, + E_TASK_STATE_READY, + E_TASK_STATE_BLOCKED, + E_TASK_STATE_SUSPENDED, + E_TASK_STATE_DELETED, + E_TASK_STATE_INVALID +} task_state_e_t; + +typedef enum { + E_NOTIFY_ACTION_NONE, + E_NOTIFY_ACTION_BITS, + E_NOTIFY_ACTION_INCR, + E_NOTIFY_ACTION_OWRITE, + E_NOTIFY_ACTION_NO_OWRITE +} notify_action_e_t; + +#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 + +typedef void* mutex_t; + +/** + * Refers to the current task handle + */ +#ifdef __cplusplus +#define CURRENT_TASK ((pros::task_t)NULL) +#else +#define CURRENT_TASK ((task_t)NULL) +#endif + +#ifdef __cplusplus +namespace c { +#endif + +/** + * Gets the number of milliseconds since PROS initialized. + * + * \return The number of milliseconds since PROS initialized + */ +uint32_t millis(void); + +/** + * Gets the number of microseconds since PROS initialized, + * + * \return The number of microseconds since PROS initialized + */ +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. + */ +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. + */ +void task_delete(task_t task); + +/** + * 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) + */ +void task_delay(const uint32_t milliseconds); + +void delay(const uint32_t milliseconds); + +/** + * Delays a 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) + */ +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 + */ +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 + */ +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 + */ +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 + */ +void task_suspend(task_t task); + +/** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ +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. + */ +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 + */ +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. + */ +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. + */ +task_t task_get_current(); + +/** + * Sends a simple notification to task and increments the notification counter. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to notify + * + * \return Always returns true. + */ +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++. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \param task + * The task to wait on. + * + * \return void + */ +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. + * + * See https://pros.cs.purdue.edu/v5/tutorials/topical/notifications.html for + * details. + * + * \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 + */ +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 + */ +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 + */ +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. + */ +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. + */ +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. + */ +bool mutex_give(mutex_t mutex); + +/** + * Deletes a mutex + * + * \param mutex + * Mutex to unlock. + */ +void mutex_delete(mutex_t mutex); + +#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..aa26d7b --- /dev/null +++ b/include/pros/rtos.hpp @@ -0,0 +1,564 @@ +/** + * \file pros/rtos.hpp + * + * Contains declarations for the PROS RTOS kernel for use by typical VEX + * programmers. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/multitasking.html to + * learn more. + * + * 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. + * 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_RTOS_HPP_ +#define _PROS_RTOS_HPP_ + +#include "pros/rtos.h" +#undef delay +#include +#include +#include +#include +#include +#include + +namespace pros { +class Task { + 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. + * + */ + 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. + * + */ + 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. + * + */ + 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. + * + */ + 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. + * + */ + 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. + * + */ + 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. + */ + explicit Task(task_t task); + + /** + * Get the currently running Task + */ + static Task current(); + + /** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * \param in + * A task handle from task_create() for which to create a pros::Task + * object. + */ + 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. + */ + void remove(); + + /** + * Gets the priority of the specified task. + * + * \return The priority of the task + */ + 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 + */ + void set_priority(std::uint32_t prio); + + /** + * Gets the state of the specified task. + * + * \return The state of the task + */ + std::uint32_t get_state(); + + /** + * Suspends the specified task, making it ineligible to be scheduled. + */ + void suspend(); + + /** + * Resumes the specified task, making it eligible to be scheduled. + * + * \param task + * The task to resume + */ + void resume(); + + /** + * Gets the name of the specified task. + * + * \return A pointer to the name of the task + */ + const char* get_name(); + + /** + * Convert this object to a C task_t handle + */ + 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. + */ + 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 + */ + 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 + */ + 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 + */ + 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 + */ + bool notify_clear(); + + /** + * 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) + */ + static void delay(const std::uint32_t milliseconds); + + /** + * Delays a 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) + */ + 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. + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + template + bool try_lock_until(const std::chrono::time_point& abs_time) { + return take(std::max(static_cast(0), (abs_time - Clock::now()).count())); + } +}; + +/** + * 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 pros + +#endif // _PROS_RTOS_HPP_ diff --git a/include/pros/screen.h b/include/pros/screen.h new file mode 100644 index 0000000..ca72ee2 --- /dev/null +++ b/include/pros/screen.h @@ -0,0 +1,499 @@ +/** + * \file screen.h + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \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/. + */ + +#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 + +/** + * ! Different font sizes that can be used in printing text. + */ +typedef enum { + E_TEXT_SMALL = 0, ///< Small text font size + E_TEXT_MEDIUM, ///< Normal/Medium text font size + E_TEXT_LARGE, ///< Large text font size + E_TEXT_MEDIUM_CENTER, ///< Medium centered text + E_TEXT_LARGE_CENTER ///< Large centered text +} text_format_e_t; + +/** + * ! Enum indicating what the current touch status is for the touchscreen. + */ +typedef enum { + E_TOUCH_RELEASED = 0, ///< Last interaction with screen was a quick press + E_TOUCH_PRESSED, ///< Last interaction with screen was a release + E_TOUCH_HELD, ///< User is holding screen down + E_TOUCH_ERROR ///< An error occured while taking/returning the mutex +} last_touch_e_t; + +/** + * ! Struct representing screen touch status, screen last x, screen last y, press count, release count. + */ +typedef struct screen_touch_status_s { + last_touch_e_t touch_status; ///< Represents if the screen is being held, released, or pressed. + int16_t x; ///< Represents the x value of the location of the touch. + int16_t y; ///< Represents the y value of the location of the touch. + int32_t press_count; ///< Represents how many times the screen has be pressed. + int32_t release_count; ///< Represents how many times the user released after a touch on the screen. +} 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)(int16_t, int16_t); + +#ifdef __cplusplus +namespace c { +#endif + +/******************************************************************************/ +/** 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +uint32_t screen_fill_circle(int16_t x, int16_t y, 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 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. + */ +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. + */ +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); + +/******************************************************************************/ +/** 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. + */ +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. + */ +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..3aecd18 --- /dev/null +++ b/include/pros/screen.hpp @@ -0,0 +1,385 @@ +/** + * \file screen.hpp + * + * Brain screen display and touch functions. + * + * Contains user calls to the v5 screen for touching and displaying graphics. + * + * \copyright (c) 2017, 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_SCREEN_HPP_ +#define _PROS_SCREEN_HPP_ + +#include "pros/screen.h" +#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 + + /******************************************************************************/ + /** 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. + */ + std::uint32_t set_pen(const 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.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. + */ + std::uint32_t set_eraser(const 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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 + */ + 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. + */ + 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. + */ + std::uint32_t touch_callback(touch_event_cb_fn_t cb, last_touch_e_t event_type); + +} //namespace screen +} //namespace pros + +#endif //header guard diff --git a/include/pros/serial.h b/include/pros/serial.h new file mode 100644 index 0000000..6db69cd --- /dev/null +++ b/include/pros/serial.h @@ -0,0 +1,247 @@ +/** + * \file pros/serial.h + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_SERIAL_H_ +#define _PROS_SERIAL_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +namespace c { +#endif + +/******************************************************************************/ +/** 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..60e82c1 --- /dev/null +++ b/include/pros/serial.hpp @@ -0,0 +1,228 @@ +/** + * \file pros/serial.hpp + * + * Contains prototypes for the V5 Generic Serial related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/serial.html to learn + * more. + * + * 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/. + */ + +#ifndef _PROS_SERIAL_HPP_ +#define _PROS_SERIAL_HPP_ + +#include +#include "pros/serial.h" + +namespace pros { +class 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 + */ + explicit Serial(std::uint8_t port, std::int32_t baudrate); + + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual std::int32_t get_write_free() const; + + /** + * Gets the port number of the serial port. + * + * \return The serial port's port number. + */ + std::uint8_t get_port() 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + virtual std::int32_t write(std::uint8_t* buffer, std::int32_t length) const; + + private: + const std::uint8_t _port; +}; + +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..8464b6c --- /dev/null +++ b/include/pros/vision.h @@ -0,0 +1,557 @@ +/** + * \file pros/vision.h + * + * Contains prototypes for the VEX Vision Sensor-related functions. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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_VISION_H_ +#define _PROS_VISION_H_ + +#define VISION_OBJECT_ERR_SIG 255 +// Parameters given by VEX +#define VISION_FOV_WIDTH 316 +#define VISION_FOV_HEIGHT 212 + +#include + +#ifdef __cplusplus +extern "C" { +namespace pros { +#endif +/** + * 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; + +/** + * 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; + +/** + * Color codes are just signatures with multiple IDs and a different type. + */ +typedef uint16_t vision_color_code_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; + int16_t y_middle_coord; +} vision_object_s_t; + +typedef enum vision_zero { + E_VISION_ZERO_TOPLEFT = 0, // (0,0) coordinate is the top left of the FOV + E_VISION_ZERO_CENTER = 1 // (0,0) coordinate is the center of the FOV +} 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 + +/** + * 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. + */ +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 + */ +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. + */ +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. + */ +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. + */ +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. + */ +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. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 + */ +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. + */ +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 + */ +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 + */ +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. + */ +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. + */ +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. + */ +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. + */ +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 + */ +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. + */ +int32_t vision_set_auto_white_balance(uint8_t port, const uint8_t enable); + +/** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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. + */ +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. + */ +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. + */ +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. + */ +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. + */ +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..eeb0046 --- /dev/null +++ b/include/pros/vision.hpp @@ -0,0 +1,445 @@ +/** + * \file pros/vision.hpp + * + * Contains prototypes for the VEX Vision Sensor-related functions in C++. + * + * Visit https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html to learn + * more. + * + * 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. + * 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_VISION_HPP_ +#define _PROS_VISION_HPP_ + +#include "pros/vision.h" + +#include + +namespace pros { +class 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 + */ + 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. + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + 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. + */ + 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. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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 + */ + 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. + */ + 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. + */ + 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 + */ + std::int32_t get_white_balance(void) const; + + /** + * Gets the port number of the Vision Sensor. + * + * \return The vision sensor's port number. + */ + std::uint8_t get_port(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. + */ + 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. + */ + 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. + */ + 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 + */ + 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. + */ + std::int32_t set_auto_white_balance(const std::uint8_t enable) const; + + /** + * Sets the exposure parameter of the Vision Sensor. See + * https://pros.cs.purdue.edu/v5/tutorials/topical/vision.html#exposure-setting + * for more detials. + * + * 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. + */ + 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. + */ + 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 + */ + 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. + */ + 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. + */ + 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. + */ + std::int32_t set_wifi_mode(const std::uint8_t enable) const; + + private: + std::uint8_t _port; +}; +} // namespace pros +#endif // _PROS_VISION_HPP_ diff --git a/include/ryanlib/AsyncProfiler.hpp b/include/ryanlib/AsyncProfiler.hpp new file mode 100644 index 0000000..73c53cd --- /dev/null +++ b/include/ryanlib/AsyncProfiler.hpp @@ -0,0 +1,234 @@ +#pragma once +#include "TaskWrapper.hpp" +#include "Trajectory.hpp" +#include "StateMachine.hpp" +#include "FeedForward.hpp" +#include "LinearMotionProfile.hpp" +#include "okapi/api/chassis/controller/chassisController.hpp" +#include "okapi/api/chassis/model/skidSteerModel.hpp" +#include "okapi/api/util/timeUtil.hpp" +#include "okapi/impl/util/timeUtilFactory.hpp" +#include "okapi/api/filter/emaFilter.hpp" + +namespace ryan{ + +/** + * @brief an enum containing all possible states for our motion profile controller + * + */ +enum class MotionProfileState{ + MOVE, FOLLOW, TURN, IDLE +}; + +// forward declare +template class StateMachine; + +/** + * @brief class that allows us to control our chassis asynchronously using motion profiles + * + */ +class AsyncMotionProfiler : public StateMachine, public TaskWrapper { + protected: + /** + * @brief Construct a new Async Motion Profiler object (using all custom velocity control) + * + * @param iChassis chassis to output to + * @param iMove linear motion profile constraint to generate + * @param iLeftLinear left velocity controller for linear motion profile + * @param iRightLinear right velocity controller for linear motion profile + * @param iLeftTrajectory left velocity controller for trajectories + * @param iRightTrajectory right velocity controller for trajectories + * @param iTimeUtil timer utility + */ + AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + std::unique_ptr iLeftLinear, + std::unique_ptr iRightLinear, + std::unique_ptr iLeftTrajectory, + std::unique_ptr iRightTrajectory, + const okapi::TimeUtil& iTimeUtil); + + /** + * @brief Construct a new Async Motion Profiler object (using internal velocity control) + * + * @param iChassis chassis to output to + * @param iMove linear motion profile constraint to generate + * @param iTimeUtil timer utility + */ + AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + const okapi::TimeUtil& iTimeUtil); + + /** + * @brief Construct a new Async Motion Profiler object (using either custom or internal velocity control depending on the constructor) + * + * @param iChassis chassis to output to + * @param iMove linear motion profile to generate + * @param iLeft left velocity controller (true for linear, false for trajectory) + * @param iRight right velocity controller (true for linear, false for trajectory) + * @param velFlag whether linear is custom (true) or trajectory is custom (true) + * @param iTimeUtil timer utility + */ + AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + std::unique_ptr iLeft, + std::unique_ptr iRight, + bool velFlag, + const okapi::TimeUtil& iTimeUtil); + + void operator=(const AsyncMotionProfiler& rhs) = delete; + + /** + * @brief generate this class using AsyncMotionProfilerBuilder only + * + */ + friend class AsyncMotionProfilerBuilder; + + public: + + /** + * @brief sets the motion profile constraints. Note that any movement currently running will be interrupted + * + * @param iConstraint the kinematic constraints for the motion profile + */ + void setConstraint(const ProfileConstraint& iConstraint); + + /** + * @brief Set the target distance to move + * + * @param iDistance target distance + * @param waitUntilSettled whether or not to wait until the motion profile is settled + */ + void setTarget(okapi::QLength iDistance, bool waitUntilSettled = false); + + /** + * @brief Set the target trajectory to follow + * + * @param iPath target trajectory to follow + * @param waitUntilSettled whether or not to wait until the motion profile is settled + */ + void setTarget(const Trajectory& iPath, bool waitUntilSettled = false); + + /** + * @brief Set the target angle to turn + * + * @param iPath target angle to turn + * @param waitUntilSettled whether or not to wait until the motion profile is settled + */ + void setTarget(okapi::QAngle iAngle, bool waitUntilSettled = false); + + /** + * @brief stop the chassis from moving + * + */ + void stop(); + + /** + * @brief blocks the current movement until the current movement is complete + * + */ + void waitUntilSettled(); + + protected: + std::shared_ptr chassis; + std::shared_ptr leftMotor; + std::shared_ptr rightMotor; + + std::unique_ptr profiler; + std::unique_ptr leftLinear{nullptr}; + std::unique_ptr rightLinear{nullptr}; + std::unique_ptr leftTrajectory{nullptr}; + std::unique_ptr rightTrajectory{nullptr}; + + okapi::TimeUtil timeUtil; + std::unique_ptr rate; + std::unique_ptr timer; + okapi::QTime maxTime{0.0}; + + Trajectory path; + pros::Mutex lock; + + bool trajectoryCustom = false; + bool linearCustom = false; + + /** + * @brief task loop + * + */ + void loop() override; +}; + + +/** + * @brief An AsyncMotionProfile builder class which allows more intuitive instantiation of the class + * + */ +class AsyncMotionProfilerBuilder{ + public: + /** + * @brief Constructs a new Async Motion Profiler Builder object + * + */ + AsyncMotionProfilerBuilder(); + + /** + * @brief Destroys the Async Motion Profiler Builder object + * + */ + ~AsyncMotionProfilerBuilder() = default; + + /** + * @brief sets the chassis object for the profiler to output to + * + * @param iChassis the chassis object to output to + * @return AsyncMotionProfilerBuilder& an ongoing builder + */ + AsyncMotionProfilerBuilder& withOutput(std::shared_ptr iChassis); + + /** + * @brief sets the motion profile generator to use for linear movements + * + * @param iProfiler the profile generator + * @return AsyncMotionProfilerBuilder& + */ + AsyncMotionProfilerBuilder& withProfiler(std::unique_ptr iProfiler); + + /** + * @brief sets the motor controller to use for linear movements + * + * @param iLeft + * @param iRight + * @return AsyncMotionProfilerBuilder& + */ + AsyncMotionProfilerBuilder& withLinearController(FFVelocityController iLeft, FFVelocityController iRight); + + /** + * @brief sets the motor controller to use when following paths + * + * @param iLeft + * @param iRight + * @return AsyncMotionProfilerBuilder& + */ + AsyncMotionProfilerBuilder& withTrajectoryController(FFVelocityController iLeft, FFVelocityController iRight); + + /** + * @brief builds the async motion profiler object with the specified parameters. The thread is started automaically + * + * @return std::shared_ptr the built async motion profiler + */ + std::shared_ptr build(); + + private: + std::unique_ptr profile; + std::shared_ptr chassis; + FFVelocityController leftL; + FFVelocityController rightL; + FFVelocityController leftT; + FFVelocityController rightT; + + bool linearInit = false; + bool trajInit = false; + bool driveInit = false; + bool profileInit = false; +}; +} \ No newline at end of file diff --git a/include/ryanlib/FeedForward.hpp b/include/ryanlib/FeedForward.hpp new file mode 100644 index 0000000..ee01241 --- /dev/null +++ b/include/ryanlib/FeedForward.hpp @@ -0,0 +1,68 @@ +#pragma once +#include "Math.hpp" + +namespace ryan{ + +/** + * @brief Our custom feedforward velocity controller class, can be used when target velocity and acceleration are known + * For example, this can be used in following motion profiles, as well as in pure pursuit + * + */ +class FFVelocityController{ + private: + double kV, kA_Up, kA_Down, kP_Pos, kP_Vel; + double currPos, currVel, power; + + public: + /** + * @brief Constructs a new FFVelocityController object + * + */ + FFVelocityController() = default; + + /** + * @brief Destroys the FFVelocityController object + * + */ + ~FFVelocityController() = default; + + /** + * @brief Constructs a new FFVelocityController object + * + * @param ikV velocity constant + * @param ikAU acceleration constant + * @param ikAD deceleration constant + * @param ikP_Pos proportional constant for position + * @param ikP_Vel proportional constant for velocity + */ + FFVelocityController(double ikV, double ikAU, double ikAD, double ikP_Pos, double ikP_Vel); + + /** + * @brief Calculates one step in accordance to the given parameters + * + * @param position desired position + * @param velocity desired velocity + * @param acceleration desired acceleration + * @param currentPos current position, in feets + * @param currentVel current velocity, in ftps + * @return calculated power to reach the target velocity + */ + double step(double position, double velocity, double acceleration, double currentPos, double currentVel); + + /** + * @brief Returns the target power + * + * @return target power + */ + double getTargetPower() const; + + /** + * @brief Returns kV constant + * + * @return kV + */ + double getkV() const; +}; + +} + diff --git a/include/ryanlib/LinearMotionProfile.hpp b/include/ryanlib/LinearMotionProfile.hpp new file mode 100644 index 0000000..5739f5b --- /dev/null +++ b/include/ryanlib/LinearMotionProfile.hpp @@ -0,0 +1,192 @@ +#pragma once +#include "Units.hpp" +#include "Math.hpp" +#include "Trajectory.hpp" + +namespace ryan{ + +/** + * @brief A struct that stores the physical constraints of the chassis + * + */ +struct ProfileConstraint{ + okapi::QSpeed maxVelocity{0.0}; + okapi::QAcceleration maxAcceleration{0.0}; + okapi::QAcceleration maxDeceleration{0.0}; + okapi::QJerk maxJerk{0.0}; + + /** + * @brief Constructs a new Profile Constraint object + * + * @param maxVel max velocity + * @param maxAccel max acceleration + * @param maxDecel max deceleration (only used in trapezoidal motion profiles) + * @param maxJerk max jerk (only used in s curve motion profiles) + */ + ProfileConstraint(okapi::QSpeed maxVel, okapi::QAcceleration maxAccel, okapi::QAcceleration maxDecel, okapi::QJerk maxJerk); + + ProfileConstraint(okapi::QSpeed maxVel, okapi::QAcceleration maxAccel, okapi::QJerk maxJerk); + + /** + * @brief Destroys the Profile Constraint object + * + */ + ~ProfileConstraint() = default; + + protected: + /** + * @brief Constructs a Profile Constraint object - only accessible by the LinearMotionProfile class + * + */ + ProfileConstraint() = default; + + /** + * @brief forward declared to be friend + * + */ + friend class LinearMotionProfile; +}; + +/** + * @brief An abstract class which acts as a base of all linear motion profile classes + * + */ +class LinearMotionProfile { + protected: + ProfileConstraint constraint; + okapi::QLength distance{0.0}; + bool isReversed{false}; + + std::vector timePhase; + std::vector distPhase; + std::vector velPhase; + std::vector accPhase; + std::vector jerkPhase; + + public: + /** + * @brief Constructs a new Linear Motion Profile object + * + */ + LinearMotionProfile() = default; + + /** + * @brief Destroys the Linear Motion Profile object + * + */ + ~LinearMotionProfile() = default; + + /** + * @brief sets the target distance + * + * @param iDistance new target distance + */ + virtual void setDistance(okapi::QLength iDistance) = 0; + + /** + * @brief sets chassis constraints + * + * @param iConstraint new constraint + */ + virtual void setConstraint(ProfileConstraint iConstraint) = 0; + + /** + * @brief Gets the total time to run the profile + * + * @return QTime total time to run the profile + */ + virtual okapi::QTime getTotalTime() const = 0; + + /** + * @brief Gets the target position at a given time + * + * @param time time step to query + * @return QLength the distance travelled at the target time + */ + virtual okapi::QLength getPosition(okapi::QTime time) const = 0; + + /** + * @brief Gets the target velocity at a given time + * + * @param time time step to query + * @return QSpeed target velocity at the target time + */ + virtual okapi::QSpeed getVelocity(okapi::QTime time) const = 0; + + /** + * @brief Gets the target acceleration at a given time + * + * @param time time step to query + * @return QAcceleration target acceleration at the target time + */ + virtual okapi::QAcceleration getAcceleration(okapi::QTime time) const = 0; + + /** + * @brief gets the kinematics data (position, velocity, acceleration) at a given time + * + * @param time time step to query + * @return TrajectoryPoint target kinematics data at the target time + */ + virtual TrajectoryPoint get(okapi::QTime time) const = 0; +}; + +/** + * @brief class which generates "trapezoidal linear motion profiles" for the chassis to follow. + * Given a target distance, it generates a set of velocities which makes the chassis + * accelerate at max acceleration, cruise at max velocity, then decelerate at max + * deceleration. As a result, the velocity curve of the chassis' translation looks like + * a trapezoid. + * + * Since all the methods are inherited from the LinearMotionProfile class, repeated comments + * are omitted. + */ +class TrapezoidalMotionProfile : public LinearMotionProfile{ + private: + okapi::QLength min3Stage = 0 * okapi::meter; + + public: + TrapezoidalMotionProfile(ProfileConstraint iConstraint); + TrapezoidalMotionProfile() = default; + ~TrapezoidalMotionProfile() = default; + + void setDistance(okapi::QLength iDistance) override; + void setConstraint(ProfileConstraint iConstraint) override; + + okapi::QTime getTotalTime() const override; + okapi::QLength getPosition(okapi::QTime time) const override; + okapi::QSpeed getVelocity(okapi::QTime time) const override; + okapi::QAcceleration getAcceleration(okapi::QTime time) const override; + TrajectoryPoint get(okapi::QTime time) const override; +}; + +/** + * @brief class which generates "s curve linear motion profiles" for the chassis to follow + * Given a target distance, it generates a set of velocities which makes the chassis + * move at max jerk, max acceleration, max velocity, and decelerate the same way. + * As a result, the velocity curve of the chassis' translation looks like + * a smooth s shaped trapezoid. + * + * Since all the methods are inherited from the LinearMotionProfile class, repeated comments + * are omitted. + */ +class SCurveMotionProfile : public LinearMotionProfile{ + okapi::QLength fullDist = 0 * okapi::meter; + okapi::QLength minDist = 0 * okapi::meter; + bool fullAccel{true}; + + public: + SCurveMotionProfile(ProfileConstraint iConstraint); + SCurveMotionProfile() = default; + ~SCurveMotionProfile() = default; + + void setDistance(okapi::QLength iDistance) override; + void setConstraint(ProfileConstraint iConstraint) override; + + okapi::QTime getTotalTime() const override; + okapi::QLength getPosition(okapi::QTime time) const override; + okapi::QSpeed getVelocity(okapi::QTime time) const override; + okapi::QAcceleration getAcceleration(okapi::QTime time) const override; + TrajectoryPoint get(okapi::QTime time) const override; +}; + +} \ No newline at end of file diff --git a/include/ryanlib/Math.hpp b/include/ryanlib/Math.hpp new file mode 100644 index 0000000..b29f62c --- /dev/null +++ b/include/ryanlib/Math.hpp @@ -0,0 +1,125 @@ +#pragma once +#include "Units.hpp" +#include "okapi/api/device/motor/abstractMotor.hpp" +#include "okapi/api/chassis/controller/chassisScales.hpp" +#include +#include +#include + +namespace ryan{ + +/** + * @brief Namespace for all math related functions + * + */ +namespace Math{ + +/** + * @brief sets the value to zero if the value is less than the deadband + * + * @param value the value to limit + * @param db deadband limit + * @return double the value controlled with deadband + */ +double deadband(double value, double db); + +/** + * @brief clamps the value within [mn, mx]. Analogous to std::clamp() + * The function works for any data type with an overloaded < and > operator + * + * @tparam T the type to use + * @param val the value to clamp + * @param mn minimum value + * @param mx maximum value + * @return T the clamped value + */ +template +T clamp(T val, T mn, T mx){return std::max(std::min(mx, val), mn);} + +/** + * @brief Converts ft/s to RPM + * + * @param ftps feets per second + * @return rounds per minute + */ +double ftpsToRPM(double ftps, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset); + +/** + * @brief Converts RPM to ft/s + * + * @param rpm rounds per minute + * @return feet per second + */ +double rpmToFtps(double rpm, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset); + +/** + * @brief Converts ft to encoder ticks (aka. encoder degrees) + * + * @param ft feet + * @return encoder ticks + */ +double ftToTick(double ft, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset); + +/** + * @brief Converts encoder ticks to ft + * + * @param tick encoder ticks + * @return feet + */ +double tickToFt(double tick, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset); + +/** + * @brief Rescales an angle to [-180, 180] + * + * @param angle Angle to be rescaled + * @return rescaled angle + */ +okapi::QAngle rescale180(okapi::QAngle angle); + +/** + * @brief Rescales an angle to [-180, 180] + * + * @param angle angle to be converted + * @return scaled angle to [-180, 180] + */ +double rescale180(double angle); + +/** + * @brief Rescales an angle to [0, 360] + * + * @param angle angle to be rescaled + * @return rescaled angle + */ +okapi::QAngle rescale360(okapi::QAngle angle); + +/** + * @brief Rescales an angle to [0, 360] + * + * @param angle angle to be converted + * @return scaled angle to [0, 360] + */ +double rescale360(double angle); + +/** + * @brief The quadratic formula [https://youtu.be/VOXYMRcWbF8] + * Computes the two roots of a quadratic equation + * x = -b +- sqrt(b^2 - 4ac) / 2a + * + * @param a ^ + * @param b ^ + * @param c ^ + * @return pair containing the two roots, first value is the larger solution + */ +std::pair quadraticFormula(double a, double b, double c); + +/** + * @brief returns the sign of the value + * + * @param value the value to check the sign + * @return int the sign of the value (-1, 0, 1) + */ +int signum(double value); + +}; + +} diff --git a/include/ryanlib/Pneumatics.hpp b/include/ryanlib/Pneumatics.hpp new file mode 100644 index 0000000..4b4addd --- /dev/null +++ b/include/ryanlib/Pneumatics.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "pros/adi.hpp" +#include "Units.hpp" + +namespace ryan{ + +/** + * @brief Wrapper class for vex Pneumatics which allows more convenient control + * + */ +class Pneumatics { + pros::ADIDigitalOut piston; + bool state; + + public: + /** + * @brief Construct a new Pneumatics object + * + * @param iPort solinoid port + * @param initState initial state of the piston + */ + Pneumatics(char iPort, bool initState = false); + + /** + * @brief Destroys the Pneumatics object + * + */ + ~Pneumatics() = default; + + /** + * @brief Toggles the solinoid to the value opposite to the current state + * + */ + void toggle(); + + /** + * @brief Sets the state of the solinoid + * + * @param iState state + */ + void set(bool iState); + + /** + * @brief Get the State of the cylinder + * + * @return whether the piston is extended + */ + bool getState() const; +}; + +} \ No newline at end of file diff --git a/include/ryanlib/StateMachine.hpp b/include/ryanlib/StateMachine.hpp new file mode 100644 index 0000000..2d02681 --- /dev/null +++ b/include/ryanlib/StateMachine.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "pros/rtos.hpp" + +namespace ryan{ + +/** + * @brief Template Wrapper class which allows easy state machine (有限狀態機) implementation. + * state machine is an elegant way of programming a subsystem. It involves several + * possible "states" the subsystem can be in, and allows the state to automatically + * transition into other states to create complex streams of control. + * + * This specific implementation is thread safe and prevents race condition (競爭危害) + * through the use of mutexes + * + * @tparam State the enum class that contains all the possible states of this state machine + * @tparam initState the initial state of the state machine, assumed to be idle + */ +template +class StateMachine{ + private: + State state = initState; + pros::Mutex stateLock; + + public: + /** + * @brief Construct a new State Machine object + * + */ + StateMachine(){} + + /** + * @brief Get the current state + * + * @return State the current state + */ + State getState(){ + stateLock.take(); + State currentState = state; + stateLock.give(); + return currentState; + } + + /** + * @brief Set the current state + * + * @param iState the new state + */ + void setState(State iState){ + stateLock.take(); + state = iState; + stateLock.give(); + } +}; + +} \ No newline at end of file diff --git a/include/ryanlib/TaskWrapper.hpp b/include/ryanlib/TaskWrapper.hpp new file mode 100644 index 0000000..1fdf3e0 --- /dev/null +++ b/include/ryanlib/TaskWrapper.hpp @@ -0,0 +1,81 @@ +#pragma once +#include "pros/rtos.hpp" +#include + +namespace ryan{ + +/* + * A utility class that wraps a task trampoline. To use, simply inherit your class from TaskWrapper + * and override the `loop` method. To start the task, the `startTask` method must be called, either + * from the constructor or from outside the class. Credit for initial idea / implementation goes to + * Theo Lemay (7842F) + * + */ + +class TaskWrapper { + protected: + /** + * @brief Construct a new Task Wrapper object + * + */ + TaskWrapper() = default; + + /** + * @brief Copying between tasks is not allowed + */ + TaskWrapper(const TaskWrapper& iTask) = delete; + + /** + * @brief Construct a new Task Wrapper object + * + * @param iTask rvalue of a task + */ + TaskWrapper(TaskWrapper&& iTask) = default; + + /** + * @brief Destroy the Task Wrapper object, virtual to allow inheritance + * + */ + virtual ~TaskWrapper(); + + /** + * @brief the task loop to run + * Override this function to implement a custom task loop. + */ + virtual void loop() = 0; + + public: + /** + * @brief Start the task. + * + * @param iname The task name, optional. + */ + virtual void startTask(const char* iname = "task"); + + /** + * @brief resumes the task. + */ + virtual void resumeTask(); + + /** + * @brief pauses the task. + */ + virtual void pauseTask(); + + /** + * @brief kills the task. + */ + virtual void stopTask(); + + /** + * @brief Get the task name. + * + * @return The name. + */ + virtual const char* getName(); + + private: + static void trampoline(void* iparam); + std::unique_ptr task {nullptr}; +}; +} \ No newline at end of file diff --git a/include/ryanlib/Trajectory.hpp b/include/ryanlib/Trajectory.hpp new file mode 100644 index 0000000..bda7017 --- /dev/null +++ b/include/ryanlib/Trajectory.hpp @@ -0,0 +1,99 @@ +#pragma once +#include +#include + +namespace ryan{ + +/** + * @brief Structure for trajectory points, which stores the robot's target position, velocity + * and acceleration at a specific time segment + * + */ +struct TrajectoryPoint { + /** + * @brief Construct an empty Trajectory Point + * + */ + TrajectoryPoint() = default; + + /** + * @brief Destroy the Trajectory Point + * + */ + ~TrajectoryPoint() = default; + + /** + * @brief Construct a new Trajectory Point object + * + * @param leftP left position, in ft + * @param rightP right position, in ft + * @param leftV left velocity, in ft/s + * @param rightV right velocity, in ft/s + * @param leftA left acceleration, in ft/s^2 + * @param rightA right acceleration, in ft/s^2 + */ + TrajectoryPoint(double leftP, double rightP, double leftV, double rightV, double leftA, double rightA); + + /** + * @brief forward declared in order to be able to access protected variables of this type + */ + friend std::ostream& operator<<(std::ostream& os, TrajectoryPoint& pt); + + double leftPosition, rightPosition, leftVelocity, leftAcceleration, rightVelocity, rightAcceleration; +}; + +/** + * @brief Prints the information of a trajectory point to an existing ostream + * + * @param os the output stream to output to + * @param pt the trajectory point to print + * @return std::ostream& an ongoing output stream + */ +std::ostream& operator<<(std::ostream& os, TrajectoryPoint& pt); + +/** + * @brief class which stores a trajectory - a series of target position, velocity and acceleration + * which allows our robot to follow a predetermined path. The paths are pre-generated on + * our computer and then deployed into our code. + */ +class Trajectory{ + private: + std::vector path; + + public: + /** + * @brief Construct a new Trajectory object + * + */ + Trajectory() = default; + + /** + * @brief Destroy the Trajectory object + * + */ + ~Trajectory() = default; + + /** + * @brief Construct a new Trajectory object + * + * @param iPath the trajectory + */ + Trajectory(const std::initializer_list& iPath); + + /** + * @brief gets the trajectory information at a given point of the trajectory + * + * @param index the index (time) to check + * @return TrajectoryPoint the trajectory point at the given time + */ + TrajectoryPoint operator[](int index) const; + + /** + * @brief returns the size of the trajectory. Every index stores 10ms of target kinematics + * + * @return int the size of the trajectory + */ + int size() const; +}; + +} \ No newline at end of file diff --git a/include/ryanlib/Units.hpp b/include/ryanlib/Units.hpp new file mode 100644 index 0000000..914cae5 --- /dev/null +++ b/include/ryanlib/Units.hpp @@ -0,0 +1,60 @@ +#pragma once +#include "okapi/api/units/RQuantity.hpp" +#include "okapi/api/units/QLength.hpp" +#include "okapi/api/units/QAngularSpeed.hpp" +#include "okapi/api/units/QAngularAcceleration.hpp" +#include "okapi/api/units/QArea.hpp" +#include "okapi/api/units/QSpeed.hpp" +#include "okapi/api/units/QAcceleration.hpp" +#include "okapi/api/units/QTime.hpp" +#include "okapi/api/units/QAngularJerk.hpp" +#include "okapi/api/units/QJerk.hpp" + +/* + * The unit library we uses allows us to check our math during compile time + * compile time using dimensional analysis. This file includes expansion + * to extra units such as curvature that we use within our code. + */ +namespace okapi{ +// Predegined Number unit +constexpr Number pct = number / 100; + +// Predefined Length Units +constexpr QLength court = 12 * foot; + +// Predefined Speed Unit +constexpr QSpeed ftps = foot / second; + +// Predefined Acceleration Unit +constexpr QAcceleration ftps2 = ftps / second; + +// Predefined Jerk Unit +constexpr QJerk mps3 = mps2 / second; +constexpr QJerk ftps3 = ftps2 / second; + + +inline namespace literals{ +// number unit literals +constexpr Number operator"" _pct(long double x) { return static_cast(x)*pct; } +constexpr Number operator"" _pct(unsigned long long int x) { return static_cast(x)*pct; } + +// Length Unit Literals +constexpr QLength operator"" _court(long double x) { return static_cast(x)*court; } +constexpr QLength operator"" _court(unsigned long long int x) { return static_cast(x)*court; } + +// Predefined Speed Unit +constexpr QSpeed operator"" _ftps(long double x) { return static_cast(x)*ftps; } +constexpr QSpeed operator"" _ftps(unsigned long long int x) { return static_cast(x)*ftps; } + +// Predefined Acceleration Unit +constexpr QAcceleration operator"" _ftps2(long double x) { return static_cast(x)*ftps2; } +constexpr QAcceleration operator"" _ftps2(unsigned long long int x) { return static_cast(x)*ftps2; } + +// Jerk Literals +constexpr QJerk operator"" _mps3(long double x) { return static_cast(x)*mps3; } +constexpr QJerk operator"" _mps3(unsigned long long int x) { return static_cast(x)*mps3; } +constexpr QJerk operator"" _ftps3(long double x) { return static_cast(x)*ftps3; } +constexpr QJerk operator"" _ftps3(unsigned long long int x) { return static_cast(x)*ftps3; } + +} // namespace literals +} // namespace okapi \ No newline at end of file diff --git a/include/ryanlib/api.hpp b/include/ryanlib/api.hpp new file mode 100644 index 0000000..cc903c7 --- /dev/null +++ b/include/ryanlib/api.hpp @@ -0,0 +1,14 @@ +#pragma once +namespace ryan{} + +using namespace ryan; + +#include "ryanlib/Units.hpp" // good +#include "ryanlib/Math.hpp" +#include "ryanlib/TaskWrapper.hpp" +#include "ryanlib/Pneumatics.hpp" +#include "ryanlib/StateMachine.hpp" +#include "ryanlib/Trajectory.hpp" +#include "ryanlib/FeedForward.hpp" +#include "ryanlib/LinearMotionProfile.hpp" +#include "ryanlib/AsyncProfiler.hpp" diff --git a/project.pros b/project.pros new file mode 100644 index 0000000..ad1f24e --- /dev/null +++ b/project.pros @@ -0,0 +1,311 @@ +{ + "py/object": "pros.conductor.project.Project", + "py/state": { + "project_name": "ryanlib-template", + "target": "v5", + "templates": { + "kernel": { + "location": "C:\\Users\\ryanl\\AppData\\Roaming\\PROS\\templates\\kernel@3.6.2", + "metadata": { + "cold_addr": "58720256", + "cold_output": "bin/cold.package.bin", + "hot_addr": "125829120", + "hot_output": "bin/hot.package.bin", + "origin": "pros-mainline", + "output": "bin/monolith.bin" + }, + "name": "kernel", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": null, + "system_files": [ + "include/display/lv_objx/lv_kb.h", + "include/display/lv_draw/lv_draw.mk", + "include/display/lv_objx/lv_ta.h", + "include/display/lv_misc/lv_math.h", + "include/pros/rtos.h", + "include/pros/distance.hpp", + "include/pros/rotation.h", + "include/display/lv_conf_checker.h", + "include/display/lv_misc/lv_gc.h", + "include/display/lv_conf.h", + "include/display/lv_themes/lv_themes.mk", + "include/pros/llemu.h", + "include/display/lv_draw/lv_draw_img.h", + "include/display/lv_objx/lv_mbox.h", + "include/display/lv_misc/lv_area.h", + "include/pros/imu.hpp", + "include/display/lv_objx/lv_table.h", + "include/display/lv_objx/lv_list.h", + "include/display/lv_misc/lv_txt.h", + "include/display/lv_fonts/lv_font_builtin.h", + "include/pros/optical.hpp", + "include/display/lv_objx/lv_gauge.h", + "include/display/lv_objx/lv_canvas.h", + "include/display/lv_hal/lv_hal_indev.h", + "include/pros/gps.hpp", + "include/pros/misc.hpp", + "include/display/lv_themes/lv_theme_default.h", + "include/display/lv_themes/lv_theme_zen.h", + "include/pros/screen.h", + "include/pros/vision.h", + "include/pros/vision.hpp", + "include/display/lv_objx/lv_preload.h", + "firmware/libm.a", + "include/display/lv_objx/lv_page.h", + "include/pros/screen.hpp", + "include/display/lv_core/lv_style.h", + "include/pros/link.h", + "include/pros/ext_adi.h", + "include/pros/adi.hpp", + "include/display/lv_objx/lv_chart.h", + "include/display/lv_core/lv_refr.h", + "include/display/lv_core/lv_vdb.h", + "include/display/lv_misc/lv_mem.h", + "include/pros/serial.h", + "include/display/lv_objx/lv_imgbtn.h", + "include/pros/apix.h", + "include/display/lv_core/lv_lang.h", + "include/display/lv_draw/lv_draw_vbasic.h", + "include/display/lv_misc/lv_symbol_def.h", + "include/display/lv_objx/lv_objx_templ.h", + "include/display/lv_misc/lv_ufs.h", + "firmware/libpros.a", + "include/pros/motors.h", + "include/display/lv_objx/lv_roller.h", + "common.mk", + "include/pros/adi.h", + "include/display/lv_objx/lv_label.h", + "include/display/lv_draw/lv_draw_triangle.h", + "include/display/lv_fonts/lv_fonts.mk", + "include/pros/gps.h", + "include/display/lv_objx/lv_objx.mk", + "include/display/lv_draw/lv_draw_rect.h", + "include/display/lv_objx/lv_img.h", + "include/display/lv_misc/lv_task.h", + "include/pros/serial.hpp", + "include/pros/misc.h", + "include/display/lv_themes/lv_theme_templ.h", + "include/display/lv_misc/lv_ll.h", + "include/display/lv_draw/lv_draw.h", + "include/display/licence.txt", + "include/display/lv_misc/lv_anim.h", + "include/display/lv_objx/lv_btnm.h", + "include/display/lv_objx/lv_cb.h", + "include/api.h", + "include/display/lv_objx/lv_arc.h", + "include/display/lv_draw/lv_draw_label.h", + "include/display/lv_objx/lv_sw.h", + "include/display/lv_themes/lv_theme_night.h", + "include/display/lv_draw/lv_draw_arc.h", + "include/display/lv_themes/lv_theme_mono.h", + "include/display/lv_draw/lv_draw_rbasic.h", + "include/display/lv_objx/lv_line.h", + "include/display/lv_misc/lv_templ.h", + "include/display/lv_objx/lv_lmeter.h", + "firmware/v5-hot.ld", + "include/display/lv_objx/lv_calendar.h", + "include/display/lv_core/lv_indev.h", + "include/pros/colors.h", + "include/display/README.md", + "include/pros/link.hpp", + "include/display/lv_misc/lv_misc.mk", + "include/pros/distance.h", + "include/pros/optical.h", + "include/display/lv_objx/lv_bar.h", + "include/display/lv_objx/lv_btn.h", + "include/display/lv_objx/lv_win.h", + "firmware/v5-common.ld", + "include/display/lv_core/lv_obj.h", + "include/pros/rotation.hpp", + "include/display/lv_objx/lv_cont.h", + "include/display/lv_misc/lv_circ.h", + "include/display/lv_hal/lv_hal_tick.h", + "include/display/lv_version.h", + "include/display/lv_objx/lv_spinbox.h", + "include/display/lv_objx/lv_led.h", + "include/display/lv_draw/lv_draw_line.h", + "include/display/lv_core/lv_core.mk", + "include/display/lv_hal/lv_hal.mk", + "include/pros/llemu.hpp", + "include/display/lv_hal/lv_hal_disp.h", + "include/display/lv_objx/lv_tileview.h", + "include/display/lv_themes/lv_theme_material.h", + "include/display/lv_misc/lv_log.h", + "include/pros/api_legacy.h", + "include/display/lv_misc/lv_font.h", + "include/display/lv_misc/lv_color.h", + "include/display/lvgl.h", + "include/display/lv_core/lv_group.h", + "firmware/libc.a", + "include/pros/rtos.hpp", + "firmware/v5.ld", + "include/pros/motors.hpp", + "include/display/lv_objx/lv_slider.h", + "include/display/lv_hal/lv_hal.h", + "include/display/lv_themes/lv_theme.h", + "include/display/lv_objx/lv_ddlist.h", + "include/display/lv_misc/lv_fs.h", + "include/pros/imu.h", + "include/display/lv_objx/lv_tabview.h", + "include/display/lv_themes/lv_theme_nemo.h", + "include/display/lv_themes/lv_theme_alien.h" + ], + "target": "v5", + "user_files": [ + "src/main.c", + "include/main.hh", + "include/main.hpp", + "Makefile", + "src/main.cpp", + "include/main.h", + ".gitignore", + "src/main.cc" + ], + "version": "3.6.2" + }, + "okapilib": { + "location": "C:\\Users\\ryanl\\AppData\\Roaming\\PROS\\templates\\okapilib@4.8.0", + "metadata": { + "origin": "pros-mainline" + }, + "name": "okapilib", + "py/object": "pros.conductor.templates.local_template.LocalTemplate", + "supported_kernels": "^3.3.1", + "system_files": [ + "include/okapi/api/odometry/odomMath.hpp", + "include/okapi/squiggles/physicalmodel/physicalmodel.hpp", + "include/okapi/api/chassis/model/threeEncoderXDriveModel.hpp", + "include/okapi/api/chassis/model/hDriveModel.hpp", + "include/okapi/api/chassis/model/readOnlyChassisModel.hpp", + "include/okapi/api/device/button/buttonBase.hpp", + "include/okapi/api/units/QAngularJerk.hpp", + "include/okapi/api/control/iterative/iterativeController.hpp", + "include/okapi/api/control/controllerInput.hpp", + "include/okapi/squiggles/math/quinticpolynomial.hpp", + "include/okapi/api/device/rotarysensor/continuousRotarySensor.hpp", + "include/okapi/api/control/async/asyncPositionController.hpp", + "include/okapi/api/filter/passthroughFilter.hpp", + "include/okapi/api/device/rotarysensor/rotarySensor.hpp", + "include/okapi/api/odometry/stateMode.hpp", + "include/okapi/impl/device/controller.hpp", + "include/okapi/api/units/QTime.hpp", + "include/okapi/api/control/util/controllerRunner.hpp", + "include/okapi/api/units/QTorque.hpp", + "include/okapi/impl/device/rotarysensor/IMU.hpp", + "include/okapi/api/control/util/pidTuner.hpp", + "include/okapi/impl/util/timeUtilFactory.hpp", + "include/okapi/api/device/motor/abstractMotor.hpp", + "include/okapi/impl/device/button/controllerButton.hpp", + "include/okapi/impl/device/rotarysensor/integratedEncoder.hpp", + "include/okapi/impl/device/rotarysensor/adiEncoder.hpp", + "include/okapi/api/filter/composableFilter.hpp", + "include/okapi/api/chassis/model/xDriveModel.hpp", + "include/okapi/squiggles/geometry/pose.hpp", + "include/okapi/api/odometry/twoEncoderOdometry.hpp", + "include/okapi/api/util/timeUtil.hpp", + "firmware/squiggles.mk", + "include/okapi/api/control/async/asyncPosPidController.hpp", + "include/okapi/impl/control/util/controllerRunnerFactory.hpp", + "include/okapi/impl/chassis/controller/chassisControllerBuilder.hpp", + "include/okapi/api/control/closedLoopController.hpp", + "include/okapi/squiggles/math/utils.hpp", + "include/okapi/api/control/async/asyncVelIntegratedController.hpp", + "include/okapi/api/units/QLength.hpp", + "include/okapi/impl/device/motor/motor.hpp", + "include/okapi/api/odometry/odometry.hpp", + "include/okapi/api/units/RQuantity.hpp", + "include/okapi/api/units/QArea.hpp", + "include/okapi/api/filter/filter.hpp", + "include/okapi/api/device/button/abstractButton.hpp", + "include/okapi/api/units/QPressure.hpp", + "include/okapi/api/control/async/asyncLinearMotionProfileController.hpp", + "include/okapi/api/control/util/flywheelSimulator.hpp", + "include/okapi/api/util/logging.hpp", + "include/okapi/api/chassis/model/threeEncoderSkidSteerModel.hpp", + "include/okapi/api/filter/emaFilter.hpp", + "include/okapi/impl/device/controllerUtil.hpp", + "include/okapi/api/util/mathUtil.hpp", + "include/okapi/api/filter/averageFilter.hpp", + "include/okapi/api/control/iterative/iterativeVelocityController.hpp", + "include/okapi/api/odometry/point.hpp", + "include/okapi/api/control/async/asyncController.hpp", + "include/okapi/impl/control/async/asyncMotionProfileControllerBuilder.hpp", + "include/okapi/api/coreProsAPI.hpp", + "include/okapi/api/units/QSpeed.hpp", + "include/okapi/impl/control/util/pidTunerFactory.hpp", + "include/okapi/api/units/QAngle.hpp", + "include/okapi/api/control/async/asyncVelocityController.hpp", + "include/okapi/api/odometry/threeEncoderOdometry.hpp", + "include/okapi/api/filter/velMath.hpp", + "include/okapi/api/control/async/asyncPosIntegratedController.hpp", + "include/okapi/squiggles/constraints.hpp", + "include/okapi/api/filter/filteredControllerInput.hpp", + "include/okapi/api/chassis/controller/chassisControllerPid.hpp", + "include/okapi/api/control/iterative/iterativePositionController.hpp", + "include/okapi/api/control/offsettableControllerInput.hpp", + "include/okapi/squiggles/squiggles.hpp", + "include/okapi/api/units/QAngularSpeed.hpp", + "include/okapi/api/control/iterative/iterativePosPidController.hpp", + "include/okapi/squiggles/physicalmodel/tankmodel.hpp", + "include/okapi/impl/util/rate.hpp", + "include/okapi/api/filter/medianFilter.hpp", + "include/okapi/impl/device/rotarysensor/potentiometer.hpp", + "include/okapi/api/control/iterative/iterativeVelPidController.hpp", + "include/okapi/squiggles/geometry/profilepoint.hpp", + "include/okapi/impl/device/button/adiButton.hpp", + "include/okapi/impl/control/async/asyncVelControllerBuilder.hpp", + "include/okapi/api/filter/demaFilter.hpp", + "include/okapi/api/units/RQuantityName.hpp", + "include/okapi/api/control/util/pathfinderUtil.hpp", + "include/okapi/api/util/abstractTimer.hpp", + "include/okapi/api.hpp", + "include/okapi/impl/control/async/asyncPosControllerBuilder.hpp", + "include/okapi/api/chassis/controller/chassisScales.hpp", + "include/okapi/api/units/QMass.hpp", + "include/okapi/impl/device/rotarysensor/adiGyro.hpp", + "include/okapi/impl/util/configurableTimeUtilFactory.hpp", + "include/okapi/api/control/util/settledUtil.hpp", + "include/okapi/impl/control/iterative/iterativeControllerFactory.hpp", + "include/okapi/impl/util/timer.hpp", + "include/okapi/api/chassis/controller/defaultOdomChassisController.hpp", + "include/okapi/impl/device/motor/motorGroup.hpp", + "include/okapi/api/control/async/asyncWrapper.hpp", + "include/okapi/squiggles/io.hpp", + "include/okapi/api/filter/ekfFilter.hpp", + "include/okapi/api/control/async/asyncMotionProfileController.hpp", + "include/okapi/squiggles/geometry/controlvector.hpp", + "include/okapi/impl/device/distanceSensor.hpp", + "include/okapi/api/control/controllerOutput.hpp", + "include/okapi/api/units/QVolume.hpp", + "include/okapi/squiggles/spline.hpp", + "include/okapi/api/units/QJerk.hpp", + "include/okapi/api/chassis/controller/chassisController.hpp", + "include/okapi/squiggles/physicalmodel/passthroughmodel.hpp", + "include/okapi/api/units/QAngularAcceleration.hpp", + "include/okapi/api/chassis/controller/chassisControllerIntegrated.hpp", + "include/okapi/impl/device/adiUltrasonic.hpp", + "include/okapi/impl/device/opticalSensor.hpp", + "include/okapi/api/units/QForce.hpp", + "include/okapi/api/util/supplier.hpp", + "include/okapi/api/chassis/controller/odomChassisController.hpp", + "include/okapi/impl/filter/velMathFactory.hpp", + "include/okapi/api/control/iterative/iterativeMotorVelocityController.hpp", + "include/okapi/api/control/async/asyncVelPidController.hpp", + "include/okapi/api/odometry/odomState.hpp", + "include/okapi/api/chassis/model/chassisModel.hpp", + "include/okapi/api/units/QFrequency.hpp", + "include/okapi/impl/device/rotarysensor/rotationSensor.hpp", + "include/okapi/api/util/abstractRate.hpp", + "include/okapi/impl/device/motor/adiMotor.hpp", + "include/okapi/api/units/QAcceleration.hpp", + "include/okapi/api/chassis/model/skidSteerModel.hpp", + "firmware/okapilib.a" + ], + "target": "v5", + "user_files": [], + "version": "4.8.0" + } + }, + "upload_options": {} + } +} \ No newline at end of file diff --git a/ryanlib@1.0.1.zip b/ryanlib@1.0.1.zip new file mode 100644 index 0000000..7acc94b Binary files /dev/null and b/ryanlib@1.0.1.zip differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..4f36a42 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,98 @@ +#include "main.h" +#include "ryanlib/api.hpp" +#include "okapi/api.hpp" +using namespace okapi; + +// Chassis' max velocity, acceleration, and jerk +ProfileConstraint moveLimit({5.3_ftps, 6_ftps2, 27_ftps3}); + +// TUNING, uncomment if you want to use the custom velocity controller +//FFVelocityController leftController(0.23, .025, .01, 1.8, .1); +//FFVelocityController rightController(0.23, .025, .01, 1.8, .1); + +std::shared_ptr chassis = ChassisControllerBuilder() + // motor port, negative if reversed + .withMotors({14, 15, 16}, {17, 18, 20}) + // {motor cartridge, wheel gear / motor gear}, {{wheel diameter, track diameter} imev5TPR} + .withDimensions({AbstractMotor::gearset::blue, 48.0/36.0}, {{2.75_in, 1.25_ft}, imev5BlueTPR}) + .build(); + +std::shared_ptr profiler = AsyncMotionProfilerBuilder() + .withOutput(chassis) + .withProfiler(std::make_unique(moveLimit)) + //.withLinearController(leftController, rightController) + .build(); + +/** + * Runs initialization code. This occurs as soon as the program is started. + * + * All other competition modes are blocked by initialize; it is recommended + * to keep execution time for this mode under a few seconds. + */ +void initialize(){ + pros::lcd::initialize(); +} + +/** + * Runs while the robot is in the disabled state of Field Management System or + * the VEX Competition Switch, following either autonomous or opcontrol. When + * the robot is enabled, this task will exit. + */ +void disabled(){} + +/** + * Runs after initialize(), and before autonomous when connected to the Field + * Management System or the VEX Competition Switch. This is intended for + * competition-specific initialization routines, such as an autonomous selector + * on the LCD. + * + * This task will exit when the robot is enabled and autonomous or opcontrol + * starts. + */ +void competition_initialize(){} + +/** + * Runs the user autonomous code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the autonomous + * mode. Alternatively, this function may be called in initialize or opcontrol + * for non-competition testing purposes. + * + * If the robot is disabled or communications is lost, the autonomous task + * will be stopped. Re-enabling the robot will restart the task, not re-start it + * from where it left off. + */ +void autonomous(){ + // TEST FUNCTION + profiler->setTarget(2_ft); + chassis->waitUntilSettled(); + profiler->setTarget(90_deg); + chassis->waitUntilSettled(); + profiler->setTarget(-2_ft); + chassis->waitUntilSettled(); +} + +/** + * Runs the operator control code. This function will be started in its own task + * with the default priority and stack size whenever the robot is enabled via + * the Field Management System or the VEX Competition Switch in the operator + * control mode. + * + * If no competition control is connected, this function will run immediately + * following initialize(). + * + * If the robot is disabled or communications is lost, the + * operator control task will be stopped. Re-enabling the robot will restart the + * task, not resume it from where it left off. + */ +void opcontrol(){ + Controller master(ControllerId::master); + auto model = chassis->getModel(); + while(true){ + model->curvature(master.getAnalog(ControllerAnalog::leftY), + master.getAnalog(ControllerAnalog::rightX), + 0.05); + pros::delay(10); + } + +} diff --git a/src/ryanlib/AsyncProfiler.cpp b/src/ryanlib/AsyncProfiler.cpp new file mode 100644 index 0000000..2a2d943 --- /dev/null +++ b/src/ryanlib/AsyncProfiler.cpp @@ -0,0 +1,292 @@ +#include "AsyncProfiler.hpp" + +namespace ryan{ +AsyncMotionProfiler::AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + std::unique_ptr iLeftLinear, + std::unique_ptr iRightLinear, + std::unique_ptr iLeftTrajectory, + std::unique_ptr iRightTrajectory, + const okapi::TimeUtil& iTimeUtil): timeUtil(iTimeUtil) +{ + chassis = std::move(iChassis); + profiler = std::move(iMove); + leftLinear = std::move(iLeftLinear); + rightLinear = std::move(iRightLinear); + leftTrajectory = std::move(iLeftTrajectory); + rightTrajectory = std::move(iRightTrajectory); + rate = std::move(timeUtil.getRate()); + timer = std::move(timeUtil.getTimer()); + linearCustom = true; + trajectoryCustom = true; + + leftMotor = std::move(std::static_pointer_cast(chassis->getModel())->getLeftSideMotor()); + rightMotor = std::move(std::static_pointer_cast(chassis->getModel())->getRightSideMotor()); +} + +AsyncMotionProfiler::AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + const okapi::TimeUtil& iTimeUtil): timeUtil(iTimeUtil){ + chassis = std::move(iChassis); + profiler = std::move(iMove); + rate = std::move(timeUtil.getRate()); + timer = std::move(timeUtil.getTimer()); + + leftMotor = std::move(std::static_pointer_cast(chassis->getModel())->getLeftSideMotor()); + rightMotor = std::move(std::static_pointer_cast(chassis->getModel())->getRightSideMotor()); +} + +AsyncMotionProfiler::AsyncMotionProfiler(std::shared_ptr iChassis, + std::unique_ptr iMove, + std::unique_ptr iLeft, + std::unique_ptr iRight, + bool velFlag, + const okapi::TimeUtil& iTimeUtil): timeUtil(iTimeUtil){ + chassis = std::move(iChassis); + profiler = std::move(iMove); + if(velFlag){ + leftLinear = std::move(iLeft); + rightLinear = std::move(iRight); + linearCustom = true; + } + else{ + leftTrajectory = std::move(iLeft); + rightTrajectory = std::move(iRight); + trajectoryCustom = true; + } + rate = std::move(timeUtil.getRate()); + timer = std::move(timeUtil.getTimer()); + + leftMotor = std::move(std::static_pointer_cast(chassis->getModel())->getLeftSideMotor()); + rightMotor = std::move(std::static_pointer_cast(chassis->getModel())->getRightSideMotor()); +} + +void AsyncMotionProfiler::setConstraint(const ProfileConstraint& iConstraint){ + stop(); + lock.take(5); + profiler->setConstraint(iConstraint); + lock.give(); +} + +void AsyncMotionProfiler::setTarget(okapi::QLength distance, bool waitUntilSettled){ + lock.take(5); + setState(MotionProfileState::MOVE); + profiler->setDistance(distance); + leftMotor->tarePosition(); + rightMotor->tarePosition(); + chassis->getModel()->tank(0, 0); + maxTime = profiler->getTotalTime() + 0.02 * okapi::second; + timer->placeMark(); + lock.give(); + + if(waitUntilSettled){ + this->waitUntilSettled(); + } +} + +void AsyncMotionProfiler::setTarget(const Trajectory& iPath, bool waitUntilSettled){ + lock.take(5); + setState(MotionProfileState::FOLLOW); + leftMotor->tarePosition(); + rightMotor->tarePosition(); + chassis->getModel()->tank(0, 0); + path = iPath; + maxTime = path.size() * 10 * okapi::millisecond + 0.02 * okapi::millisecond; + timer->placeMark(); + lock.give(); + + if(waitUntilSettled){ + this->waitUntilSettled(); + } +} + +void AsyncMotionProfiler::setTarget(okapi::QAngle iAngle, bool waitUntilSettled){ + lock.take(5); + setState(MotionProfileState::TURN); + profiler->setDistance(iAngle.convert(okapi::radian) * chassis->getChassisScales().wheelTrack/2); + leftMotor->tarePosition(); + rightMotor->tarePosition(); + chassis->getModel()->tank(0, 0); + maxTime = profiler->getTotalTime() + 0.02 * okapi::second; + timer->placeMark(); + lock.give(); + + if(waitUntilSettled){ + this->waitUntilSettled(); + } +} + +void AsyncMotionProfiler::stop(){ + lock.take(5); + setState(MotionProfileState::IDLE); + (chassis->getModel())->tank(0, 0); + lock.give(); +} + +void AsyncMotionProfiler::loop(){ + TrajectoryPoint pt; + double leftPower, rightPower; + okapi::EmaFilter lFilter(0.7); + okapi::EmaFilter rFilter(0.7); + + while(true){ + lock.take(5); + okapi::QTime time = timer->getDtFromMark(); + + double leftPos = Math::tickToFt(leftMotor->getPosition(), chassis->getChassisScales(), chassis->getGearsetRatioPair()); + double leftVel = Math::rpmToFtps(leftMotor->getActualVelocity(), chassis->getChassisScales(), chassis->getGearsetRatioPair()); + double rightPos = Math::tickToFt(rightMotor->getPosition(), chassis->getChassisScales(), chassis->getGearsetRatioPair()); + double rightVel = Math::rpmToFtps(rightMotor->getActualVelocity(), chassis->getChassisScales(), chassis->getGearsetRatioPair()); + + std::cout << lFilter.filter(leftVel) << std::endl; + //std::cout << rFilter.filter(rightVel) << std::endl; + //std::cout << leftPos << std::endl; + //std::cout << rightPos << std::endl; + + if(getState() == MotionProfileState::IDLE){ + + } + else if(time > maxTime){ + setState(MotionProfileState::IDLE); + chassis->getModel()->tank(0, 0); + } + else if(getState() == MotionProfileState::MOVE){ + pt = profiler->get(time); + if(linearCustom){ + leftPower = leftLinear->step(pt.leftPosition, pt.leftVelocity, pt.leftAcceleration, leftPos, leftVel); + rightPower = rightLinear->step(pt.rightPosition, pt.rightVelocity, pt.rightAcceleration, rightPos, rightVel); + chassis->getModel()->tank(leftPower, rightPower); + } + else{ + double vel = Math::ftpsToRPM(pt.leftVelocity, chassis->getChassisScales(), chassis->getGearsetRatioPair()); + leftMotor->moveVelocity(vel); + rightMotor->moveVelocity(vel); + } + } + else if(getState() == MotionProfileState::TURN){ + pt = profiler->get(time); + if(linearCustom){ + leftPower = leftLinear->step(pt.leftPosition, pt.leftVelocity, pt.leftAcceleration, leftPos, leftVel); + rightPower = rightLinear->step(-pt.rightPosition, -pt.rightVelocity, -pt.rightAcceleration, rightPos, rightVel); + chassis->getModel()->tank(leftPower, rightPower); + } + else{ + double vel = Math::ftpsToRPM(pt.leftVelocity, chassis->getChassisScales(), chassis->getGearsetRatioPair()); + leftMotor->moveVelocity(vel); + rightMotor->moveVelocity(-vel); + } + } + else if(getState() == MotionProfileState::FOLLOW){ + pt = path[(int)(time.convert(okapi::millisecond) / 10)]; + if(trajectoryCustom){ + leftPower = leftTrajectory->step(pt.leftPosition, pt.leftVelocity, pt.leftAcceleration, leftPos, leftVel); + rightPower = rightTrajectory->step(pt.rightPosition, pt.rightVelocity, pt.rightAcceleration, rightPos, rightVel); + chassis->getModel()->tank(leftPower, rightPower); + } + else{ + double leftVel = Math::ftpsToRPM(pt.leftVelocity, chassis->getChassisScales(), chassis->getGearsetRatioPair()); + double rightVel = Math::ftpsToRPM(pt.rightVelocity, chassis->getChassisScales(), chassis->getGearsetRatioPair()); + leftMotor->moveVelocity(leftVel); + rightMotor->moveVelocity(rightVel); + } + } + + lock.give(); + rate->delayUntil(10); + } +} + +void AsyncMotionProfiler::waitUntilSettled(){ + while(getState() != MotionProfileState::IDLE){ + pros::delay(10); + } +} + +AsyncMotionProfilerBuilder::AsyncMotionProfilerBuilder(){ + linearInit = false; + trajInit = false; + driveInit = false; + profileInit = false; +} + +AsyncMotionProfilerBuilder& AsyncMotionProfilerBuilder::withOutput(std::shared_ptr iChassis){ + chassis = std::move(iChassis); + driveInit = true; + return *this; +} + +AsyncMotionProfilerBuilder& AsyncMotionProfilerBuilder::withProfiler(std::unique_ptr iProfiler){ + profile = std::move(iProfiler); + profileInit = true; + return *this; +} + +AsyncMotionProfilerBuilder& AsyncMotionProfilerBuilder::withLinearController(FFVelocityController iLeft, FFVelocityController iRight){ + leftL = iLeft, rightL = iRight; + linearInit = true; + return *this; + +} + +AsyncMotionProfilerBuilder& AsyncMotionProfilerBuilder::withTrajectoryController(FFVelocityController iLeft, FFVelocityController iRight){ + leftT = iLeft, rightT = iRight; + trajInit = true; + return *this; +} + +std::shared_ptr AsyncMotionProfilerBuilder::build(){ + if(driveInit && profileInit && linearInit && trajInit){ + std::shared_ptr ret(new AsyncMotionProfiler(std::move(chassis), + std::move(profile), + std::make_unique(leftL), + std::make_unique(rightL), + std::make_unique(leftT), + std::make_unique(rightT), + okapi::TimeUtilFactory::createDefault())); + + ret->startTask(); + return std::move(ret); + } + else if(driveInit && profileInit && linearInit){ + std::shared_ptr ret(new AsyncMotionProfiler(std::move(chassis), + std::move(profile), + std::make_unique(leftL), + std::make_unique(rightL), + true, + okapi::TimeUtilFactory::createDefault())); + + ret->startTask(); + return std::move(ret); + } + else if(driveInit && profileInit && trajInit){ + std::shared_ptr ret(new AsyncMotionProfiler(std::move(chassis), + std::move(profile), + std::make_unique(leftT), + std::make_unique(rightT), + false, + okapi::TimeUtilFactory::createDefault())); + + ret->startTask(); + return std::move(ret); + } + else if(driveInit && profileInit){ + std::shared_ptr ret(new AsyncMotionProfiler(std::move(chassis), + std::move(profile), + okapi::TimeUtilFactory::createDefault())); + + ret->startTask(); + return std::move(ret); + } + else{ + throw std::runtime_error("AsyncMotionProfilerBuilder: Not all parameters supplied, failed to build (you need at least a chassis and a profiler"); + } +} + +} + + + + + + + diff --git a/src/ryanlib/FeedForward.cpp b/src/ryanlib/FeedForward.cpp new file mode 100644 index 0000000..f061962 --- /dev/null +++ b/src/ryanlib/FeedForward.cpp @@ -0,0 +1,27 @@ +#include "FeedForward.hpp" + +namespace ryan{ + +FFVelocityController::FFVelocityController(double ikV, double ikAU, double ikAD, double ikP_Pos, double ikP_Vel){ + kV = ikV, kA_Up = ikAU, kA_Down = ikAD, kP_Pos = ikP_Pos, kP_Vel = ikP_Vel; +} + +double FFVelocityController::step(double position, double velocity, double acceleration, double currentPos, double currentVel){ + if(acceleration > 0){ + return power = (kV * velocity + kA_Up * acceleration + kP_Pos * (position - currentPos) + kP_Vel * (velocity - currentVel)); + } + else{ + return power = (kV * velocity + kA_Down * acceleration + kP_Pos * (position - currentPos) + kP_Vel * (velocity - currentVel)); + } +} + +double FFVelocityController::getTargetPower() const{ + return power; +} + +double FFVelocityController::getkV() const{ + return kV; +} + +} + diff --git a/src/ryanlib/LinearMotionProfile.cpp b/src/ryanlib/LinearMotionProfile.cpp new file mode 100644 index 0000000..235ac48 --- /dev/null +++ b/src/ryanlib/LinearMotionProfile.cpp @@ -0,0 +1,394 @@ +#include "LinearMotionProfile.hpp" + +namespace ryan{ + +// Profile Constraint +ProfileConstraint::ProfileConstraint(okapi::QSpeed maxVel, okapi::QAcceleration maxAccel, okapi::QAcceleration maxDecel, okapi::QJerk maxJerk){ + if(maxVel == 0 * okapi::mps){ + throw std::invalid_argument("ProfileConstraint: Max Velocity can't be zero"); + } + else if(maxAccel == 0 * okapi::mps2){ + throw std::invalid_argument("ProfileConstraint: Max Acceleration can't be zero"); + } + else if(maxDecel == 0 * okapi::mps2){ + maxDecel = maxAccel; + } + else if(maxJerk == 0 * okapi::mps3){ + throw std::invalid_argument("ProfileConstraint: Max Jerk can't be zero (choose an arbitrary large number if you want a trapezoidal profile)"); + } + + this->maxVelocity = abs(maxVel); + this->maxAcceleration = abs(maxAccel); + this->maxDeceleration = abs(maxDecel); + this->maxJerk = abs(maxJerk); +} + +ProfileConstraint::ProfileConstraint(okapi::QSpeed maxVel, okapi::QAcceleration maxAccel, okapi::QJerk maxJerk){ + if(maxVel == 0 * okapi::mps){ + throw std::invalid_argument("ProfileConstraint: Max Velocity can't be zero"); + } + else if(maxAccel == 0 * okapi::mps2){ + throw std::invalid_argument("ProfileConstraint: Max Acceleration can't be zero"); + } + else if(maxJerk == 0 * okapi::mps3){ + throw std::invalid_argument("ProfileConstraint: Max Jerk can't be zero (choose an arbitrary large number if you want a trapezoidal profile)"); + } + + this->maxVelocity = abs(maxVel); + this->maxAcceleration = abs(maxAccel); + this->maxDeceleration = abs(maxAccel); + this->maxJerk = abs(maxJerk); +} + + +// Trapezoidal Motion Profile +TrapezoidalMotionProfile::TrapezoidalMotionProfile(ProfileConstraint iConstraint){ + distPhase.resize(3); + timePhase.resize(3); + velPhase.resize(3); + accPhase.resize(3); + setConstraint(iConstraint); +} + +void TrapezoidalMotionProfile::setConstraint(ProfileConstraint iConstraint){ + constraint = iConstraint; + min3Stage = constraint.maxVelocity * constraint.maxVelocity / constraint.maxAcceleration / 2 + + constraint.maxVelocity * constraint.maxVelocity / constraint.maxDeceleration / 2; + accPhase = {constraint.maxAcceleration, 0 * okapi::mps2, -constraint.maxAcceleration}; + setDistance(distance); +} + +void TrapezoidalMotionProfile::setDistance(okapi::QLength iDistance){ + isReversed = (iDistance < 0 * okapi::meter); + distance = abs(iDistance); + + if(distance < min3Stage){ // 2 stage + timePhase[0] = sqrt(distance / constraint.maxAcceleration); + distPhase[0] = distance / 2; + velPhase[0] = 0 * okapi::mps; + + timePhase[1] = 0 * okapi::second; + distPhase[1] = 0 * okapi::meter; + velPhase[1] = timePhase[0] * constraint.maxAcceleration; + + timePhase[2] = timePhase[0]; + distPhase[2] = distPhase[0]; + velPhase[2] = velPhase[1]; + } + else{ // full trapezoidal profile + timePhase[0] = constraint.maxVelocity / constraint.maxAcceleration; + distPhase[0] = 0.5 * constraint.maxVelocity * constraint.maxVelocity / constraint.maxAcceleration; + velPhase[0] = 0 * okapi::mps; + + timePhase[1] = (distance - distPhase[0] * 2) / constraint.maxVelocity; + distPhase[1] = constraint.maxVelocity * timePhase[1]; + velPhase[1] = constraint.maxVelocity; + + timePhase[2] = timePhase[0]; + distPhase[2] = distPhase[0]; + velPhase[2] = velPhase[1]; + } + + for(int i = 1; i < 3; i++){ + timePhase[i] += timePhase[i-1]; + distPhase[i] += distPhase[i-1]; + } +} + +okapi::QTime TrapezoidalMotionProfile::getTotalTime() const{ + return timePhase[2]; +} + +okapi::QSpeed TrapezoidalMotionProfile::getVelocity(okapi::QTime time) const{ + okapi::QSpeed ret; + if(time < 0 * okapi::second || time > timePhase[2]){ + ret = 0 * okapi::mps; + } + else if(time < timePhase[0]){ + ret = constraint.maxAcceleration * time; + } + else if(time > timePhase[1]){ + ret = constraint.maxAcceleration * (timePhase[2] - time); + } + else{ + ret = constraint.maxVelocity; + } + + return isReversed ? -ret : ret; +} + +okapi::QAcceleration TrapezoidalMotionProfile::getAcceleration(okapi::QTime time) const{ + okapi::QAcceleration ret; + if(time < 0 * okapi::second || time > timePhase[2]){ + ret = 0 * okapi::mps2; + } + else if(time < timePhase[0]){ + ret = constraint.maxAcceleration; + } + else if(time > timePhase[1]){ + ret = -1 * constraint.maxAcceleration; + } + else{ + ret = 0 * okapi::mps2; + } + + return isReversed ? -1 * ret : ret; +} + +okapi::QLength TrapezoidalMotionProfile::getPosition(okapi::QTime time) const{ + okapi::QLength ret; + if(time < 0 * okapi::second){ + ret = 0 * okapi::meter; + } + else if(time > timePhase[2]){ + ret = distance; + } + else if(time < timePhase[0]){ + ret = 0.5 * constraint.maxAcceleration * time * time; + } + else if(time > timePhase[1]){ + okapi::QTime dTime = time - timePhase[1]; + ret = distPhase[1] + velPhase[2] * dTime + 0.5 * accPhase[2] * dTime * dTime; + } + else{ + ret = distPhase[0] + constraint.maxVelocity * (time - timePhase[0]); + } + + return isReversed ? -1 * ret : ret; +} + +TrajectoryPoint TrapezoidalMotionProfile::get(okapi::QTime time) const{ + double position = getPosition(time).convert(okapi::foot); + double velocity = getVelocity(time).convert(okapi::ftps); + double acceleration = getAcceleration(time).convert(okapi::ftps2); + + return {position, position, velocity, velocity, acceleration, acceleration}; +} + +// S Curve Motion Profile +SCurveMotionProfile::SCurveMotionProfile(ProfileConstraint iConstraint){ + timePhase.resize(7); + distPhase.resize(7); + velPhase.resize(7); + accPhase.resize(7); + setConstraint(iConstraint); +} + +void SCurveMotionProfile::setConstraint(ProfileConstraint iConstraint){ + constraint = iConstraint; + jerkPhase = {iConstraint.maxJerk, 0 * okapi::mps3, -iConstraint.maxJerk, 0 * okapi::mps3, -iConstraint.maxJerk, 0 * okapi::mps3, iConstraint.maxJerk}; + + okapi::QTime time = constraint.maxAcceleration / constraint.maxJerk; + if(constraint.maxJerk * time * time >= constraint.maxVelocity){ + fullAccel = false; + okapi::QTime t1 = sqrt(constraint.maxVelocity / constraint.maxJerk); + minDist = constraint.maxJerk * t1 * t1 * t1 * 2; + fullDist = minDist; + } + else{ + fullAccel = true; + okapi::QTime t1 = constraint.maxAcceleration / constraint.maxJerk; + minDist = constraint.maxJerk * t1 * t1 * t1 * 2; + + okapi::QTime t2 = (constraint.maxVelocity - (constraint.maxJerk * t1 * t1)) / constraint.maxAcceleration; + fullDist = (0.5 * constraint.maxJerk * t1 * t1) * t2 + 0.5 * (constraint.maxAcceleration) * t2 * t2; + fullDist += constraint.maxVelocity * t1; + fullDist *= 2; + } + + setDistance(distance); +} + +void SCurveMotionProfile::setDistance(okapi::QLength iDistance){ + isReversed = iDistance < 0 * okapi::meter ; + distance = abs(iDistance); + + if(distance < minDist){ // 4 stage + timePhase[1] = timePhase[3] = timePhase[5] = 0 * okapi::second; + timePhase[0] = timePhase[2] = timePhase[4] = timePhase[6] = cbrt(distance / constraint.maxJerk / 2); + + distPhase[0] = distPhase[6] = timePhase[0] * timePhase[0] * timePhase[0] * constraint.maxJerk / 6; + distPhase[1] = distPhase[3] = distPhase[5] = 0 * okapi::meter; + distPhase[2] = distPhase[4] = 0.5 * distance - distPhase[0]; + + velPhase[0] = 0 * okapi::mps; + velPhase[1] = velPhase[2] = velPhase[5] = velPhase[6] = 0.5 * constraint.maxJerk * timePhase[0] * timePhase[0]; + velPhase[3] = velPhase[4] = velPhase[1] * 2; + + accPhase[0] = accPhase[3] = accPhase[4] = 0 * okapi::mps2; + accPhase[1] = accPhase[2] = constraint.maxJerk * timePhase[0]; + accPhase[5] = accPhase[6] = -accPhase[1]; + } + else if(!fullAccel){ // 5 stage + timePhase[0] = timePhase[2] = timePhase[4] = timePhase[6] = sqrt(constraint.maxVelocity / constraint.maxJerk); + timePhase[1] = timePhase[5] = 0 * okapi::second; + timePhase[3] = (distance - constraint.maxVelocity * timePhase[0] * 2) / constraint.maxVelocity; + + distPhase[0] = distPhase[6] = timePhase[0] * timePhase[0] * timePhase[0] * constraint.maxJerk / 6; + distPhase[1] = distPhase[5] = 0 * okapi::meter; + distPhase[2] = distPhase[4] = constraint.maxVelocity * timePhase[0] - distPhase[0]; + distPhase[3] = distance - distPhase[0] * 2 - distPhase[2] * 2; + + velPhase[0] = 0 * okapi::mps; + velPhase[1] = velPhase[2] = velPhase[5] = velPhase[6] = constraint.maxVelocity / 2; + velPhase[3] = velPhase[4] = constraint.maxVelocity; + + accPhase[0] = accPhase[3] = accPhase[4] = 0 * okapi::mps2; + accPhase[1] = accPhase[2] = constraint.maxJerk * timePhase[0]; + accPhase[5] = accPhase[6] = -accPhase[1]; + } + else if(distance < fullDist){ // 6 stage + double a = (constraint.maxAcceleration).convert(okapi::ftps2); + double b = (3 * constraint.maxAcceleration * constraint.maxAcceleration / constraint.maxJerk).convert(okapi::ftps); + double c = (2 * constraint.maxAcceleration * constraint.maxAcceleration * constraint.maxAcceleration / constraint.maxJerk / constraint.maxJerk - distance).convert(okapi::foot); + auto t2Candidate = ryan::Math::quadraticFormula(a, b, c); + + timePhase[0] = timePhase[2] = timePhase[4] = timePhase[6] = constraint.maxAcceleration / constraint.maxJerk; + timePhase[1] = timePhase[5] = std::max(t2Candidate.first, t2Candidate.second) * okapi::second; + timePhase[3] = 0 * okapi::second; + + accPhase[0] = accPhase[3] = accPhase[4] = 0 * okapi::mps2; + accPhase[1] = accPhase[2] = constraint.maxJerk * timePhase[0]; + accPhase[5] = accPhase[6] = -accPhase[1]; + + velPhase[0] = 0 * okapi::mps; + velPhase[1] = velPhase[6] = 0.5 * constraint.maxJerk * timePhase[0] * timePhase[0]; + velPhase[2] = velPhase[5] = velPhase[1] + constraint.maxAcceleration * timePhase[1]; + velPhase[3] = velPhase[4] = velPhase[2] + accPhase[2] * timePhase[2] - 0.5 * constraint.maxJerk * timePhase[2] * timePhase[2]; + + distPhase[0] = distPhase[6] = constraint.maxJerk * timePhase[0] * timePhase[0] * timePhase[0] / 6; + distPhase[1] = distPhase[5] = velPhase[1] * timePhase[1] + 0.5 * accPhase[1] * timePhase[1] * timePhase[1]; + distPhase[2] = distPhase[4] = velPhase[2] * timePhase[2] + 0.5 * accPhase[2] * timePhase[2] * timePhase[2] - constraint.maxJerk * timePhase[2] * timePhase[2] * timePhase[2] / 6; + distPhase[3] = 0 * okapi::meter; + } + else{ // full s curve + velPhase[0] = 0 * okapi::mps; + accPhase[0] = 0 * okapi::mps2; + timePhase[0] = constraint.maxAcceleration / constraint.maxJerk; + distPhase[0] = constraint.maxJerk * timePhase[0] * timePhase[0] * timePhase[0] / 6; + + velPhase[1] = 0.5 * constraint.maxJerk * timePhase[0] * timePhase[0]; + accPhase[1] = constraint.maxAcceleration; + timePhase[1] = (constraint.maxVelocity - velPhase[1]*2) / constraint.maxAcceleration; + distPhase[1] = velPhase[1] * timePhase[1] + 0.5 * accPhase[1] * timePhase[1] * timePhase[1]; + + velPhase[2] = velPhase[1] + accPhase[1] * timePhase[1]; + accPhase[2] = constraint.maxAcceleration; + timePhase[2] = timePhase[0]; + distPhase[2] = velPhase[2] * timePhase[2] + 0.5 * accPhase[2] * timePhase[2] * timePhase[2] - constraint.maxJerk * timePhase[2] * timePhase[2] * timePhase[2] / 6; + + velPhase[3] = constraint.maxVelocity; + accPhase[3] = 0 * okapi::mps2; + timePhase[3] = (distance - 2 * (distPhase[0] + distPhase[1] + distPhase[2])) / constraint.maxVelocity; + distPhase[3] = velPhase[3] * timePhase[3]; + + velPhase[4] = constraint.maxVelocity; + accPhase[4] = 0 * okapi::mps2; + timePhase[4] = timePhase[2]; + distPhase[4] = distPhase[2]; + + velPhase[5] = velPhase[2]; + accPhase[5] = -constraint.maxAcceleration; + timePhase[5] = timePhase[1]; + distPhase[5] = distPhase[1]; + + velPhase[6] = velPhase[1]; + accPhase[6] = -constraint.maxAcceleration; + timePhase[6] = timePhase[0]; + distPhase[6] = distPhase[0]; + } + + for(int i = 1; i < 7; i++){ + timePhase[i] += timePhase[i-1]; + distPhase[i] += distPhase[i-1]; + } +} + +okapi::QTime SCurveMotionProfile::getTotalTime() const{ + return timePhase[6]; +} + +okapi::QLength SCurveMotionProfile::getPosition(okapi::QTime time) const{ + okapi::QLength pos = 0 * okapi::meter; + + if(time < 0 * okapi::second){ + pos = 0 * okapi::meter; + } + else if(time >= timePhase[6]){ + pos = distance; + } + else if(time < timePhase[0]){ + pos = constraint.maxJerk * time * time * time / 6; + } + else{ + int index = 1; + for(int i = 1; i < 7; i++){ + if(time < timePhase[i]){ + index = i; + break; + } + } + okapi::QTime dTime = time - timePhase[index-1]; + pos = distPhase[index-1] + velPhase[index] * dTime + 0.5 * accPhase[index] * dTime * dTime + jerkPhase[index] * dTime * dTime * dTime / 6; + } + + return isReversed ? -pos : pos; +} + +okapi::QSpeed SCurveMotionProfile::getVelocity(okapi::QTime time) const{ + okapi::QSpeed vel = 0 * okapi::mps; + + if(time < 0 * okapi::second || time >= timePhase[6]){ + vel = 0 * okapi::mps; + } + else if(time < timePhase[0]){ + vel = 0.5 * constraint.maxJerk * time * time; + } + else{ + int index = 1; + for(int i = 1; i < 7; i++){ + if(time < timePhase[i]){ + index = i; + break; + } + } + okapi::QTime dTime = time - timePhase[index-1]; + vel = velPhase[index] + accPhase[index] * dTime + jerkPhase[index] * dTime * dTime * 0.5; + } + + return isReversed ? -vel : vel; +} + +okapi::QAcceleration SCurveMotionProfile::getAcceleration(okapi::QTime time) const{ + okapi::QAcceleration acc = 0 * okapi::mps2; + + if(time < 0 * okapi::second || time >= timePhase[6]){ + acc = 0 * okapi::mps2; + } + else if(time < timePhase[0]){ + acc = constraint.maxJerk * time; + } + else{ + int index = 1; + for(int i = 1; i < 7; i++){ + if(time < timePhase[i]){ + index = i; + break; + } + } + okapi::QTime dTime = time - timePhase[index-1]; + acc = accPhase[index] + jerkPhase[index] * dTime; + } + + return isReversed ? -acc : acc; +} + +TrajectoryPoint SCurveMotionProfile::get(okapi::QTime time) const{ + double position = getPosition(time).convert(okapi::foot); + double velocity = getVelocity(time).convert(okapi::ftps); + double acceleration = getAcceleration(time).convert(okapi::ftps2); + + return {position, position, velocity, velocity, acceleration, acceleration}; +} + +} \ No newline at end of file diff --git a/src/ryanlib/Math.cpp b/src/ryanlib/Math.cpp new file mode 100644 index 0000000..1c140e6 --- /dev/null +++ b/src/ryanlib/Math.cpp @@ -0,0 +1,70 @@ +#include "Math.hpp" + +namespace ryan{ + +double Math::deadband(double value, double db){ + if(abs(value) < db){ + return 0; + } + else{ + return value; + } +} + +// vel (ft/s) -> vel(in/s) -> rps(wheel) -> rps -> rpm +double Math::ftpsToRPM(double ftps, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset){ + return ftps * 12 / (scale.wheelDiameter.convert(okapi::inch) * M_PI) * gearset.ratio * 60; +} + +// rpm -> rps -> rps (wheel) -> vel (in/s) -> vel (ft/s) +double Math::rpmToFtps(double rpm, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset){ + return rpm / 60 / gearset.ratio * (scale.wheelDiameter.convert(okapi::inch) * M_PI) / 12; +} + +double Math::ftToTick(double ft, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset){ + return ft * 12 / (scale.wheelDiameter.convert(okapi::inch)*M_PI) * (gearset.ratio) * scale.tpr; +} + +double Math::tickToFt(double tick, okapi::ChassisScales scale, okapi::AbstractMotor::GearsetRatioPair gearset){ + return (tick/scale.tpr)/(gearset.ratio)*(scale.wheelDiameter.convert(okapi::inch)*M_PI)/12; +} + +okapi::QAngle Math::rescale180(okapi::QAngle angle){ + return rescale180(angle.convert(okapi::degree)) * okapi::degree; +} + +double Math::rescale180(double angle){ + return angle - 360.0 * std::floor((angle + 180.0) * (1.0 / 360.0)); +} + +okapi::QAngle Math::rescale360(okapi::QAngle angle){ + return rescale360(angle.convert(okapi::degree)) * okapi::degree; +} + +double Math::rescale360(double angle){ + return angle - 360.0 * (std::floor(angle * (1.0 / 360.0))); +} + +std::pair Math::quadraticFormula(double a, double b, double c){ + double discriminant = b * b - 4 * a * c; + + if(discriminant < 0){ + throw std::runtime_error("Quadratic Formula: No Real Solution!"); + } + else if(abs(discriminant) <= 0.001){ + return {-b / 2 * a, -b / 2 * a}; + } + else{ + double x1 = (-b + sqrt(discriminant)) / (2 * a); + double x2 = (-b - sqrt(discriminant)) / (2 * a); + + return {x1, x2}; + } +} + +int Math::signum(double value){ + return (value > 0) - (value < 0); +} + +} + diff --git a/src/ryanlib/Pneumatics.cpp b/src/ryanlib/Pneumatics.cpp new file mode 100644 index 0000000..5fc8767 --- /dev/null +++ b/src/ryanlib/Pneumatics.cpp @@ -0,0 +1,23 @@ +#include "Pneumatics.hpp" + +namespace ryan{ + +Pneumatics::Pneumatics(char iPort, bool initState):piston(iPort), state(initState){ + piston.set_value(state); +} + +void Pneumatics::toggle(){ + state = !state; + piston.set_value(state); +} + +void Pneumatics::set(bool iState){ + state = iState; + piston.set_value(iState); +} + +bool Pneumatics::getState() const{ + return state; +} + +} \ No newline at end of file diff --git a/src/ryanlib/TaskWrapper.cpp b/src/ryanlib/TaskWrapper.cpp new file mode 100644 index 0000000..2cbd05f --- /dev/null +++ b/src/ryanlib/TaskWrapper.cpp @@ -0,0 +1,38 @@ +#include "TaskWrapper.hpp" + +namespace ryan{ + +TaskWrapper::~TaskWrapper(){ + task->remove(); + task.reset(nullptr); +} + +void TaskWrapper::startTask(const char* iname){ + task = std::move(std::make_unique(trampoline, this, iname)); +} + +void TaskWrapper::pauseTask(){ + task->suspend(); +} + +void TaskWrapper::resumeTask(){ + task->resume(); +} + +void TaskWrapper::stopTask(){ + task->remove(); + task = nullptr; +} + +const char* TaskWrapper::getName(){ + return task->get_name(); +} + +void TaskWrapper::trampoline(void* iparam){ + if(iparam){ + TaskWrapper* that = static_cast(iparam); + that->loop(); + } +} + +} \ No newline at end of file diff --git a/src/ryanlib/Trajectory.cpp b/src/ryanlib/Trajectory.cpp new file mode 100644 index 0000000..58abf83 --- /dev/null +++ b/src/ryanlib/Trajectory.cpp @@ -0,0 +1,30 @@ +#include "Trajectory.hpp" + +namespace ryan{ + +TrajectoryPoint::TrajectoryPoint(double leftP, double rightP, double leftV, double rightV, double leftA, double rightA): +leftPosition(leftP), rightPosition(rightP), leftVelocity(leftV), leftAcceleration(leftA), rightVelocity(rightV), rightAcceleration(rightA){} + +std::ostream& operator<<(std::ostream& os, TrajectoryPoint& pt){ + os << pt.leftPosition << " " << pt.rightPosition << " " << pt.leftVelocity << " " << pt.rightVelocity << " " << pt.leftAcceleration << " " << pt.rightAcceleration; + return os; +} + +Trajectory::Trajectory(const std::initializer_list& iPath): +path(iPath) +{} + +TrajectoryPoint Trajectory::operator[](int index) const{ + if(index < 0 || index >= path.size()){ + return {0, 0, 0, 0, 0, 0}; + } + else{ + return path[index]; + } +} + +int Trajectory::size() const{ + return path.size(); +} + +} \ No newline at end of file