diff --git a/PROS/Makefile b/PROS/Makefile new file mode 100644 index 0000000..4426e1f --- /dev/null +++ b/PROS/Makefile @@ -0,0 +1,134 @@ +################################################################################ +######################### 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 this to 1 to add additional rules to compile your project as a PROS library template +IS_LIBRARY:=0 +# TODO: CHANGE THIS! +LIBNAME:=libbest +VERSION:=1.0.0 +# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c +# this line excludes opcontrol.c and similar files +EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/opcontrol $(SRCDIR)/initialize $(SRCDIR)/autonomous,$(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 + +INCLUDE=-isystem$(INCDIR) + +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)) + +LIBRARIES=-Wl,--start-group $(wildcard $(FWDIR)/*.a) -lm -lgcc -Wl,--end-group +ARCHIVE_TEXT_LIST:=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(wildcard $(FWDIR)/*.a)))) + +ifndef OUTBIN +OUTNAME:=output +endif +OUTBIN:=$(BINDIR)/$(OUTNAME).bin +OUTELF:=$(BINDIR)/$(OUTNAME).elf + +.PHONY: all clean quick + +quick: $(OUTBIN) + +all: clean $(OUTBIN) + +clean: + @echo Cleaning project + -$Drm -rf $(BINDIR) + +upload-legacy: + @java -jar firmware/uniflash.jar vex $(BINDIR)/$(OUTBIN) + +upload: + pros flash -f $(BINDIR)/$(OUTBIN) + + +$(OUTBIN): $(OUTELF) $(BINDIR) + @echo -n "Creating $@ for $(DEVICE) " + $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(OUTELF): $(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) + @echo -n "Linking project with $(ARCHIVE_TEXT_LIST) " + $(call test_output,$D$(LD) $(LDFLAGS) $^ $(LIBRARIES) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +define asm_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) + +define c_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(CC) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CFLAGS) $(EXTRA_CFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) + +define cxx_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(CXX) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CXXFLAGS) $(EXTRA_CXXFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) + + +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)) + @echo -n "Creating $@ " + $(call test_output,$D$(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 +endif diff --git a/PROS/common.mk b/PROS/common.mk new file mode 100644 index 0000000..d32b271 --- /dev/null +++ b/PROS/common.mk @@ -0,0 +1,109 @@ +ARCHTUPLE=arm-none-eabi- +DEVICE=VexCortex + +MFLAGS=-mthumb -mcpu=cortex-m3 -mlittle-endian +CPPFLAGS=-Os +GCCFLAGS=-ffunction-sections -fsigned-char -fomit-frame-pointer -fsingle-precision-constant -fdiagnostics-color + +WARNFLAGS+= + +SPACE := +SPACE += +COMMA := , +LNK_FLAGS = --gc-sections + +ASMFLAGS=$(MFLAGS) $(WARNFLAGS) +CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) -std=gnu99 +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) -fno-exceptions -fno-rtti -felide-constructors $(GCCFLAGS) --std=gnu++11 +LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostartfiles -Wl,-static -Bfirmware -Wl,-u,VectorTable -Wl,-T -Xlinker firmware/cortex.ld $(subst ?%,$(SPACE),$(addprefix -Wl$(COMMA), $(LNK_FLAGS))) +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)gcc +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=\x1b[0m +OK_COLOR=\x1b[32;01m +ERROR_COLOR=\x1b[31;01m +WARN_COLOR=\x1b[33;01m +STEP_COLOR=\x1b[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/echo -e +echo=@$(ECHO) "$2$1$(NO_COLOR)" +echon=@$(ECHO) -n "$2$1$(NO_COLOR)" + +define test_output +@rm -f temp.log temp.errors +$1 2> temp.log || touch temp.errors +@if test -e temp.errors; then $(ECHO) "$(ERROR_STRING)" && cat temp.log; elif test -s temp.log; then $(ECHO) "$(WARN_STRING)" && cat temp.log; else $(ECHO) "$2"; fi; +@if test -e temp.errors; then rm -f temp.log temp.errors && false; fi; +@rm -f temp.log temp.errors +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 + +# 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 - diff --git a/PROS/firmware/STM32F10x.ld b/PROS/firmware/STM32F10x.ld new file mode 100644 index 0000000..28e36ad --- /dev/null +++ b/PROS/firmware/STM32F10x.ld @@ -0,0 +1,100 @@ +/* Memory space definitions */ +MEMORY { + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 384K +} + +/* Higher address of the user mode stack */ +EXTERN ( _estack ); +PROVIDE ( _estack = ORIGIN(RAM) + LENGTH(RAM) ); + +/* This sends all unreferenced IRQHandlers to reset. */ +PROVIDE ( ISR_SWI = 0 ); +PROVIDE ( ISR_IRQ = 0 ); +PROVIDE ( ISR_Prefetch = 0 ); +PROVIDE ( ISR_Abort = 0 ); +PROVIDE ( ISR_FIQ = 0 ); + +PROVIDE ( ISR_NMI = 0 ); +PROVIDE ( ISR_HardFault = 0 ); +PROVIDE ( ISR_MemManage = 0 ); +PROVIDE ( ISR_BusFault = 0 ); +PROVIDE ( ISR_UsageFault = 0 ); + +PROVIDE ( ISR_SVC = 0 ); +PROVIDE ( ISR_DebugMon = 0 ); +PROVIDE ( ISR_PendSV = 0 ); +PROVIDE ( ISR_SysTick = 0 ); + +PROVIDE ( ISR_WWDG = 0 ); +PROVIDE ( ISR_PVD = 0 ); +PROVIDE ( ISR_TAMPER = 0 ); +PROVIDE ( ISR_RTC = 0 ); +PROVIDE ( ISR_FLASH = 0 ); +PROVIDE ( ISR_RCC = 0 ); +PROVIDE ( ISR_EXTI0 = 0 ); +PROVIDE ( ISR_EXTI1 = 0 ); +PROVIDE ( ISR_EXTI2 = 0 ); +PROVIDE ( ISR_EXTI3 = 0 ); +PROVIDE ( ISR_EXTI4 = 0 ); +PROVIDE ( ISR_DMAChannel1 = 0 ); +PROVIDE ( ISR_DMAChannel2 = 0 ); +PROVIDE ( ISR_DMAChannel3 = 0 ); +PROVIDE ( ISR_DMAChannel4 = 0 ); +PROVIDE ( ISR_DMAChannel5 = 0 ); +PROVIDE ( ISR_DMAChannel6 = 0 ); +PROVIDE ( ISR_DMAChannel7 = 0 ); +PROVIDE ( ISR_DMA1_Channel1 = 0 ); +PROVIDE ( ISR_DMA1_Channel2 = 0 ); +PROVIDE ( ISR_DMA1_Channel3 = 0 ); +PROVIDE ( ISR_DMA1_Channel4 = 0 ); +PROVIDE ( ISR_DMA1_Channel5 = 0 ); +PROVIDE ( ISR_DMA1_Channel6 = 0 ); +PROVIDE ( ISR_DMA1_Channel7 = 0 ); +PROVIDE ( ISR_ADC = 0 ); +PROVIDE ( ISR_ADC1_2 = 0 ); +PROVIDE ( ISR_USB_HP_CAN_TX = 0 ); +PROVIDE ( ISR_USB_HP_CAN1_TX = 0 ); +PROVIDE ( ISR_USB_LP_CAN_RX0 = 0 ); +PROVIDE ( ISR_USB_LP_CAN1_RX0 = 0 ); +PROVIDE ( ISR_CAN_RX1 = 0 ); +PROVIDE ( ISR_CAN1_RX1 = 0 ); +PROVIDE ( ISR_CAN_SCE = 0 ); +PROVIDE ( ISR_CAN1_SCE = 0 ); +PROVIDE ( ISR_EXTI9_5 = 0 ); +PROVIDE ( ISR_TIM1_BRK = 0 ); +PROVIDE ( ISR_TIM1_UP = 0 ); +PROVIDE ( ISR_TIM1_TRG_COM = 0 ); +PROVIDE ( ISR_TIM1_CC = 0 ); +PROVIDE ( ISR_TIM2 = 0 ); +PROVIDE ( ISR_TIM3 = 0 ); +PROVIDE ( ISR_TIM4 = 0 ); +PROVIDE ( ISR_I2C1_EV = 0 ); +PROVIDE ( ISR_I2C1_ER = 0 ); +PROVIDE ( ISR_I2C2_EV = 0 ); +PROVIDE ( ISR_I2C2_ER = 0 ); +PROVIDE ( ISR_SPI1 = 0 ); +PROVIDE ( ISR_SPI2 = 0 ); +PROVIDE ( ISR_USART1 = 0 ); +PROVIDE ( ISR_USART2 = 0 ); +PROVIDE ( ISR_USART3 = 0 ); +PROVIDE ( ISR_EXTI15_10 = 0 ); +PROVIDE ( ISR_RTCAlarm = 0 ); +PROVIDE ( ISR_USBWakeUp = 0 ); +PROVIDE ( ISR_TIM8_BRK = 0 ); +PROVIDE ( ISR_TIM8_UP = 0 ); +PROVIDE ( ISR_TIM8_TRG_COM = 0 ); +PROVIDE ( ISR_TIM8_CC = 0 ); +PROVIDE ( ISR_ADC3 = 0 ); +PROVIDE ( ISR_FSMC = 0 ); +PROVIDE ( ISR_SDIO = 0 ); +PROVIDE ( ISR_TIM5 = 0 ); +PROVIDE ( ISR_SPI3 = 0 ); +PROVIDE ( ISR_UART4 = 0 ); +PROVIDE ( ISR_UART5 = 0 ); +PROVIDE ( ISR_TIM6 = 0 ); +PROVIDE ( ISR_TIM7 = 0 ); +PROVIDE ( ISR_DMA2_Channel1 = 0 ); +PROVIDE ( ISR_DMA2_Channel2 = 0 ); +PROVIDE ( ISR_DMA2_Channel3 = 0 ); +PROVIDE ( ISR_DMA2_Channel4_5 = 0 ); diff --git a/PROS/firmware/cortex.ld b/PROS/firmware/cortex.ld new file mode 100644 index 0000000..8c800b9 --- /dev/null +++ b/PROS/firmware/cortex.ld @@ -0,0 +1,123 @@ +/* Include STM32F10X linker scripts */ +INCLUDE "STM32F10x.ld" + +EXTERN ( _heapbegin ); + +/* Section definitions for Cortex firmware flashing */ +SECTIONS { + .isr_vector : { + /* startup code, prevents garbage collection from eating everything */ + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH + .text : { + . = ALIGN(4); + *(.text) + *(.text.*) + /* Preinit array of functions */ + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + . = ALIGN(4); + /* Init array of functions */ + KEEP(*(.init)) + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + . = ALIGN(4); + /* C++ constructors */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + . = ALIGN(4); + /* Finalizer array of functions */ + KEEP(*(.fini)) + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + . = ALIGN(4); + /* C++ destructors */ + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + _etext = .; + _srdata = .; + . = ALIGN(4); + *(.rodata) + *(.rodata*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); + _erdata = .; + _sidata = .; + } >FLASH + /* The program executes knowing that the data is in the RAM, but the loader puts the + * initial values in the FLASH (inidata). The startup copies the initial values over */ + .data : AT ( _sidata ) { + . = ALIGN(4); + _sdata = .; + *(.data) + *(.data.*) + *(.RAMtext) + . = ALIGN(4); + _edata = .; + } >RAM + /* Uninitialized data (zero-fill) section */ + .bss : { + . = ALIGN(4); + _sbss = .; + *(.bss) + *(COMMON) + . = ALIGN(4); + _ebss = .; + . = ALIGN(8); + _heapbegin = .; + } >RAM + + /DISCARD/ : { + libc.a ( * ) + libg.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + libstdc++.a ( * ) + libsupc++.a ( * ) + } + /* ARM exception unwinding, mandated by ARM EABI C++ standard (with -fno-exceptions?) */ + .ARM.exidx 0 : { *(.ARM.exidx*) } + /* Stabs debugging sections */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/PROS/firmware/libpros.a b/PROS/firmware/libpros.a new file mode 100644 index 0000000..6063041 Binary files /dev/null and b/PROS/firmware/libpros.a differ diff --git a/PROS/firmware/uniflash.jar b/PROS/firmware/uniflash.jar new file mode 100644 index 0000000..80ba9b0 Binary files /dev/null and b/PROS/firmware/uniflash.jar differ diff --git a/PROS/include/API.h b/PROS/include/API.h new file mode 100644 index 0000000..e9bb2ae --- /dev/null +++ b/PROS/include/API.h @@ -0,0 +1,1623 @@ +/** @file API.h + * @brief Provides the high-level user functionality intended for use by typical VEX Cortex + * programmers. + * + * This file should be included for you in the predefined stubs in each new VEX Cortex PROS + * project through the inclusion of "main.h". In any new C source file, it is advisable to + * include main.h instead of referencing API.h by name, to better handle any nomenclature + * changes to this file or its contents. + * + * Copyright (c) 2011-2018, 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/. + * + * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be + * obtained from http://sourceforge.net/projects/freertos/files/ or on request. + */ + +#ifndef API_H_ +#define API_H_ + +// System includes +#include +#include +#include +#include + +// Begin C++ extern to C +#ifdef __cplusplus +extern "C" { +#endif + +#define PROS_VERSION_MAJOR 2 +#define PROS_VERSION_MINOR 12 +#define PROS_VERSION_PATCH 2 +#define PROS_VERSION_STRING "2.12.2" + +// -------------------- VEX competition functions -------------------- + +/** + * DOWN button (valid on channels 5, 6, 7, 8) + */ +#define JOY_DOWN 1 +/** + * LEFT button (valid on channels 7, 8) + */ +#define JOY_LEFT 2 +/** + * UP button (valid on channels 5, 6, 7, 8) + */ +#define JOY_UP 4 +/** + * RIGHT button (valid on channels 7, 8) + */ +#define JOY_RIGHT 8 +/** + * Analog axis for the X acceleration from the VEX Joystick. + */ +#define ACCEL_X 5 +/** + * Analog axis for the Y acceleration from the VEX Joystick. + */ +#define ACCEL_Y 6 + +/** + * Returns true if the robot is in autonomous mode, or false otherwise. + * + * While in autonomous mode, joystick inputs will return a neutral value, but serial port + * communications (even over VexNET) will still work properly. + */ +bool isAutonomous(); +/** + * Returns true if the robot is enabled, or false otherwise. + * + * While disabled via the VEX Competition Switch or VEX Field Controller, motors will not + * function. However, the digital I/O ports can still be changed, which may indirectly affect + * the robot state (e.g. solenoids). Avoid performing externally visible actions while + * disabled (the kernel should take care of this most of the time). + */ +bool isEnabled(); +/** + * Returns true if a joystick is connected to the specified slot number (1 or 2), or false + * otherwise. + * + * Useful for automatically merging joysticks for one operator, or splitting for two. This + * function does not work properly during initialize() or initializeIO() and can return false + * positives. It should be checked once and stored at the beginning of operatorControl(). + * + * @param joystick the joystick slot to check + */ +bool isJoystickConnected(unsigned char joystick); +/** + * Returns true if a VEX field controller or competition switch is connected, or false + * otherwise. + * + * When in online mode, the switching between autonomous() and operatorControl() tasks is + * managed by the PROS kernel. + */ +bool isOnline(); +/** + * Gets the value of a control axis on the VEX joystick. Returns the value from -127 to 127, + * or 0 if no joystick is connected to the requested slot. + * + * @param joystick the joystick slot to check + * @param axis one of 1, 2, 3, 4, ACCEL_X, or ACCEL_Y + */ +int joystickGetAnalog(unsigned char joystick, unsigned char axis); +/** + * Gets the value of a button on the VEX joystick. Returns true if that button is pressed, or + * false otherwise. If no joystick is connected to the requested slot, returns false. + * + * @param joystick the joystick slot to check + * @param buttonGroup one of 5, 6, 7, or 8 to request that button as labelled on the joystick + * @param button one of JOY_UP, JOY_DOWN, JOY_LEFT, or JOY_RIGHT; requesting JOY_LEFT or + * JOY_RIGHT for groups 5 or 6 will cause an undefined value to be returned + */ +bool joystickGetDigital(unsigned char joystick, unsigned char buttonGroup, + unsigned char button); +/** + * Returns the backup battery voltage in millivolts. + * + * If no backup battery is connected, returns 0. + */ +unsigned int powerLevelBackup(); +/** + * Returns the main battery voltage in millivolts. + * + * In rare circumstances, this method might return 0. Check the output value for reasonability + * before blindly blasting the user. + */ +unsigned int powerLevelMain(); +/** + * Sets the team name displayed to the VEX field control and VEX Firmware Upgrade. + * + * @param name a string containing the team name; only the first eight characters will be shown + */ +void setTeamName(const char *name); + +// -------------------- Pin control functions -------------------- + +/** + * There are 8 available analog I/O on the Cortex. + */ +#define BOARD_NR_ADC_PINS 8 +/** + * There are 27 available I/O on the Cortex that can be used for digital communication. + * + * This excludes the crystal ports but includes the Communications, Speaker, and Analog ports. + * + * The motor ports are not on the Cortex and are thus excluded from this count. Pin 0 is the + * Speaker port, pins 1-12 are the standard Digital I/O, 13-20 are the Analog I/O, 21+22 are + * UART1, 23+24 are UART2, and 25+26 are the I2C port. + */ +#define BOARD_NR_GPIO_PINS 27 +/** + * Used for digitalWrite() 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 digitalWrite() 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 + +/** + * pinMode() state for digital input, with pullup. + * + * This is the default state for the 12 Digital pins. The pullup causes the input to read as + * "HIGH" when unplugged, but is fairly weak and can safely be driven by most sources. Many VEX + * digital sensors rely on this behavior and cannot be used with INPUT_FLOATING. + */ +#define INPUT 0x0A +/** + * pinMode() state for analog inputs. + * + * This is the default state for the 8 Analog pins and the Speaker port. This only works on + * pins with analog input capabilities; use anywhere else results in undefined behavior. + */ +#define INPUT_ANALOG 0x00 +/** + * pinMode() state for digital input, without pullup. + * + * Beware of power consumption, as digital inputs left "floating" may switch back and forth + * and cause spurious interrupts. + */ +#define INPUT_FLOATING 0x04 +/** + * pinMode() state for digital output, push-pull. + * + * This is the mode which should be used to output a digital HIGH or LOW value from the Cortex. + * This mode is useful for pneumatic solenoid valves and VEX LEDs. + */ +#define OUTPUT 0x01 +/** + * pinMode() state for open-drain outputs. + * + * This is useful in a few cases for external electronics and should not be used for the VEX + * solenoid or LEDs. + */ +#define OUTPUT_OD 0x05 + +/** + * Calibrates the analog sensor on the specified channel. + * + * 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 + * analogReadCalibrated() and analogReadCalibratedHR() functions. These functions will return + * the difference between this value and the current sensor value when called. + * + * Do not use this function in initializeIO(), or when the sensor value might be unstable + * (gyro rotation, accelerometer movement). + * + * This function may not work properly if the VEX Cortex is tethered to a PC using the orange + * USB A to A cable and has no VEX 7.2V Battery connected and powered on, as the VEX Battery + * provides power to sensors. + * + * @param channel the channel to calibrate from 1-8 + * @return the average sensor value computed by this function + */ +int analogCalibrate(unsigned char channel); +/** + * Reads an analog input channel and returns the 12-bit value. + * + * The value returned is undefined if the analog pin has been switched to a different mode. + * This function is Wiring-compatible with the exception of the larger output range. The + * meaning of the returned value varies depending on the sensor attached. + * + * This function may not work properly if the VEX Cortex is tethered to a PC using the orange + * USB A to A cable and has no VEX 7.2V Battery connected and powered on, as the VEX Battery + * provides power to sensors. + * + * @param channel the channel to read from 1-8 + * @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 + */ +int analogRead(unsigned char channel); +/** + * Reads the calibrated value of an analog input channel. + * + * The analogCalibrate() function must be run first on that channel. This function is + * inappropriate for sensor values intended for integration, as round-off error can accumulate + * causing drift over time. Use analogReadCalibratedHR() instead. + * + * This function may not work properly if the VEX Cortex is tethered to a PC using the orange + * USB A to A cable and has no VEX 7.2V Battery connected and powered on, as the VEX Battery + * provides power to sensors. + * + * @param channel the channel to read from 1-8 + * @return the difference of the sensor value from its calibrated default from -4095 to 4095 + */ +int analogReadCalibrated(unsigned char channel); +/** + * Reads the calibrated value of an analog input channel 1-8 with enhanced precision. + * + * The analogCalibrate() 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 errors induced by the average value being between two values come out + * in the wash when integrated over time. Think of the value as the true value times 16. + * + * This function may not work properly if the VEX Cortex is tethered to a PC using the orange + * USB A to A cable and has no VEX 7.2V Battery connected and powered on, as the VEX Battery + * provides power to sensors. + * + * @param channel the channel to read from 1-8 + * @return the difference of the sensor value from its calibrated default from -16384 to 16384 + */ +int analogReadCalibratedHR(unsigned char channel); +/** + * Gets the digital value (1 or 0) of a pin configured as a digital input. + * + * If the pin is configured as some other mode, the digital value which reflects the current + * state of the pin is returned, which may or may not differ from the currently set value. The + * return value is undefined for pins configured as Analog inputs, or for ports in use by a + * Communications interface. This function is Wiring-compatible. + * + * This function may not work properly if the VEX Cortex is tethered to a PC using the orange + * USB A to A cable and has no VEX 7.2V Battery connected and powered on, as the VEX Battery + * provides power to sensors. + * + * @param pin the pin to read from 1-26 + * @return true if the pin is HIGH, or false if it is LOW + */ +bool digitalRead(unsigned char pin); +/** + * Sets the digital value (1 or 0) of a pin configured as a digital output. + * + * If the pin is configured as some other mode, behavior is undefined. This function is + * Wiring-compatible. + * + * @param pin the pin to write from 1-26 + * @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 + */ +void digitalWrite(unsigned char pin, bool value); +/** + * Configures the pin as an input or output with a variety of settings. + * + * Do note that INPUT by default turns on the pull-up resistor, as most VEX sensors are + * open-drain active low. It should not be a big deal for most push-pull sources. This function + * is Wiring-compatible. + * + * @param pin the pin to modify from 1-26 + * @param mode one of INPUT, INPUT_ANALOG, INPUT_FLOATING, OUTPUT, or OUTPUT_OD + */ +void pinMode(unsigned char pin, unsigned char mode); + +/* + * Digital port 10 cannot be used as an interrupt port, or for an encoder. Plan accordingly. + */ + +/** + * When used in ioSetInterrupt(), triggers an interrupt on rising edges (LOW to HIGH). + */ +#define INTERRUPT_EDGE_RISING 1 +/** + * When used in ioSetInterrupt(), triggers an interrupt on falling edges (HIGH to LOW). + */ +#define INTERRUPT_EDGE_FALLING 2 +/** + * When used in ioSetInterrupt(), triggers an interrupt on both rising and falling edges + * (LOW to HIGH or HIGH to LOW). + */ +#define INTERRUPT_EDGE_BOTH 3 +/** + * Type definition for interrupt handlers. Such functions must accept one argument indicating + * the pin which changed. + */ +typedef void (*InterruptHandler)(unsigned char pin); + +/** + * Disables interrupts on the specified pin. + * + * Disabling interrupts on interrupt pins which are not in use conserves processing time. + * + * @param pin the pin on which to reset interrupts from 1-9,11-12 + */ +void ioClearInterrupt(unsigned char pin); +/** + * Sets up an interrupt to occur on the specified pin, and resets any counters or timers + * associated with the pin. + * + * Each time the specified change occurs, the function pointer passed in will be called with + * the pin that changed as an argument. Enabling pin-change interrupts consumes processing + * time, so it is best to only enable necessary interrupts and to keep the InterruptHandler + * function short. Pin change interrupts can only be enabled on pins 1-9 and 11-12. + * + * Do not use API functions such as delay() inside the handler function, as the function will + * run in an ISR where the scheduler is paused and no other interrupts can execute. It is best + * to quickly update some state and allow a task to perform the work. + * + * Do not use this function on pins that are also being used by the built-in ultrasonic or + * shaft encoder drivers, or on pins which have been switched to output mode. + * + * @param pin the pin on which to enable interrupts from 1-9,11-12 + * @param edges one of INTERRUPT_EDGE_RISING, INTERRUPT_EDGE_FALLING, or INTERRUPT_EDGE_BOTH + * @param handler the function to call when the condition is satisfied + */ +void ioSetInterrupt(unsigned char pin, unsigned char edges, InterruptHandler handler); + +// -------------------- Physical output control functions -------------------- + +/** + * Gets the last set speed of the specified motor channel. + * + * This speed may have been set by any task or the PROS kernel itself. This is not guaranteed + * to be the speed that the motor is actually running at, or even the speed currently being + * sent to the motor, due to latency in the Motor Controller 29 protocol and physical loading. + * To measure actual motor shaft revolution speed, attach a VEX Integrated Motor Encoder or + * VEX Quadrature Encoder and use the velocity functions associated with each. + * + * @param channel the motor channel to fetch from 1-10 + * @return the speed last sent to this channel; -127 is full reverse and 127 is full forward, + * with 0 being off + */ +int motorGet(unsigned char channel); +/** + * Sets the speed of the specified motor channel. + * + * Do not use motorSet() with the same channel argument from two different tasks. It is safe to + * use motorSet() with different channel arguments from different tasks. + * + * @param channel the motor channel to modify from 1-10 + * @param speed the new signed speed; -127 is full reverse and 127 is full forward, with 0 + * being off + */ +void motorSet(unsigned char channel, int speed); +/** + * Stops the motor on the specified channel, equivalent to calling motorSet() with an argument + * of zero. + * + * This performs a coasting stop, not an active brake. Since motorStop is similar to + * motorSet(0), see the note for motorSet() about use from multiple tasks. + * + * @param channel the motor channel to stop from 1-10 + */ +void motorStop(unsigned char channel); +/** + * Stops all motors; significantly faster than looping through all motor ports and calling + * motorSet(channel, 0) on each one. + */ +void motorStopAll(); + +/** + * Initializes VEX speaker support. + * + * The VEX speaker is not thread safe; it can only be used from one task at a time. Using the + * VEX speaker may impact robot performance. Teams may benefit from an if statement that only + * enables sound if isOnline() returns false. + */ +void speakerInit(); +/** + * Plays up to three RTTTL (Ring Tone Text Transfer Language) songs simultaneously over the + * VEX speaker. The audio is mixed to allow polyphonic sound to be played. Many simple songs + * are available in RTTTL format online, or compose your own. + * + * The song must not be NULL, but unused tracks within the song can be set to NULL. If any of + * the three song tracks is invalid, the result of this function is undefined. + * + * The VEX speaker is not thread safe; it can only be used from one task at a time. Using the + * VEX speaker may impact robot performance. Teams may benefit from an if statement that only + * enables sound if isOnline() returns false. + * + * @param songs an array of up to three (3) RTTTL songs as string values to play + */ +void speakerPlayArray(const char * * songs); +/** + * Plays an RTTTL (Ring Tone Text Transfer Language) song over the VEX speaker. Many simple + * songs are available in RTTTL format online, or compose your own. + * + * The song must not be NULL. If an invalid song is specified, the result of this function is + * undefined. + * + * The VEX speaker is not thread safe; it can only be used from one task at a time. Using the + * VEX speaker may impact robot performance. Teams may benefit from an if statement that only + * enables sound if isOnline() returns false. + * + * @param song the RTTTL song as a string value to play + */ +void speakerPlayRtttl(const char *song); +/** + * Powers down and disables the VEX speaker. + * + * If a song is currently being played in another task, the behavior of this function is + * undefined, since the VEX speaker is not thread safe. + */ +void speakerShutdown(); + +// -------------------- VEX sensor control functions -------------------- + +/** + * IME addresses end at 0x1F. Actually using more than 10 (address 0x1A) encoders will cause + * unreliable communications. + */ +#define IME_ADDR_MAX 0x1F + +/** + * Initializes all IMEs. + * + * IMEs are assigned sequential incrementing addresses, beginning with the first IME on the + * chain (closest to the VEX Cortex I2C port). Therefore, a given configuration of IMEs will + * always have the same ID assigned to each encoder. The addresses range from 0 to + * IME_ADDR_MAX, so the first encoder gets 0, the second gets 1, ... + * + * This function should most likely be used in initialize(). Do not use it in initializeIO() or + * at any other time when the scheduler is paused (like an interrupt). Checking the return + * value of this function is important to ensure that all IMEs are plugged in and responding as + * expected. + * + * This function, unlike the other IME functions, is not thread safe. If using imeInitializeAll + * to re-initialize encoders, calls to other IME functions might behave unpredictably during + * this function's execution. + * + * @return the number of IMEs successfully initialized. + */ +unsigned int imeInitializeAll(); +/** + * Gets the current 32-bit count of the specified IME. + * + * Much like the count for a quadrature encoder, the tick count is signed and cumulative. + * The value reflects total counts since the last reset. Different VEX Motor Encoders have a + * different number of counts per revolution: + * + * * \c 240.448 for the 269 IME + * * \c 627.2 for the 393 IME in high torque mode (factory default) + * * \c 392 for the 393 IME in high speed mode + * + * If the IME address is invalid, or the IME has not been reset or initialized, the value + * stored in *value is undefined. + * + * @param address the IME address to fetch from 0 to IME_ADDR_MAX + * @param value a pointer to the location where the value will be stored (obtained using the + * "&" operator on the target variable name e.g. imeGet(2, &counts)) + * @return true if the count was successfully read and the value stored in *value is valid; + * false otherwise + */ +bool imeGet(unsigned char address, int *value); +/** + * Gets the current rotational velocity of the specified IME. + * + * In this version of PROS, the velocity is positive if the IME count is increasing and + * negative if the IME count is decreasing. The velocity is in RPM of the internal encoder + * wheel. Since checking the IME for its type cannot reveal whether the motor gearing is + * high speed or high torque (in the 2-Wire Motor 393 case), the user must divide the return + * value by the number of output revolutions per encoder revolution: + * + * * \c 30.056 for the 269 IME + * * \c 39.2 for the 393 IME in high torque mode (factory default) + * * \c 24.5 for the 393 IME in high speed mode + * + * If the IME address is invalid, or the IME has not been reset or initialized, the value + * stored in *value is undefined. + * + * @param address the IME address to fetch from 0 to IME_ADDR_MAX + * @param value a pointer to the location where the value will be stored (obtained using the + * "&" operator on the target variable name e.g. imeGetVelocity(2, &counts)) + * @return true if the velocity was successfully read and the value stored in *value is valid; + * false otherwise + */ +bool imeGetVelocity(unsigned char address, int *value); +/** + * Resets the specified IME's counters to zero. + * + * This method can be used while the IME is rotating. + * + * @param address the IME address to reset from 0 to IME_ADDR_MAX + * @return true if the reset succeeded; false otherwise + */ +bool imeReset(unsigned char address); +/** + * Shuts down all IMEs on the chain; their addresses return to the default and the stored + * counts and velocities are lost. This function, unlike the other IME functions, is not + * thread safe. + * + * To use the IME chain again, wait at least 0.25 seconds before using imeInitializeAll again. + */ +void imeShutdown(); + +/** + * Reference type for an initialized gyro. + * + * Gyro information is stored as an opaque pointer to a structure in memory; as this is a + * pointer type, it can be safely passed or stored by value. + */ +typedef void * Gyro; + +/** + * Gets the current gyro angle in degrees, rounded to the nearest degree. + * + * There are 360 degrees in a circle. + * + * @param gyro the Gyro object from gyroInit() to read + * @return the signed and cumulative number of degrees rotated around the gyro's vertical axis + * since the last start or reset + */ +int gyroGet(Gyro gyro); +/** + * Initializes and enables a gyro on an analog port. + * + * NULL will be returned if the port is invalid or the gyro is already in use. Initializing a + * gyro implicitly calibrates it and resets its count. Do not move the robot while the gyro is + * being calibrated. It is suggested to call this function in initialize() and to place the + * robot in its final position before powering it on. + * + * The multiplier parameter can tune the gyro to adapt to specific sensors. The default value + * at this time is 196; higher values will increase the number of degrees reported for a fixed + * actual rotation, while lower values will decrease the number of degrees reported. If your + * robot is consistently turning too far, increase the multiplier, and if it is not turning + * far enough, decrease the multiplier. + * + * @param port the analog port to use from 1-8 + * @param multiplier an optional constant to tune the gyro readings; use 0 for the default + * value + * @return a Gyro object to be stored and used for later calls to gyro functions + */ +Gyro gyroInit(unsigned char port, unsigned short multiplier); +/** + * Resets the gyro to zero. + * + * It is safe to use this method while a gyro is enabled. It is not necessary to call this + * method before stopping or starting a gyro. + * + * @param gyro the Gyro object from gyroInit() to reset + */ +void gyroReset(Gyro gyro); +/** + * Stops and disables the gyro. + * + * Gyros use processing power, so disabling unused gyros increases code performance. + * The gyro's position will be retained. + * + * @param gyro the Gyro object from gyroInit() to stop + */ +void gyroShutdown(Gyro gyro); + +/** + * Reference type for an initialized encoder. + * + * Encoder information is stored as an opaque pointer to a structure in memory; as this is a + * pointer type, it can be safely passed or stored by value. + */ +typedef void * Encoder; +/** + * Gets the number of ticks recorded by the encoder. + * + * There are 360 ticks in one revolution. + * + * @param enc the Encoder object from encoderInit() to read + * @return the signed and cumulative number of counts since the last start or reset + */ +int encoderGet(Encoder enc); +/** + * Initializes and enables a quadrature encoder on two digital ports. + * + * Neither the top port nor the bottom port can be digital port 10. NULL will be returned if + * either port is invalid or the encoder is already in use. Initializing an encoder implicitly + * resets its count. + * + * @param portTop the "top" wire from the encoder sensor with the removable cover side UP + * @param portBottom the "bottom" wire from the encoder sensor + * @param reverse if "true", the sensor will count in the opposite direction + * @return an Encoder object to be stored and used for later calls to encoder functions + */ +Encoder encoderInit(unsigned char portTop, unsigned char portBottom, bool reverse); +/** + * Resets the encoder 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. + * + * @param enc the Encoder object from encoderInit() to reset + */ +void encoderReset(Encoder enc); +/** + * Stops and disables the encoder. + * + * Encoders use processing power, so disabling unused encoders increases code performance. + * The encoder's count will be retained. + * + * @param enc the Encoder object from encoderInit() to stop + */ +void encoderShutdown(Encoder enc); + +/** + * This value is returned if the sensor cannot find a reasonable value to return. + */ +#define ULTRA_BAD_RESPONSE -1 + +/** + * Reference type for an initialized ultrasonic sensor. + * + * Ultrasonic information is stored as an opaque pointer to a structure in memory; as this is a + * pointer type, it can be safely passed or stored by value. + */ +typedef void * Ultrasonic; +/** + * Gets the current ultrasonic sensor value in centimeters. + * + * If no object was found or if the ultrasonic sensor is polled while it is pinging and waiting + * for a response, -1 (ULTRA_BAD_RESPONSE) 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. + * + * @param ult the Ultrasonic object from ultrasonicInit() to read + * @return the distance to the nearest object in centimeters + */ +int ultrasonicGet(Ultrasonic ult); +/** + * Initializes an ultrasonic sensor on the specified digital ports. + * + * The ultrasonic sensor will be polled in the background in concert with the other sensors + * registered using this method. NULL will be returned if either port is invalid or the + * ultrasonic sensor port is already in use. + * + * @param portEcho the port connected to the orange cable from 1-9,11-12 + * @param portPing the port connected to the yellow cable from 1-12 + * @return an Ultrasonic object to be stored and used for later calls to ultrasonic functions + */ +Ultrasonic ultrasonicInit(unsigned char portEcho, unsigned char portPing); +/** + * Stops and disables the ultrasonic sensor. + * + * The last distance it had before stopping will be retained. One more ping operation may occur + * before the sensor is fully disabled. + * + * @param ult the Ultrasonic object from ultrasonicInit() to stop + */ +void ultrasonicShutdown(Ultrasonic ult); + +// -------------------- Custom sensor control functions -------------------- + +// ---- I2C port control ---- +/** + * i2cRead - Reads the specified number of data bytes from the specified 7-bit I2C address. The + * bytes will be stored at the specified location. Returns true if successful or false if + * failed. If only some bytes could be read, false is still returned. + * + * The I2C address should be right-aligned; the R/W bit is automatically supplied. + * + * Since most I2C devices use an 8-bit register architecture, this method has limited + * usefulness. Consider i2cReadRegister instead for the vast majority of applications. + */ +bool i2cRead(uint8_t addr, uint8_t *data, uint16_t count); +/** + * i2cReadRegister - Reads the specified amount of data from the given register address on + * the specified 7-bit I2C address. Returns true if successful or false if failed. If only some + * bytes could be read, false is still returned. + * + * The I2C address should be right-aligned; the R/W bit is automatically supplied. + * + * Most I2C devices support an auto-increment address feature, so using this method to read + * more than one byte will usually read a block of sequential registers. Try to merge reads to + * separate registers into a larger read using this function whenever possible to improve code + * reliability, even if a few intermediate values need to be thrown away. + */ +bool i2cReadRegister(uint8_t addr, uint8_t reg, uint8_t *value, uint16_t count); +/** + * i2cWrite - Writes the specified number of data bytes to the specified 7-bit I2C address. + * Returns true if successful or false if failed. If only smoe bytes could be written, false + * is still returned. + * + * The I2C address should be right-aligned; the R/W bit is automatically supplied. + * + * Since most I2C devices use an 8-bit register architecture, this method is mostly useful for + * setting the register position (most devices remember the last-used address) or writing a + * sequence of bytes to one register address using an auto-increment feature. In these cases, + * the first byte written from the data buffer should have the register address to use. + */ +bool i2cWrite(uint8_t addr, uint8_t *data, uint16_t count); +/** + * i2cWriteRegister - Writes the specified data byte to a register address on the specified + * 7-bit I2C address. Returns true if successful or false if failed. + * + * The I2C address should be right-aligned; the R/W bit is automatically supplied. + * + * Only one byte can be written to each register address using this method. While useful for + * the vast majority of I2C operations, writing multiple bytes requires the i2cWrite method. + */ +bool i2cWriteRegister(uint8_t addr, uint8_t reg, uint16_t value); + +/** + * PROS_FILE is an integer referring to a stream for the standard I/O functions. + * + * PROS_FILE * is the standard library method of referring to a file pointer, even though there is + * actually nothing there. + */ +typedef int PROS_FILE; + + +#ifndef FILE +/** + * For convenience, FILE is defined as PROS_FILE if it wasn't already defined. This provides + * backwards compatability with PROS, but also allows libraries such as newlib to be incorporated + * into PROS projects. If you're not using C++/newlib, you can disregard this and just use FILE. + */ +#define FILE PROS_FILE +#endif + +/** + * Bit mask for usartInit() for 8 data bits (typical) + */ +#define SERIAL_DATABITS_8 0x0000 +/** + * Bit mask for usartInit() for 9 data bits + */ +#define SERIAL_DATABITS_9 0x1000 +/** + * Bit mask for usartInit() for 1 stop bit (typical) + */ +#define SERIAL_STOPBITS_1 0x0000 +/** + * Bit mask for usartInit() for 2 stop bits + */ +#define SERIAL_STOPBITS_2 0x2000 +/** + * Bit mask for usartInit() for No parity (typical) + */ +#define SERIAL_PARITY_NONE 0x0000 +/** + * Bit mask for usartInit() for Even parity + */ +#define SERIAL_PARITY_EVEN 0x0400 +/** + * Bit mask for usartInit() for Odd parity + */ +#define SERIAL_PARITY_ODD 0x0600 +/** + * Specifies the default serial settings when used in usartInit() + */ +#define SERIAL_8N1 0x0000 + +/** + * Initialize the specified serial interface with the given connection parameters. + * + * I/O to the port is accomplished using the "standard" I/O functions such as fputs(), + * fprintf(), and fputc(). + * + * Re-initializing an open port may cause loss of data in the buffers. This routine may be + * safely called from initializeIO() or when the scheduler is paused. If I/O is attempted on a + * serial port which has never been opened, the behavior will be the same as if the port had + * been disabled. + * + * @param usart the port to open, either "uart1" or "uart2" + * @param baud the baud rate to use from 2400 to 1000000 baud + * @param flags a bit mask combination of the SERIAL_* flags specifying parity, stop, and data + * bits + */ +void usartInit(PROS_FILE *usart, unsigned int baud, unsigned int flags); +/** + * Disables the specified USART interface. + * + * Any data in the transmit and receive buffers will be lost. Attempts to read from the port + * when it is disabled will deadlock, and attempts to write to it may deadlock depending on + * the state of the buffer. + * + * @param usart the port to close, either "uart1" or "uart2" + */ +void usartShutdown(PROS_FILE *usart); + +// -------------------- Character input and output -------------------- + +/** + * The standard output stream uses the PC debug terminal. + */ +#define stdout ((PROS_FILE *)3) +/** + * The standard input stream uses the PC debug terminal. + */ +#define stdin ((PROS_FILE *)3) +/** + * UART 1 on the Cortex; must be opened first using usartInit(). + */ +#define uart1 ((PROS_FILE *)1) +/** + * UART 2 on the Cortex; must be opened first using usartInit(). + */ +#define uart2 ((PROS_FILE *)2) + +#ifndef EOF +/** + * EOF is a value evaluating to -1. + */ +#define EOF ((int)-1) +#endif + +#ifndef SEEK_SET +/** + * SEEK_SET is used in fseek() to denote an absolute position in bytes from the start of the + * file. + */ +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +/** + * SEEK_CUR is used in fseek() to denote an relative position in bytes from the current file + * location. + */ +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +/** + * SEEK_END is used in fseek() to denote an absolute position in bytes from the end of the + * file. The offset will most likely be negative in this case. + */ +#define SEEK_END 2 +#endif + +/** + * Closes the specified file descriptor. This function does not work on communication ports; + * use usartShutdown() instead. + * + * @param stream the file descriptor to close from fopen() + */ +void fclose(PROS_FILE *stream); +/** + * Returns the number of characters that can be read without blocking (the number of + * characters available) from the specified stream. This only works for communication ports and + * files in Read mode; for files in Write mode, 0 is always returned. + * + * This function may underestimate, but will not overestimate, the number of characters which + * meet this criterion. + * + * @param stream the stream to read (stdin, uart1, uart2, or an open file in Read mode) + * @return the number of characters which meet this criterion; if this number cannot be + * determined, returns 0 + */ +int fcount(PROS_FILE *stream); +/** + * Delete the specified file if it exists and is not currently open. + * + * The file will actually be erased from memory on the next re-boot. A physical power cycle is + * required to purge deleted files and free their allocated space for new files to be written. + * Deleted files are still considered inaccessible to fopen() in Read mode. + * + * @param file the file name to erase + * @return 0 if the file was deleted, or 1 if the file could not be found + */ +int fdelete(const char *file); +/** + * Checks to see if the specified stream is at its end. This only works for communication ports + * and files in Read mode; for files in Write mode, 1 is always returned. + * + * @param stream the channel to check (stdin, uart1, uart2, or an open file in Read mode) + * @return 0 if the stream is not at EOF, or 1 otherwise. + */ +int feof(PROS_FILE *stream); +/** + * Flushes the data on the specified file channel open in Write mode. This function has no + * effect on a communication port or a file in Read mode, as these streams are always flushed as + * quickly as possible by the kernel. + * + * Successful completion of an fflush function on a file in Write mode cannot guarantee that + * the file is vaild until fclose() is used on that file descriptor. + * + * @param stream the channel to flush (an open file in Write mode) + * @return 0 if the data was successfully flushed, EOF otherwise + */ +int fflush(PROS_FILE *stream); +/** + * Reads and returns one character from the specified stream, blocking until complete. + * + * Do not use fgetc() on a VEX LCD port; deadlock may occur. + * + * @param stream the stream to read (stdin, uart1, uart2, or an open file in Read mode) + * @return the next character from 0 to 255, or -1 if no character can be read + */ +int fgetc(PROS_FILE *stream); +/** + * Reads a string from the specified stream, storing the characters into the memory at str. + * Characters will be read until the specified limit is reached, a new line is found, or the + * end of file is reached. + * + * If the stream is already at end of file (for files in Read mode), NULL will be returned; + * otherwise, at least one character will be read and stored into str. + * + * @param str the location where the characters read will be stored + * @param num the maximum number of characters to store; at most (num - 1) characters will be + * read, with a null terminator ('\0') automatically appended + * @param stream the channel to read (stdin, uart1, uart2, or an open file in Read mode) + * @return str, or NULL if zero characters could be read + */ +char* fgets(char *str, int num, PROS_FILE *stream); +/** + * Opens the given file in the specified mode. The file name is truncated to eight characters. + * Only four files can be in use simultaneously in any given time, with at most one of those + * files in Write mode. This function does not work on communication ports; use usartInit() + * instead. + * + * mode can be "r" or "w". Due to the nature of the VEX Cortex memory, the "r+", "w+", and "a" + * modes are not supported by the file system. + * + * Opening a file that does not exist in Read mode will fail and return NULL, but opening a new + * file in Write mode will create it if there is space. Opening a file that already exists in + * Write mode will destroy the contents and create a new blank file if space is available. + * + * There are important considerations when using of the file system on the VEX Cortex. Reading + * from files is safe, but writing to files should only be performed when robot actuators have + * been stopped. PROS will attempt to continue to handle events during file writes, but most + * user tasks cannot execute during file writing. Powering down the VEX Cortex mid-write may + * cause file system corruption. + * + * @param file the file name + * @param mode the file mode + * @return a file descriptor pointing to the new file, or NULL if the file could not be opened + */ +PROS_FILE * fopen(const char *file, const char *mode); +/** + * Prints the simple string to the specified stream. + * + * This method is much, much faster than fprintf() and does not add a new line like fputs(). + * Do not use fprint() on a VEX LCD port. Use lcdSetText() instead. + * + * @param string the string to write + * @param stream the stream to write (stdout, uart1, uart2, or an open file in Write mode) + */ +void fprint(const char *string, PROS_FILE *stream); +/** + * Writes one character to the specified stream. + * + * Do not use fputc() on a VEX LCD port. Use lcdSetText() instead. + * + * @param value the character to write (a value of type "char" can be used) + * @param stream the stream to write (stdout, uart1, uart2, or an open file in Write mode) + * @return the character written + */ +int fputc(int value, PROS_FILE *stream); +/** + * Behaves the same as the "fprint" function, and appends a trailing newline ("\n"). + * + * Do not use fputs() on a VEX LCD port. Use lcdSetText() instead. + * + * @param string the string to write + * @param stream the stream to write (stdout, uart1, uart2, or an open file in Write mode) + * @return the number of characters written, excluding the new line + */ +int fputs(const char *string, PROS_FILE *stream); +/** + * Reads data from a stream into memory. Returns the number of bytes thus read. + * + * If the memory at ptr cannot store (size * count) bytes, undefined behavior occurs. + * + * @param ptr a pointer to where the data will be stored + * @param size the size of each data element to read in bytes + * @param count the number of data elements to read + * @param stream the stream to read (stdout, uart1, uart2, or an open file in Read mode) + * @return the number of bytes successfully read + */ +size_t fread(void *ptr, size_t size, size_t count, PROS_FILE *stream); +/** + * Seeks within a file open in Read mode. This function will fail when used on a file in Write + * mode or on any communications port. + * + * @param stream the stream to seek within + * @param offset the location within the stream to seek + * @param origin the reference location for offset: SEEK_CUR, SEEK_SET, or SEEK_END + * @return 0 if the seek was successful, or 1 otherwise + */ +int fseek(PROS_FILE *stream, long int offset, int origin); +/** + * Returns the current position of the stream. This function works on files in either Read or + * Write mode, but will fail on communications ports. + * + * @param stream the stream to check + * @return the offset of the stream, or -1 if the offset could not be determined + */ +long int ftell(PROS_FILE *stream); +/** + * Writes data from memory to a stream. Returns the number of bytes thus written. + * + * If the memory at ptr is not as long as (size * count) bytes, undefined behavior occurs. + * + * @param ptr a pointer to the data to write + * @param size the size of each data element to write in bytes + * @param count the number of data elements to write + * @param stream the stream to write (stdout, uart1, uart2, or an open file in Write mode) + * @return the number of bytes successfully written + */ +size_t fwrite(const void *ptr, size_t size, size_t count, PROS_FILE *stream); +/** + * Reads and returns one character from "stdin", which is the PC debug terminal. + * + * @return the next character from 0 to 255, or -1 if no character can be read + */ +int getchar(); +/** + * Prints the simple string to the debug terminal without formatting. + * + * This method is much, much faster than printf(). + * + * @param string the string to write + */ +void print(const char *string); +/** + * Writes one character to "stdout", which is the PC debug terminal, and returns the input + * value. + * + * When using a wireless connection, one may need to press the spacebar before the input is + * visible on the terminal. + * + * @param value the character to write (a value of type "char" can be used) + * @return the character written + */ +int putchar(int value); +/** + * Behaves the same as the "print" function, and appends a trailing newline ("\n"). + * + * @param string the string to write + * @return the number of characters written, excluding the new line + */ +int puts(const char *string); + +/** + * Prints the formatted string to the specified output stream. + * + * The specifiers supported by this minimalistic printf() function are: + * * @c \%d: Signed integer in base 10 (int) + * * @c \%u: Unsigned integer in base 10 (unsigned int) + * * @c \%x, @c \%X: Integer in base 16 (unsigned int, int) + * * @c \%p: Pointer (void *, int *, ...) + * * @c \%c: Character (char) + * * @c \%s: Null-terminated string (char *) + * * @c \%%: Single literal percent sign + * * @c \%f: Floating-point number + * + * Specifiers can be modified with: + * * @c 0: Zero-pad, instead of space-pad + * * @c a.b: Make the field at least "a" characters wide. If "b" is specified for "%f", changes the + * number of digits after the decimal point + * * @c -: Left-align, instead of right-align + * * @c +: Always display the sign character (displays a leading "+" for positive numbers) + * * @c l: Ignored for compatibility + * + * Invalid format specifiers, or mismatched parameters to specifiers, cause undefined behavior. + * Other characters are written out verbatim. Do not use fprintf() on a VEX LCD port. + * Use lcdPrint() instead. + * + * @param stream the stream to write (stdout, uart1, or uart2) + * @param formatString the format string as specified above + * @return the number of characters written + */ +int fprintf(PROS_FILE *stream, const char *formatString, ...); +/** + * Prints the formatted string to the debug stream (the PC terminal). + * + * @param formatString the format string as specified in fprintf() + * @return the number of characters written + */ +int printf(const char *formatString, ...); +/** + * Prints the formatted string to the string buffer with the specified length limit. + * + * The length limit, as per the C standard, includes the trailing null character, so an + * argument of 256 will cause a maximum of 255 non-null characters to be printed, and one null + * terminator in all cases. + * + * @param buffer the string buffer where characters can be placed + * @param limit the maximum number of characters to write + * @param formatString the format string as specified in fprintf() + * @return the number of characters stored + */ +int snprintf(char *buffer, size_t limit, const char *formatString, ...); +/** + * Prints the formatted string to the string buffer. + * + * If the buffer is not big enough to contain the complete formatted output, undefined behavior + * occurs. See snprintf() for a safer version of this function. + * + * @param buffer the string buffer where characters can be placed + * @param formatString the format string as specified in fprintf() + * @return the number of characters stored + */ +int sprintf(char *buffer, const char *formatString, ...); + +/** + * LEFT button on LCD for use with lcdReadButtons() + */ +#define LCD_BTN_LEFT 1 +/** + * CENTER button on LCD for use with lcdReadButtons() + */ +#define LCD_BTN_CENTER 2 +/** + * RIGHT button on LCD for use with lcdReadButtons() + */ +#define LCD_BTN_RIGHT 4 + +/** + * Clears the LCD screen on the specified port. + * + * Printing to a line implicitly overwrites the contents, so clearing should only be required + * at startup. + * + * @param lcdPort the LCD to clear, either uart1 or uart2 + */ +void lcdClear(PROS_FILE *lcdPort); +/** + * Initializes the LCD port, but does not change the text or settings. + * + * If the LCD was not initialized before, the text currently on the screen will be undefined. + * The port will not be usable with standard serial port functions until the LCD is stopped. + * + * @param lcdPort the LCD to initialize, either uart1 or uart2 + */ +void lcdInit(PROS_FILE *lcdPort); +/** + * Prints the formatted string to the attached LCD. + * + * The output string will be truncated as necessary to fit on the LCD screen, 16 characters + * wide. It is probably better to generate the string in a local buffer and use lcdSetText() + * but this method is provided for convenience. + * + * @param lcdPort the LCD to write, either uart1 or uart2 + * @param line the LCD line to write, either 1 or 2 + * @param formatString the format string as specified in fprintf() + */ +#ifdef DOXYGEN +void lcdPrint(PROS_FILE *lcdPort, unsigned char line, const char *formatString, ...); +#else +void __attribute__ ((format (printf, 3, 4))) lcdPrint(PROS_FILE *lcdPort, unsigned char line, + const char *formatString, ...); +#endif +/** + * Reads the user button status from the LCD display. + * + * For example, if the left and right buttons are pushed, (1 | 4) = 5 will be returned. 0 is + * returned if no buttons are pushed. + * + * @param lcdPort the LCD to poll, either uart1 or uart2 + * @return the buttons pressed as a bit mask + */ +unsigned int lcdReadButtons(PROS_FILE *lcdPort); +/** + * Sets the specified LCD backlight to be on or off. + * + * Turning it off will save power but may make it more difficult to read in dim conditions. + * + * @param lcdPort the LCD to adjust, either uart1 or uart2 + * @param backlight true to turn the backlight on, or false to turn it off + */ +void lcdSetBacklight(PROS_FILE *lcdPort, bool backlight); +/** + * Prints the string buffer to the attached LCD. + * + * The output string will be truncated as necessary to fit on the LCD screen, 16 characters + * wide. This function, like fprint(), is much, much faster than a formatted routine such as + * lcdPrint() and consumes less memory. + * + * @param lcdPort the LCD to write, either uart1 or uart2 + * @param line the LCD line to write, either 1 or 2 + * @param buffer the string to write + */ +void lcdSetText(PROS_FILE *lcdPort, unsigned char line, const char *buffer); +/** + * Shut down the specified LCD port. + * + * @param lcdPort the LCD to stop, either uart1 or uart2 + */ +void lcdShutdown(PROS_FILE *lcdPort); + +// -------------------- Real-time scheduler functions -------------------- +/** + * Only this many tasks can exist at once. Attempts to create further tasks will not succeed + * until tasks end or are destroyed, AND the idle task cleans them up. + * + * Changing this value will not change the limit without a kernel recompile. The idle task + * and VEX daemon task count against the limit. The user autonomous() or teleop() also counts + * against the limit, so 12 tasks usually remain for other uses. + */ +#define TASK_MAX 16 +/** + * The maximum number of available task priorities, which run from 0 to 5. + * + * Changing this value will not change the priority count without a kernel recompile. + */ +#define TASK_MAX_PRIORITIES 6 +/** + * The lowest priority that can be assigned to a task, which puts it on a level with the idle + * task. This may cause severe performance problems and is generally not recommended. + */ +#define TASK_PRIORITY_LOWEST 0 +/** + * The default task priority, which should be used for most tasks. + * + * Default tasks such as autonomous() inherit this priority. + */ +#define TASK_PRIORITY_DEFAULT 2 +/** + * The highest priority that can be assigned to a task. Unlike the lowest priority, this + * priority can be safely used without hampering interrupts. Beware of deadlock. + */ +#define TASK_PRIORITY_HIGHEST (TASK_MAX_PRIORITIES - 1) +/** + * The recommended stack size for a new task that does an average amount of work. This stack + * size is used for default tasks such as autonomous(). + * + * This is probably OK for 4-5 levels of function calls and the use of printf() with several + * arguments. Tasks requiring deep recursion or large local buffers will need a bigger stack. + */ +#define TASK_DEFAULT_STACK_SIZE 512 +/** + * The minimum stack depth for a task. Scheduler state is stored on the stack, so even if the + * task never uses the stack, at least this much space must be allocated. + * + * Function calls and other seemingly innocent constructs may place information on the stack. + * Err on the side of a larger stack when possible. + */ +#define TASK_MINIMAL_STACK_SIZE 64 + +/** + * Constant returned from taskGetState() when the task is dead or nonexistant. + */ +#define TASK_DEAD 0 +/** + * Constant returned from taskGetState() when the task is actively executing. + */ +#define TASK_RUNNING 1 +/** + * Constant returned from taskGetState() when the task is exists and is available to run, but + * not currently running. + */ +#define TASK_RUNNABLE 2 +/** + * Constant returned from taskGetState() when the task is delayed or blocked waiting for a + * semaphore, mutex, or I/O operation. + */ +#define TASK_SLEEPING 3 +/** + * Constant returned from taskGetState() when the task is suspended using taskSuspend(). + */ +#define TASK_SUSPENDED 4 + +/** + * Type by which tasks are referenced. + * + * As this is a pointer type, it can be safely passed or stored by value. + */ +typedef void * TaskHandle; +/** + * Type by which mutexes are referenced. + * + * As this is a pointer type, it can be safely passed or stored by value. + */ +typedef void * Mutex; +/** + * Type by which semaphores are referenced. + * + * As this is a pointer type, it can be safely passed or stored by value. + */ +typedef void * Semaphore; +/** + * Type for defining task functions. Task functions must accept one parameter of type + * "void *"; they need not use it. + * + * For example: + * + * void MyTask(void *ignore) { + * while (1); + * } + */ +typedef void (*TaskCode)(void *); + +/** + * Creates a new task and add it to the list of tasks that are ready to run. + * + * @param taskCode the function to execute in its own task + * @param stackDepth the number of variables available on the stack (4 * stackDepth bytes will + * be allocated on the Cortex) + * @param parameters an argument passed to the taskCode function + * @param priority a value from TASK_PRIORITY_LOWEST to TASK_PRIORITY_HIGHEST determining the + * initial priority of the task + * @return a handle to the created task, or NULL if an error occurred + */ +TaskHandle taskCreate(TaskCode taskCode, const unsigned int stackDepth, void *parameters, + const unsigned int priority); +/** + * Delays the current task for a given number of milliseconds. + * + * Delaying for a period of zero will force a reschedule, where tasks of equal priority may be + * scheduled if available. The calling task will still be available for immediate rescheduling + * once the other tasks have had their turn or if nothing of equal or higher priority is + * available to be scheduled. + * + * 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 + * taskDelayUntil(). + * + * @param msToDelay the number of milliseconds to wait, with 1000 milliseconds per second + */ +void taskDelay(const unsigned long msToDelay); +/** + * Delays the current task until a specified time. The task will be unblocked + * at the time *previousWakeTime + cycleTime, and *previousWakeTime will be changed to reflect + * the time at which the task will unblock. + * + * If the target time is in the past, no delay occurs, but a reschedule is forced, as if + * taskDelay() was called with an argument of zero. If the sum of cycleTime and + * *previousWakeTime overflows or underflows, undefined behavior occurs. + * + * This function should be used by cyclical tasks to ensure a constant execution frequency. + * While taskDelay() specifies a wake time relative to the time at which the function is + * called, taskDelayUntil() specifies the absolute future time at which it wishes to unblock. + * Calling taskDelayUntil with the same cycleTime parameter value in a loop, with + * previousWakeTime referring to a local variable initialized to millis(), will cause the + * loop to execute with a fixed period. + * + * @param previousWakeTime a pointer to the location storing the last unblock time, obtained + * by using the "&" operator on a variable (e.g. "taskDelayUntil(&now, 50);") + * @param cycleTime the number of milliseconds to wait, with 1000 milliseconds per second + */ +void taskDelayUntil(unsigned long *previousWakeTime, const unsigned long cycleTime); +/** + * Kills and removes the specified task from the kernel task list. + * + * Deleting the last task will end the program, possibly leading to undesirable states as + * some outputs may remain in their last set configuration. + * + * NOTE: The idle task is responsible for freeing the kernel allocated memory from tasks that + * have been deleted. It is therefore important that the idle task is not starved of + * processing time. Memory allocated by the task code is not automatically freed, and should be + * freed before the task is deleted. + * + * @param taskToDelete the task to kill; passing NULL kills the current task + */ +void taskDelete(TaskHandle taskToDelete); +/** + * Determines the number of tasks that are currently being managed. + * + * This includes all ready, blocked and suspended tasks. A task that has been deleted but not + * yet freed 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 running, waiting, or suspended + */ +unsigned int taskGetCount(); +/** + * Retrieves the state of the specified task. Note that the state of tasks which have died may + * be re-used for future tasks, causing the value returned by this function to reflect a + * different task than possibly intended in this case. + * + * @param task Handle to the task to query. Passing NULL will query the current task status + * (which will, by definition, be TASK_RUNNING if this call returns) + * + * @return A value reflecting the task's status, one of the constants TASK_DEAD, TASK_RUNNING, + * TASK_RUNNABLE, TASK_SLEEPING, or TASK_SUSPENDED + */ +unsigned int taskGetState(TaskHandle task); +/** + * Obtains the priority of the specified task. + * + * @param task the task to check; passing NULL checks the current task + * @return the priority of that task from 0 to TASK_MAX_PRIORITIES + */ +unsigned int taskPriorityGet(const TaskHandle task); +/** + * Sets the priority of the specified task. + * + * A context switch may occur before the function returns if the priority being set is higher + * than the currently executing task and the task being mutated is available to be scheduled. + * + * @param task the task to change; passing NULL changes the current task + * @param newPriority a value between TASK_PRIORITY_LOWEST and TASK_PRIORITY_HIGHEST inclusive + * indicating the new task priority + */ +void taskPrioritySet(TaskHandle task, const unsigned int newPriority); +/** + * Resumes the specified task. + * + * A task that has been suspended by one or more calls to taskSuspend() will be made available + * for scheduling again by a call to taskResume(). If the task was not suspended at the time + * of the call to taskResume(), undefined behavior occurs. + * + * @param taskToResume the task to change; passing NULL is not allowed as the current task + * cannot be suspended (it is obviously running if this function is called) + */ +void taskResume(TaskHandle taskToResume); +/** + * Starts a task which will periodically call the specified function. + * + * Intended for use as a quick-start skeleton for cyclic tasks with higher priority than the + * "main" tasks. The created task will have priority TASK_PRIORITY_DEFAULT + 1 with the default + * stack size. To customize behavior, create a task manually with the specified function. + * + * This task will automatically terminate after one further function invocation when the robot + * is disabled or when the robot mode is switched. + * + * @param fn the function to call in this loop + * @param increment the delay between successive calls in milliseconds; the taskDelayUntil() + * function is used for accurate cycle timing + * @return a handle to the task, or NULL if an error occurred + */ +TaskHandle taskRunLoop(void (*fn)(void), const unsigned long increment); +/** + * Suspends the specified task. + * + * When suspended a task will not be scheduled, regardless of whether it might be otherwise + * available to run. + * + * @param taskToSuspend the task to suspend; passing NULL suspends the current task + */ +void taskSuspend(TaskHandle taskToSuspend); + +/** + * Creates a semaphore intended for synchronizing tasks. To prevent some critical code from + * simultaneously modifying a shared resource, use mutexes instead. + * + * Semaphores created using this function can be accessed using the semaphoreTake() and + * semaphoreGive() functions. The mutex functions must not be used on objects of this type. + * + * This type of object does not need to have balanced take and give calls, so priority + * inheritance is not used. Semaphores can be signalled by an interrupt routine. + * + * @return a handle to the created semaphore + */ +Semaphore semaphoreCreate(); +/** + * Signals a semaphore. Tasks waiting for a signal using semaphoreTake() will be unblocked by + * this call and can continue execution. + * + * Slow processes can give semaphores when ready, and fast processes waiting to take the + * semaphore will continue at that point. + * + * @param semaphore the semaphore to signal + * @return true if the semaphore was successfully given, or false if the semaphore was not + * taken since the last give + */ +bool semaphoreGive(Semaphore semaphore); +/** + * Waits on a semaphore. If the semaphore is already in the "taken" state, the current task + * will wait for the semaphore to be signaled. Other tasks can run during this time. + * + * @param semaphore the semaphore to wait + * @param blockTime the maximum time to wait for the semaphore to be given, where -1 + * specifies an infinite timeout + * @return true if the semaphore was successfully taken, or false if the timeout expired + */ +bool semaphoreTake(Semaphore semaphore, const unsigned long blockTime); +/** + * Deletes the specified semaphore. This function can be dangerous; deleting semaphores being + * waited on by a task may cause deadlock or a crash. + * + * @param semaphore the semaphore to destroy + */ +void semaphoreDelete(Semaphore semaphore); + +/** + * Creates a mutex intended to allow only one task to use a resource at a time. For signalling + * and synchronization, try using semaphores. + * + * Mutexes created using this function can be accessed using the mutexTake() and mutexGive() + * functions. The semaphore functions must not be used on objects of this type. + * + * This type of object uses a priority inheritance mechanism so a task 'taking' a mutex MUST + * ALWAYS 'give' the mutex back once the mutex is no longer required. + * + * @return a handle to the created mutex + */ +Mutex mutexCreate(); +/** + * Relinquishes a mutex so that other tasks can use the resource it guards. The mutex must be + * held by the current task using a corresponding call to mutexTake. + * + * @param mutex the mutex to release + * @return true if the mutex was released, or false if the mutex was not already held + */ +bool mutexGive(Mutex mutex); +/** + * Requests a mutex so that other tasks cannot simultaneously use the resource it guards. + * The mutex must not already be held by the current task. If another task already + * holds the mutex, the function will wait for the mutex to be released. Other tasks can run + * during this time. + * + * @param mutex the mutex to request + * @param blockTime the maximum time to wait for the mutex to be available, where -1 + * specifies an infinite timeout + * @return true if the mutex was successfully taken, or false if the timeout expired + */ +bool mutexTake(Mutex mutex, const unsigned long blockTime); +/** + * Deletes the specified mutex. This function can be dangerous; deleting semaphores being + * waited on by a task may cause deadlock or a crash. + * + * @param mutex the mutex to destroy + */ +void mutexDelete(Mutex mutex); + +/** + * Wiring-compatible alias of taskDelay(). + * + * @param time the duration of the delay in milliseconds (1 000 milliseconds per second) + */ +void delay(const unsigned long time); +/** + * Wait for approximately the given number of microseconds. + * + * The method used for delaying this length of time may vary depending on the argument. + * The current task will always be delayed by at least the specified period, but possibly much + * more depending on CPU load. In general, this function is less reliable than delay(). Using + * this function in a loop may hog processing time from other tasks. + * + * @param us the duration of the delay in microseconds (1 000 000 microseconds per second) + */ +void delayMicroseconds(const unsigned long us); +/** + * Returns the number of microseconds since Cortex power-up. There are 10^6 microseconds in a + * second, so as a 32-bit integer, this will overflow and wrap back to zero every two hours or + * so. + * + * This function is Wiring-compatible. + * + * @return the number of microseconds since the Cortex was turned on or the last overflow + */ +unsigned long micros(); +/** + * Returns the number of milliseconds since Cortex power-up. There are 1000 milliseconds in a + * second, so as a 32-bit integer, this will not overflow for 50 days. + * + * This function is Wiring-compatible. + * + * @return the number of milliseconds since the Cortex was turned on + */ +unsigned long millis(); +/** + * Alias of taskDelay() intended to help EasyC users. + * + * @param time the duration of the delay in milliseconds (1 000 milliseconds per second) + */ +void wait(const unsigned long time); +/** + * Alias of taskDelayUntil() intended to help EasyC users. + * + * @param previousWakeTime a pointer to the last wakeup time + * @param time the duration of the delay in milliseconds (1 000 milliseconds per second) + */ +void waitUntil(unsigned long *previousWakeTime, const unsigned long time); +/** + * Enables IWDG watchdog timer which will reset the cortex if it locks up due to static shock + * or a misbehaving task preventing the timer to be reset. Not recovering from static shock + * will cause the robot to continue moving its motors indefinitely until turned off manually. + * + * This function should only be called once in initializeIO() + */ +void watchdogInit(); +/** + * Enables the Cortex to run the op control task in a standalone mode- no VEXnet connection required. + * + * This function should only be called once in initializeIO() + */ +void standaloneModeEnable(); + +// End C++ extern to C +#ifdef __cplusplus +} +#endif + +#endif diff --git a/PROS/include/main.h b/PROS/include/main.h new file mode 100644 index 0000000..c74ab36 --- /dev/null +++ b/PROS/include/main.h @@ -0,0 +1,32 @@ +//copy and paste main.h file here +#define MOTOR_PORT 11 //left front +#define MOTOR_PORT 12 //left back +#define MOTOR_PORT 13 //right front +#define MOTOR_PORT 14 //right back +#define MOTOR_PORT 15 //puncher +#define MOTOR_PORT 16 //intake + +// Motivational quote +void littleCeasars(){ + //will display text on controller converted from VCS folder + pros::lcd::set_text(1, "lEtS gEt tHiS bReAd"); //for documentation check: https://pros.cs.purdue.edu/v5/api/cpp/llemu.html or https://pros.cs.purdue.edu/v5/api/cpp/misc.html#set-text + +} + +void opDrive(){ + //simple tank drive code for opControl + leftFront.move(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); //for documentation check: https://pros.cs.purdue.edu/v5/api/cpp/motors.html#move-velocity or https://pros.cs.purdue.edu/v5/tutorials/topical/controller.html?highlight=controller%20analog + leftBack.move(master.get_analog(E_CONTROLLER_ANALOG_LEFT_Y)); //for docs check: https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html + rightFront.move(master.get_analog(E_CONTROLLER_ANALOG_RIGHT_Y)); + rightBack.move(master.get_analog(E_CONTROLLER_ANALOG_RIGHT_Y)); +} + +void opIntake(){ + if(master.get_digital(E_CONTROLLER_DIGITAL_R2)){ //for docs check: https://pros.cs.purdue.edu/v5/api/c/misc.html#controller-id-e-t + intake.move(100); + }else if(master.get_digital(E_CONTROLLER_DIGITAL_L1)){ + intake.move(-100); + }else{ + intake.move(0); + } +} diff --git a/PROS/project.pros b/PROS/project.pros new file mode 100644 index 0000000..f63bf80 --- /dev/null +++ b/PROS/project.pros @@ -0,0 +1 @@ +{"py/object": "prosconfig.ProjectConfig", "py/state": {"kernel": "2.12.2", "libraries": {}, "output": "bin/output.bin"}} \ No newline at end of file diff --git a/PROS/src/auto.c b/PROS/src/auto.c new file mode 100644 index 0000000..f7134ff --- /dev/null +++ b/PROS/src/auto.c @@ -0,0 +1,27 @@ +/** @file auto.c + * @brief File for autonomous code + * + * This file should contain the user autonomous() function and any functions related to it. + * + * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be + * obtained from http://sourceforge.net/projects/freertos/files/ or on request. + */ + +#include "main.h" + +/* + * 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. If the robot is disabled or communications is + * lost, the autonomous task will be stopped by the kernel. Re-enabling the robot will restart + * the task, not re-start it from where it left off. + * + * Code running in the autonomous task cannot access information from the VEX Joystick. However, + * the autonomous function can be invoked from another task if a VEX Competition Switch is not + * available, and it can access joystick information if called in this way. + * + * The autonomous task may exit, unlike operatorControl() which should never exit. If it does + * so, the robot will await a switch to another mode or disable/enable cycle. + */ +void autonomous() { +} diff --git a/PROS/src/init.c b/PROS/src/init.c new file mode 100644 index 0000000..07bc36e --- /dev/null +++ b/PROS/src/init.c @@ -0,0 +1,51 @@ +/** @file init.c + * @brief File for initialization code + * + * This file should contain the user initialize() function and any functions related to it. + * + * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be + * obtained from http://sourceforge.net/projects/freertos/files/ or on request. + */ + +#include "main.h" + +/* + * Runs pre-initialization code. This function will be started in kernel mode one time while the + * VEX Cortex is starting up. As the scheduler is still paused, most API functions will fail. + * + * The purpose of this function is solely to set the default pin modes (pinMode()) and port + * states (digitalWrite()) of limit switches, push buttons, and solenoids. It can also safely + * configure a UART port (usartOpen()) but cannot set up an LCD (lcdInit()). + */ +void initializeIO() { +} + +/* + * Runs user initialization code. This function will be started in its own task with the default + * priority and stack size once when the robot is starting up. It is possible that the VEXnet + * communication link may not be fully established at this time, so reading from the VEX + * Joystick may fail. + * + * This function should initialize most sensors (gyro, encoders, ultrasonics), LCDs, global + * variables, and IMEs. + * + * This function must exit relatively promptly, or the operatorControl() and autonomous() tasks + * will not start. An autonomous mode selection menu like the pre_auton() in other environments + * can be implemented in this task if desired. + */ +void initialize() { + //initialization function code + pros::lcd::initialize(); + + //setup controller + pros::Controller master (E_CONTROLLER_MASTER); + + //setup motors + pros::Motor leftFront (11, E_MOTOR_GEARSET_18, false, E_MOTOR_ENCODER_DEGREES); //for conditions check: https://pros.cs.purdue.edu/v5/tutorials/topical/motors.html + pros::Motor leftBack (12, E_MOTOR_GEARSET_18, false, E_MOTOR_ENCODER_DEGREES); //E_MOTOR_GEARSET_36 = red(100RPM), E_MOTOR_GEARSET_18 == green(200 RPM), E_MOTOR_GEARSET_06 = blue(600 RPM) for more see: https://pros.cs.purdue.edu/v5/api/c/motors.html#motor-gearset-e-t + pros::Motor rightFront (13, E_MOTOR_GEARSET_18, false, E_MOTOR_ENCODER_DEGREES); + pros::Motor rightBack (14, E_MOTOR_GEARSET_18, false, E_MOTOR_ENCODER_DEGREES); + pros::Motor puncher (15, E_MOTOR_GEARSET_36, false, E_MOTOR_ENCODER_DEGREES); + pros::Motor intake (16, E_MOTOR_GEARSET_36, false, E_MOTOR_ENCODER_DEGREES); + +} diff --git a/PROS/src/opcontrol.c b/PROS/src/opcontrol.c new file mode 100644 index 0000000..0704bf5 --- /dev/null +++ b/PROS/src/opcontrol.c @@ -0,0 +1,42 @@ +/** @file opcontrol.c + * @brief File for operator control code + * + * This file should contain the user operatorControl() function and any functions related to it. + * + * PROS contains FreeRTOS (http://www.freertos.org) whose source code may be + * obtained from http://sourceforge.net/projects/freertos/files/ or on request. + */ + +#include "main.h" + +/* + * Runs the user 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 the robot is disabled or + * communications is lost, the operator control task will be stopped by the kernel. Re-enabling + * the robot will restart the task, not resume it from where it left off. + * + * If no VEX Competition Switch or Field Management system is plugged in, the VEX Cortex will + * run the operator control task. Be warned that this will also occur if the VEX Cortex is + * tethered directly to a computer via the USB A to A cable without any VEX Joystick attached. + * + * Code running in this task can take almost any action, as the VEX Joystick is available and + * the scheduler is operational. However, proper use of delay() or taskDelayUntil() is highly + * recommended to give other tasks (including system tasks such as updating LCDs) time to run. + * + * This task should never exit; it should end with some kind of infinite loop, even if empty. + */ +void operatorControl() { + while (1) { + //calls opDrive void which controls the drive with joysticks + opDrive(); + + //calls opIntake void which controls the intake with buttons + opIntake(); + + + + pros::delay(2); + } + } +}