diff --git a/.gitignore b/.gitignore index 6d7821889..36feda877 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ temp.errors .clangd/ .cache/ .DS_Store +/amalgamate-src/* diff --git a/Makefile b/Makefile index 2b445b42f..539e8824e 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ BINDIR=$(ROOT)/bin SRCDIR=$(ROOT)/src INCDIR=$(ROOT)/include EXTRA_INCDIR=$(FWDIR)/libv5rts/sdk/vexv5/patched_include +AMALGAMATE_SRCDIR=$(ROOT)/amalgamate-src # Directories to be excluded from all builds EXCLUDE_SRCDIRS+=$(SRCDIR)/tests @@ -46,6 +47,10 @@ TEMPLATE_FILES+= $(ROOT)/template-gitignore PATCHED_SDK=$(FWDIR)/libv5rts/sdk/vexv5/libv5rts.patched.a +ifndef NO_AMALGAMATE +SRCDIR=$(AMALGAMATE_SRCDIR) +endif + EXTRA_LIB_DEPS=$(INCDIR)/api.h $(PATCHED_SDK) ################################################################################ @@ -53,19 +58,27 @@ EXTRA_LIB_DEPS=$(INCDIR)/api.h $(PATCHED_SDK) ########## Nothing below this line should be edited by typical users ########### -include ./common.mk -.PHONY: $(INCDIR)/api.h patch_sdk_headers clean -$(INCDIR)/api.h: version.py +.PHONY: $(INCDIR)/pros/version.h patch_sdk_headers amalgamate clean +$(INCDIR)/pros/version.h: version.py $(VV)python version.py +amalgamate: amalgamate.py +ifndef NO_AMALGAMATE + @echo "Amalgamating src files" + $(VV)python amalgamate.py + $(VV)cp src/main.cpp amalgamate-src/main.cpp +endif + patch_sdk_headers: patch_headers.py @echo "Patching SDK headers" $(VV)python patch_headers.py # Override clean, necessary to remove patched sdk on clean -clean: +clean:: @echo "Cleaning patched SDK" @rm -f $(PATCHED_SDK) @rm -rf $(EXTRA_INCDIR) + @rm -rf $(AMALGAMATE_SRCDIR) $(PATCHED_SDK): $(FWDIR)/libv5rts/sdk/vexv5/libv5rts.a $(call test_output_2,Stripping unwanted symbols from libv5rts.a ,$(STRIP) $^ @libv5rts-strip-options.txt -o $@, $(DONE_STRING)) @@ -75,7 +88,7 @@ CREATE_TEMPLATE_ARGS+=--user "src/main.{cpp,c,cc}" --user "include/main.{hpp,h,h CREATE_TEMPLATE_ARGS+=--target v5 CREATE_TEMPLATE_ARGS+=--output bin/monolith.bin --cold_output bin/cold.package.bin --hot_output bin/hot.package.bin --cold_addr 58720256 --hot_addr 125829120 -template: patch_sdk_headers clean-template library +template: patch_sdk_headers amalgamate clean-template library $(VV)mkdir -p $(TEMPLATE_DIR) @echo "Moving template files to $(TEMPLATE_DIR)" $Dif [ $(shell uname -s) == "Darwin" ]; then \ @@ -91,7 +104,7 @@ template: patch_sdk_headers clean-template library $Dpros c create-template $(TEMPLATE_DIR) kernel $(shell cat $(ROOT)/version) $(CREATE_TEMPLATE_ARGS) LIBV5RTS_EXTRACTION_DIR=$(BINDIR)/libv5rts -$(LIBAR): patch_sdk_headers $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) +$(LIBAR): patch_sdk_headers amalgamate $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) $(VV)mkdir -p $(LIBV5RTS_EXTRACTION_DIR) $(call test_output_2,Extracting libv5rts ,cd $(LIBV5RTS_EXTRACTION_DIR) && $(AR) x ../../$(PATCHED_SDK),$(DONE_STRING)) $(eval LIBV5RTS_OBJECTS := $(shell $(AR) t $(PATCHED_SDK))) diff --git a/amalgamate.py b/amalgamate.py new file mode 100644 index 000000000..e0e8c8d8d --- /dev/null +++ b/amalgamate.py @@ -0,0 +1,49 @@ +from os import listdir, makedirs, walk +from os.path import isfile, join, exists, dirname, realpath, splitext + +def print_and_exit(message): + print(message) + print("Failed to amalgamate files") + exit(1) + +# get the current directory +try: + current_dir = dirname(realpath(__file__)) +except: + print_and_exit("Could not get working directory!") + +src_dir = current_dir + "/src" +amalgamate_src_dir = current_dir + "/amalgamate-src" + +if not exists(amalgamate_src_dir): + try: + makedirs(amalgamate_src_dir) + except: + print_and_exit("Could not create directory for amalgamation!") + +c_src_files = [join(dp, f) for dp, dn, filenames in walk(f"{current_dir}/src") for f in filenames if + splitext(f)[1].lower() == '.c'] +cpp_src_files = [join(dp, f) for dp, dn, filenames in walk(f"{current_dir}/src") for f in filenames if + splitext(f)[1].lower() == '.cpp'] + +with open(amalgamate_src_dir + "/amalgamate.c", "w") as dest: + for c_file in c_src_files: + if "/test/" in c_file: + continue + with open(c_file) as f: + contents = f.read() + dest.write(f"#line 1 \"{c_file}\"\n") + dest.write(contents + "\n") + +with open(amalgamate_src_dir + "/amalgamate.cpp", "w") as dest: + for cpp_file in cpp_src_files: + if "/test/" in cpp_file or "main.cpp" in cpp_file: + continue + with open(cpp_file) as f: + contents = f.read() + dest.write(f"#line 1 \"{cpp_file}\"\n") + dest.write(contents + "\n") + +with open(amalgamate_src_dir + "/main.cpp", "w") as dest: + with open(src_dir + "/main.cpp", "r") as src: + dest.write(src.read()) diff --git a/common.mk b/common.mk index 39bd7d956..edc623b43 100644 --- a/common.mk +++ b/common.mk @@ -188,7 +188,7 @@ quick: $(DEFAULT_BIN) all: clean $(DEFAULT_BIN) -clean: +clean:: @echo Cleaning project -$Drm -rf $(BINDIR) -$Drm -rf $(DEPDIR) @@ -262,7 +262,7 @@ $(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 +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 $(DEPDIR)/$(basename %).d $(VV)mkdir -p $$(dir $$@) $(MAKEDEPFOLDER) $$(call test_output_2,Compiled $$< ,$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -o $$@ $$<,$(OK_STRING)) diff --git a/include/api.h b/include/api.h index 57c248c78..ea328e334 100644 --- a/include/api.h +++ b/include/api.h @@ -39,13 +39,6 @@ #include #endif /* __cplusplus */ -#define PROS_VERSION_MAJOR 4 -#define PROS_VERSION_MINOR 1 - -#define PROS_VERSION_PATCH 0 -#define PROS_VERSION_STRING "4.1.0" - - #include "pros/adi.h" #include "pros/colors.h" #include "pros/device.h" diff --git a/include/pros/apix.h b/include/pros/apix.h index 165c0541b..123f58261 100644 --- a/include/pros/apix.h +++ b/include/pros/apix.h @@ -71,7 +71,7 @@ typedef void* sem_t; * task_abort_delay(task); * \endcode */ -bool task_abort_delay(task_t task); +int32_t task_abort_delay(task_t task); /** * Notify a task when a target task is being deleted. @@ -152,7 +152,7 @@ mutex_t mutex_recursive_create(void); * * \endcode */ -bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); +uint8_t mutex_recursive_take(mutex_t mutex, uint32_t timeout); /** * Gives a recursive mutex. @@ -179,7 +179,7 @@ bool mutex_recursive_take(mutex_t mutex, uint32_t timeout); * * \endcode */ -bool mutex_recursive_give(mutex_t mutex); +uint8_t mutex_recursive_give(mutex_t mutex); /** * Returns a handle to the current owner of a mutex. @@ -360,7 +360,7 @@ sem_t sem_binary_create(void); * } * \endcode */ -bool sem_wait(sem_t sem, uint32_t timeout); +uint8_t sem_wait(sem_t sem, uint32_t timeout); /** * Increments a semaphore's value. @@ -390,7 +390,7 @@ bool sem_wait(sem_t sem, uint32_t timeout); * * \endcode */ -bool sem_post(sem_t sem); +uint8_t sem_post(sem_t sem); /** * Returns the current value of the semaphore. @@ -524,7 +524,7 @@ bool queue_append(queue_t queue, const void* item, uint32_t timeout); * } * \endcode */ -bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); +int32_t queue_peek(queue_t queue, void* const buffer, uint32_t timeout); /** * Receive an item from the queue. @@ -555,7 +555,7 @@ bool queue_peek(queue_t queue, void* const buffer, uint32_t timeout); * } * \endcode */ -bool queue_recv(queue_t queue, void* const buffer, uint32_t timeout); +int32_t queue_recv(queue_t queue, void* const buffer, uint32_t timeout); /** * Return the number of messages stored in a queue. diff --git a/include/pros/optical.h b/include/pros/optical.h index 049c395b7..61a2c86d0 100644 --- a/include/pros/optical.h +++ b/include/pros/optical.h @@ -460,6 +460,39 @@ int32_t optical_enable_gesture(uint8_t port); */ int32_t optical_disable_gesture(uint8_t port); +/** + * Get integration time (update rate) of the optical sensor in milliseconds, with + * minimum time being + * + * This function uses the following values of errno when an error 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 Integration time in milliseconds if the operation is successful + * or PROS_ERR if the operation failed, setting errno. + */ +double optical_get_integration_time(uint8_t port); + +/** + * Set integration time (update rate) of the optical sensor in milliseconds. + * + * This function uses the following values of errno when an error 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 + * \param time + * The desired integration time in milliseconds + * \return 1 if the operation is successful or PROS_ERR if the operation failed, + * setting errno. + */ +int32_t optical_set_integration_time(uint8_t port, double time); + ///@} ///@} diff --git a/include/pros/optical.hpp b/include/pros/optical.hpp index 463daa8a8..b3e1d4e99 100644 --- a/include/pros/optical.hpp +++ b/include/pros/optical.hpp @@ -398,6 +398,36 @@ class Optical : public Device { */ virtual std::int32_t disable_gesture(); + /** + * Set integration time (update rate) of the optical sensor in milliseconds, with + * minimum time being 3 ms and maximum time being 712 ms. Default is 100 ms, with the + * optical sensor communciating with the V5 brain every 20 ms. + * + * This function uses the following values of errno when an error 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_F if the operation failed, + * setting errno. + */ + double get_integration_time(); + + /** + * Get integration time (update rate) of the optical sensor in milliseconds. + * + * This function uses the following values of errno when an error 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 time + * The desired integration time in milliseconds + * \return Integration time in milliseconds if the operation is successful + * or PROS_ERR if the operation failed, setting errno. + */ + std::int32_t set_integration_time(double time); + /** * This is the overload for the << operator for printing to streams * diff --git a/include/pros/rtos.h b/include/pros/rtos.h index d6b9be480..ba3e6dc84 100644 --- a/include/pros/rtos.h +++ b/include/pros/rtos.h @@ -116,6 +116,8 @@ typedef void (*task_fn_t)(void*); /** * The state of a task. */ +#ifndef PROS_TASK_ENUMS_DEFINED +#define PROS_TASK_ENUMS_DEFINED typedef enum { E_TASK_STATE_RUNNING = 0, /**< The task is actively executing. */ E_TASK_STATE_READY, /**< The task exists and is available to run, but is not currently running. */ @@ -135,6 +137,7 @@ typedef enum { E_NOTIFY_ACTION_OWRITE, /**< The task’s notification value will be unconditionally set to the new value.*/ E_NOTIFY_ACTION_NO_OWRITE /**< The task’s notification value will be set to the new value if the task does not already have a pending notification.*/ } notify_action_e_t; +#endif // PROS_TASK_ENUMS_DEFINED /// @} Name: Enumerations @@ -660,7 +663,7 @@ task_t task_get_current(); * } * \endcode */ -uint32_t task_notify(task_t task); +int32_t task_notify(task_t task); /** * @@ -743,7 +746,7 @@ void task_join(task_t task); * } * \endcode */ -uint32_t task_notify_ext(task_t task, uint32_t value, notify_action_e_t action, uint32_t* prev_value); +int32_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. @@ -820,7 +823,7 @@ uint32_t task_notify_take(bool clear_on_exit, uint32_t timeout); * } * \endcode */ -bool task_notify_clear(task_t task); +int32_t task_notify_clear(task_t task); /** * Creates a mutex. diff --git a/include/pros/version.h b/include/pros/version.h new file mode 100644 index 000000000..453284f67 --- /dev/null +++ b/include/pros/version.h @@ -0,0 +1,23 @@ +/** +* \file version.h +* +* PROS Version Information +* +* Contains PROS kernel version information +* +* +* \copyright Copyright (c) 2017-2023, Purdue University ACM SIGBots. +* All rights reserved. +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#define PROS_VERSION_MAJOR 4 +#define PROS_VERSION_MINOR 1 + +#define PROS_VERSION_PATCH 0 +#define PROS_VERSION_STRING "4.1.0" \ No newline at end of file diff --git a/include/rtos/task.h b/include/rtos/task.h index 1069e506e..3649197ec 100644 --- a/include/rtos/task.h +++ b/include/rtos/task.h @@ -67,6 +67,9 @@ typedef void * task_t; */ typedef int32_t (*TaskHookFunction_t)( void * ); + +#ifndef PROS_TASK_ENUMS_DEFINED +#define PROS_TASK_ENUMS_DEFINED /* Task states returned by task_get_state. */ typedef enum { @@ -87,6 +90,7 @@ typedef enum E_NOTIFY_ACTION_OWRITE, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */ E_NOTIFY_ACTION_NO_OWRITE /* Set the task's notification value if the previous value has been read by the task. */ } notify_action_e_t; +#endif // PROS_TASK_ENUMS_DEFINED /* * Used internally only. diff --git a/include/system/hot.h b/include/system/hot.h index bc5824f85..4b2c02f1f 100644 --- a/include/system/hot.h +++ b/include/system/hot.h @@ -14,4 +14,13 @@ struct hot_table { } functions; }; +// exidx is the table that tells the unwinder how to unwind a stack frame +// for a PC. Under hot/cold, there's two tables and the unwinder was kind +// enough to let us implement a function to give it a table for a PC so +// support for hot/cold is as easy as it gets +struct __EIT_entry { + _uw fnoffset; + _uw content; +}; + extern struct hot_table* const HOT_TABLE; diff --git a/src/common/cobs.c b/src/common/cobs.c index 13742500a..d5e20013b 100644 --- a/src/common/cobs.c +++ b/src/common/cobs.c @@ -16,7 +16,7 @@ #include -#include "cobs.h" +#include "common/cobs.h" size_t cobs_encode_measure(const uint8_t* restrict src, const size_t src_len, const uint32_t prefix) { size_t read_idx = 0; diff --git a/src/devices/vdml_optical.c b/src/devices/vdml_optical.c index 295d07597..84e5cb3f5 100644 --- a/src/devices/vdml_optical.c +++ b/src/devices/vdml_optical.c @@ -17,6 +17,11 @@ #include "vdml/registry.h" #include "vdml/vdml.h" +// Source for these figures: +// https://www.vexforum.com/t/v5-optical-sensor-refresh-rate/109632/9 +#define MIN_INTEGRATION_TIME 3 // ms +#define MAX_INTEGRATION_TIME 712 // ms + double optical_get_hue(uint8_t port) { claim_port_i(port - 1, E_DEVICE_OPTICAL); double rtn = vexDeviceOpticalHueGet(device->device_info); @@ -134,3 +139,20 @@ int32_t optical_disable_gesture(uint8_t port) { vexDeviceOpticalGestureDisable(device->device_info); return_port(port - 1, PROS_SUCCESS); } + +double optical_get_integration_time(uint8_t port) { + claim_port_f(port - 1, E_DEVICE_OPTICAL); + double rtv = vexDeviceOpticalIntegrationTimeGet(device->device_info); + return_port(port - 1, rtv); +} + +int32_t optical_set_integration_time(uint8_t port, double time) { + claim_port_i(port - 1, E_DEVICE_OPTICAL); + // going to set the time to minimum of 3 ms, 3 ms is possible but impractical. + time = time < MIN_INTEGRATION_TIME ? MIN_INTEGRATION_TIME : time; + // also boundary limit max integration time too + time = time > MAX_INTEGRATION_TIME ? MAX_INTEGRATION_TIME : time; + + vexDeviceOpticalIntegrationTimeSet(device->device_info, time); + return_port(port - 1, PROS_SUCCESS); +} \ No newline at end of file diff --git a/src/devices/vdml_optical.cpp b/src/devices/vdml_optical.cpp index 78e448f1d..31cc79668 100644 --- a/src/devices/vdml_optical.cpp +++ b/src/devices/vdml_optical.cpp @@ -10,6 +10,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "pros/optical.h" #include "pros/optical.hpp" #include "vdml/vdml.h" @@ -76,6 +77,13 @@ std::int32_t Optical::disable_gesture(){ return optical_disable_gesture(_port); } +double Optical::get_integration_time() { + return optical_get_integration_time(_port); +} + +std::int32_t Optical::set_integration_time(double time) { + return optical_set_integration_time(_port, time); +} std::ostream& operator<<(std::ostream& os, pros::Optical& optical) { pros::c::optical_rgb_s_t rgb = optical.get_rgb(); diff --git a/src/system/dev/ser_daemon.c b/src/system/dev/ser_daemon.c index d77fdee3f..86305d958 100644 --- a/src/system/dev/ser_daemon.c +++ b/src/system/dev/ser_daemon.c @@ -18,6 +18,7 @@ #include #include "kapi.h" +#include "pros/version.h" #include "system/dev/banners.h" #include "system/hot.h" #include "system/optimizers.h" diff --git a/src/system/hot.c b/src/system/hot.c index 3341967a6..20589d7cc 100644 --- a/src/system/hot.c +++ b/src/system/hot.c @@ -19,12 +19,12 @@ uint32_t const volatile* const MAGIC_ADDR = MAGIC; // When linking in hot, these pointers work just like any other weak symbol // Note: to get C++ style initialize and friends, we strip out cpp_initialize and friends so that linker // regenerates that function with the call to the correct (user-written) C++ version -extern char const* _PROS_COMPILE_TIMESTAMP; -extern char const* _PROS_COMPILE_DIRECTORY; +extern char const* const _PROS_COMPILE_TIMESTAMP; +extern char const* const _PROS_COMPILE_DIRECTORY; extern const int _PROS_COMPILE_TIMESTAMP_INT; -extern unsigned __exidx_start; -extern unsigned __exidx_end; +extern struct __EIT_entry __exidx_start; +extern struct __EIT_entry __exidx_end; // this expands to a bunch of: // extern void autonomous(); diff --git a/src/system/mlock.c b/src/system/mlock.c index a78a53334..a3cb3ed17 100644 --- a/src/system/mlock.c +++ b/src/system/mlock.c @@ -13,12 +13,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include "rtos/task.h" - void __malloc_lock(void) { +void __malloc_lock(struct _reent* _) { rtos_suspend_all(); - } +} - void __malloc_unlock(void) { +void __malloc_unlock(struct _reent* _) { rtos_resume_all(); - } +} diff --git a/src/system/newlib_stubs.c b/src/system/newlib_stubs.c index feeb8b80e..11542a928 100644 --- a/src/system/newlib_stubs.c +++ b/src/system/newlib_stubs.c @@ -23,7 +23,7 @@ #include "rtos/task.h" #include "v5_api.h" -#include "hot.h" +#include "system/hot.h" #include "pros/misc.h" #define SEC_TO_MSEC 1000 diff --git a/src/system/unwind.c b/src/system/unwind.c index 9ac6c180e..cf68875a5 100644 --- a/src/system/unwind.c +++ b/src/system/unwind.c @@ -72,14 +72,6 @@ static inline void print_phase2_vrs(struct phase2_vrs* vrs) { fputs("\n", stderr); } -// exidx is the table that tells the unwinder how to unwind a stack frame -// for a PC. Under hot/cold, there's two tables and the unwinder was kind -// enough to let us implement a function to give it a table for a PC so -// support for hot/cold is as easy as it gets -struct __EIT_entry { - _uw fnoffset; - _uw content; -}; // these are all defined by the linker extern struct __EIT_entry __exidx_start; extern struct __EIT_entry __exidx_end; diff --git a/version.py b/version.py index e818f25ec..7a275939a 100644 --- a/version.py +++ b/version.py @@ -28,7 +28,7 @@ assert semver.count('.') >= 2 major, minor, patch = semver.split('.', 2) patch = patch.split('-', 1)[0] - with io.open('include/api.h', 'r', encoding='ascii') as file: + with io.open('include/pros/version.h', 'r', encoding='ascii') as file: data = file.readlines() for i, line in enumerate(data): if '#define PROS_VERSION_MAJOR' in line: @@ -39,7 +39,7 @@ data[i] = u'#define PROS_VERSION_PATCH {}\n'.format(patch) if '#define PROS_VERSION_STRING ' in line: data[i] = u'#define PROS_VERSION_STRING "{}"\n'.format(semver) - with io.open('include/api.h', 'w', newline='\n', encoding='ascii') as file: + with io.open('include/pros/version.h', 'w', newline='\n', encoding='ascii') as file: file.writelines(data) except subprocess.CalledProcessError as e: