From 696018f04d4c173417a237c7a706336c3fea9d24 Mon Sep 17 00:00:00 2001 From: Cole Deck Date: Thu, 29 Feb 2024 16:33:12 -0600 Subject: [PATCH] Initial Version - CustomController recording system - TinyBot mode --- .gitignore | 3 + .vscode/c_cpp_properties.json | 49 +++ .vscode/settings.json | 5 + .vscode/vex_project_settings.json | 18 + include/vex.h | 16 + makefile | 30 ++ src/main.cpp | 555 ++++++++++++++++++++++++++++++ vex/mkenv.mk | 110 ++++++ vex/mkrules.mk | 32 ++ 9 files changed, 818 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/vex_project_settings.json create mode 100644 include/vex.h create mode 100644 makefile create mode 100644 src/main.cpp create mode 100644 vex/mkenv.mk create mode 100644 vex/mkrules.mk diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a967d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/bin +/build +compile_commands.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..add022f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,49 @@ +{ + "env": { + "vex_compilerPath": "${config:vexrobotics.vexcode.Cpp.Toolchain.Path}\\clang\\bin\\clang", + "vex_sdkPath": "${config:vexrobotics.vexcode.Cpp.Sdk.Home}\\V5\\V5_20220726_10_00_00\\vexv5", + "vex_gcc": "${vex_sdkPath}/gcc/include/c++/4.9.3", + "vex_sdkIncludes": [ + "${vex_sdkPath}/clang/8.0.0/include/**", + "${vex_gcc}/**", + "${vex_gcc}/arm-none-eabi/armv7-arm/thumb", + "${vex_sdkPath}/gcc/include", + "${vex_sdkPath}/include/**", + "${workspaceFolder}/include/**", + "${workspaceFolder}/src/**" + ] + }, + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${vex_sdkIncludes}" + ], + "compilerPath": "${vex_compilerPath}", + "cStandard": "gnu99", + "cppStandard": "gnu++11", + "intelliSenseMode": "windows-clang-x86" + }, + { + "name": "Mac", + "includePath": [ + "${vex_sdkIncludes}" + ], + "compilerPath": "${vex_compilerPath}", + "cStandard": "gnu99", + "cppStandard": "gnu++11", + "intelliSenseMode": "macos-clang-x86" + }, + { + "name": "Linux", + "includePath": [ + "${vex_sdkIncludes}" + ], + "compilerPath": "", + "cStandard": "gnu99", + "cppStandard": "gnu++11", + "intelliSenseMode": "linux-clang-x86" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a55b5a3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "C_Cpp.default.systemIncludePath": [ + "${config:vexrobotics.vexcode.Cpp.Sdk.Home}\\V5\\V5_20220726_10_00_00\\vexv5\\gcc\\include\\sys" + ] +} \ No newline at end of file diff --git a/.vscode/vex_project_settings.json b/.vscode/vex_project_settings.json new file mode 100644 index 0000000..7f90bd7 --- /dev/null +++ b/.vscode/vex_project_settings.json @@ -0,0 +1,18 @@ +{ + "project": { + "name": "TinyBotRecording", + "slot": 1, + "description": "", + "platform": "V5", + "creationDate": "Thu, 22 Feb 2024 21:59:48 GMT", + "language": "cpp", + "sdkVersion": "V5_20220726_10_00_00", + "cpp": { + "includePath": [] + } + }, + "extension": { + "version": "0.5.0", + "json": 1 + } +} \ No newline at end of file diff --git a/include/vex.h b/include/vex.h new file mode 100644 index 0000000..b05c010 --- /dev/null +++ b/include/vex.h @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +#include "v5.h" +#include "v5_vcs.h" + + +#define waitUntil(condition) \ + do { \ + wait(5, msec); \ + } while (!(condition)) + +#define repeat(iterations) \ + for (int iterator = 0; iterator < iterations; iterator++) \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..acc3bca --- /dev/null +++ b/makefile @@ -0,0 +1,30 @@ +# VEXcode makefile 2019_03_26_01 + +# show compiler output +VERBOSE = 0 + +# include toolchain options +include vex/mkenv.mk + +# location of the project source cpp and c files +SRC_C = $(wildcard src/*.cpp) +SRC_C += $(wildcard src/*.c) +SRC_C += $(wildcard src/*/*.cpp) +SRC_C += $(wildcard src/*/*.c) + +OBJ = $(addprefix $(BUILD)/, $(addsuffix .o, $(basename $(SRC_C))) ) + +# location of include files that c and cpp files depend on +SRC_H = $(wildcard include/*.h) + +# additional dependancies +SRC_A = makefile + +# project header file locations +INC_F = include + +# build targets +all: $(BUILD)/$(PROJECT).bin + +# include build rules +include vex/mkrules.mk diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..f8480db --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,555 @@ +#pragma region VEXcode Generated Robot Configuration +// Make sure all required headers are included. +#include +#include +#include +#include +#include +#include + +#include "vex.h" + +using namespace vex; + +// Brain should be defined by default +brain Brain; + + +// START V5 MACROS +#define waitUntil(condition) \ + do { \ + wait(5, msec); \ + } while (!(condition)) + +#define repeat(iterations) \ + for (int iterator = 0; iterator < iterations; iterator++) +// END V5 MACROS + + +// Robot configuration code. +controller vexController = controller(primary); // Instance of the VEX controller +motor leftMotorA = motor(PORT19, ratio6_1, false); +motor leftMotorB = motor(PORT20, ratio6_1, false); +motor_group LeftDriveSmart = motor_group(leftMotorA, leftMotorB); +motor rightMotorA = motor(PORT9, ratio6_1, true); +motor rightMotorB = motor(PORT10, ratio6_1, true); +motor_group RightDriveSmart = motor_group(rightMotorA, rightMotorB); +drivetrain Drivetrain = drivetrain(LeftDriveSmart, RightDriveSmart, 319.19, 295, 40, mm, 1); + +motor WingsMotorA = motor(PORT15, ratio18_1, true); +motor WingsMotorB = motor(PORT5, ratio18_1, false); +motor_group Wings = motor_group(WingsMotorA, WingsMotorB); + + + + + +// Forward declaration to resolve circular dependency + + + + + +// Helper to make playing sounds from the V5 in VEXcode easier and +// keeps the code cleaner by making it clear what is happening. +void playVexcodeSound(const char *soundName) { + printf("VEXPlaySound:%s\n", soundName); + wait(5, msec); +} + +class CustomController { +private: + + bool recording = false; + + struct ControllerState { + uint32_t timestamp = 0; + int8_t ButtonA = false; + int8_t ButtonB = false; + int8_t ButtonX = false; + int8_t ButtonY = false; + int8_t ButtonUp = false; + int8_t ButtonDown = false; + int8_t ButtonLeft = false; + int8_t ButtonRight = false; + int8_t ButtonL1 = false; + int8_t ButtonL2 = false; + int8_t ButtonR1 = false; + int8_t ButtonR2 = false; + int16_t Axis1 = 0; + int16_t Axis2 = 0; + int16_t Axis3 = 0; + int16_t Axis4 = 0; + }; + struct ControllerState state; + struct ControllerState playbackstate; + + struct RecordingData { + uint32_t recordinglength = 0; + struct ControllerState recording[100000]; + }; + struct RecordingData recordingtmp; + timer recordingtimer; + uint32_t recordingidx = 0; + int filenum = 1; + bool playback = false; + + void saveRecording(const RecordingData& myStruct, const std::string& filename) { + //std::remove(filename.c_str()); + std::ofstream file(filename, std::ios::binary); + if (file.is_open()) { + file.write(reinterpret_cast(&myStruct), sizeof(RecordingData)); + file.close(); + } + } + + void loadRecording(RecordingData& myStruct, const std::string& filename) { + std::ifstream file(filename, std::ios::binary); + if (file.is_open()) { + file.read(reinterpret_cast(&myStruct), sizeof(RecordingData)); + file.close(); + } + } + + + public: + // Constructor + + CustomController() { + } + + bool startRecording() { + if(!recording && !playback) { + recording = true; + recordingidx = 0; + recordingtimer.clear(); + return true; + } + else { + return false; // already recording + } + } + + bool stopRecording() { + if(recording) { + recording = false; + recordingtmp.recordinglength = recordingidx + 1; + char filename[1] = ""; + snprintf(filename, 2, "%d", filenum); + std::string fn = filename; + fn += ".txt"; + saveRecording(recordingtmp, fn); + return true; + } + else { + return false; // not recording + } + } + + bool startPlayback() { + if(!playback && !recording) { + char filename[1] = ""; + snprintf(filename, 2, "%d", filenum); + std::string fn = filename; + fn += ".txt"; + recordingidx = 0; + loadRecording(recordingtmp, fn); + recordingtimer.clear(); + playback = true; + return true; + } + else { + return false; + } + } + inline int32_t record(int32_t value) { + if(!recording) return value; + state.timestamp = recordingtimer.time(); + recordingtmp.recording[recordingidx] = state; + recordingidx++; + wait(1,msec); + return value; + } + + bool __update_struct() { + if(!playback) return false; + + if (recordingidx >= recordingtmp.recordinglength) { + stopPlayback(); + return true; + } + else if ( recordingtmp.recording[recordingidx].timestamp <= recordingtimer.time() ) { + recordingidx++; + //playbackstate = recordingtmp.recording[recordingidx]; + + //wait(1,msec); + return true; + } else { + playbackstate = recordingtmp.recording[recordingidx]; + return false; + } + } + + + void stopPlayback() { + playback = false; + vexController.Screen.setCursor(3,1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print(filenum); + } + bool update_struct() { + while (playback && __update_struct()) { + wait(0, msec); + } + + /*vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.setCursor(2,1); + vexController.Screen.print(recordingidx); + vexController.Screen.setCursor(3,1); + vexController.Screen.print(playbackstate.Axis1);*/ + + return true; + } + + void recordingloop() { + if(vexController.ButtonLeft.pressing() && !recording && !playback) { + wait(250, msec); + startRecording(); + vexController.Screen.setCursor(3,1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print("Recording"); + } + if(vexController.ButtonLeft.pressing() && recording && !playback) { + stopRecording(); + vexController.Screen.setCursor(3,1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print(filenum); + wait(250, msec); + } + if(vexController.ButtonRight.pressing() && !recording && !playback) { + wait(250, msec); + startPlayback(); + vexController.Screen.setCursor(3,1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print("Playing"); + } + if (vexController.ButtonUp.pressing()) { + filenum ++; + vexController.Screen.setCursor(3, 1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print(filenum); + wait(250, msec); + } + if (vexController.ButtonDown.pressing()) { + filenum --; + vexController.Screen.setCursor(3, 1); + vexController.Screen.clearLine(); + vexController.Screen.clearScreen(); + vexController.Screen.print(filenum); + wait(250, msec); + } + + } + // Check if a button is pressed + bool ButtonA() { + if(playback) { + update_struct(); + return playbackstate.ButtonA; + } + return record(state.ButtonA = vexController.ButtonA.pressing()); + } + + bool ButtonB() { + if(playback) { + update_struct(); + return playbackstate.ButtonB; + } + return record(state.ButtonB = vexController.ButtonB.pressing()); + } + + bool ButtonX() { + if(playback) { + update_struct(); + return playbackstate.ButtonX; + } + return record(state.ButtonX = vexController.ButtonX.pressing()); + } + + bool ButtonY() { + if(playback) { + update_struct(); + return playbackstate.ButtonY; + } + return record(state.ButtonY = vexController.ButtonY.pressing()); + } + + bool ButtonUp() { + if(playback) { + update_struct(); + return playbackstate.ButtonUp; + } + return record(state.ButtonUp = vexController.ButtonUp.pressing()); + } + + bool ButtonDown() { + if(playback) { + update_struct(); + return playbackstate.ButtonDown; + } + return record(state.ButtonDown = vexController.ButtonDown.pressing()); + } + + bool ButtonLeft() { + if(playback) { + update_struct(); + return playbackstate.ButtonLeft; + } + return record(state.ButtonLeft = vexController.ButtonLeft.pressing()); + } + + bool ButtonRight() { + if(playback) { + update_struct(); + return playbackstate.ButtonRight; + } + return record(state.ButtonRight = vexController.ButtonRight.pressing()); + } + + bool ButtonL1() { + if(playback) { + update_struct(); + return playbackstate.ButtonL1; + } + return record(state.ButtonL1 = vexController.ButtonL1.pressing()); + } + + bool ButtonL2() { + if(playback) { + update_struct(); + return playbackstate.ButtonL2; + } + return record(state.ButtonL2 = vexController.ButtonL2.pressing()); + } + + bool ButtonR1() { + if(playback) { + update_struct(); + return playbackstate.ButtonR1; + } + return record(state.ButtonR1 = vexController.ButtonR1.pressing()); + } + + bool ButtonR2() { + if(playback) { + update_struct(); + return playbackstate.ButtonR2; + } + return record(state.ButtonR2 = vexController.ButtonR2.pressing()); + } + + // Getters for Axis values + int Axis1() { + if(playback) { + update_struct(); + return playbackstate.Axis1; + } + return record(state.Axis1 = vexController.Axis1.position(percent)); + } + + int Axis2() { + if(playback) { + update_struct(); + return playbackstate.Axis2; + } + return record(state.Axis2 = vexController.Axis2.position(percent)); + } + + int Axis3() { + if(playback) { + update_struct(); + return playbackstate.Axis3; + } + return record(state.Axis3 = vexController.Axis3.position(percent)); + } + + int Axis4() { + if(playback) { + update_struct(); + return playbackstate.Axis4; + } + return record(state.Axis4 = vexController.Axis4.position(percent)); + } + + // Add more functionalities as needed +}; + +CustomController Controller1; + +// define variable for remote controller enable/disable +bool RemoteControlCodeEnabled = true; +// define variables used for controlling motors based on controller inputs +bool DrivetrainLNeedsToBeStopped_Controller1 = true; +bool DrivetrainRNeedsToBeStopped_Controller1 = true; + +// define a task that will handle monitoring inputs from Controller1 +int rc_auto_loop_function_Controller1() { + // process the controller input every 20 milliseconds + // update the motors based on the input values + while(true) { + + + if(RemoteControlCodeEnabled) { + + } + wait(5, msec); + } + return 0; +} + +task rc_auto_loop_task_Controller1(rc_auto_loop_function_Controller1); + +#pragma endregion VEXcode Generated Robot Configuration +// Include the V5 Library + + +// Allows for easier use of the VEX Library +using namespace vex; + +competition Competition; + +float myVariable; + +// "when started" hat block +int whenStarted1() { + return 0; +} + +void drive() { + while (true) { + //Controller1.recordingloop(); + // calculate the drivetrain motor velocities from the controller joystick axies + // left = Axis3 + // right = Axis2 + int drivetrainLeftSideSpeed = Controller1.Axis3(); + int drivetrainRightSideSpeed = Controller1.Axis2(); + + // check if the value is inside of the deadband range + if (drivetrainLeftSideSpeed < 5 && drivetrainLeftSideSpeed > -5) { + // check if the left motor has already been stopped + if (DrivetrainLNeedsToBeStopped_Controller1) { + // stop the left drive motor + LeftDriveSmart.stop(); + // tell the code that the left motor has been stopped + DrivetrainLNeedsToBeStopped_Controller1 = false; + } + } else { + // reset the toggle so that the deadband code knows to stop the left motor nexttime the input is in the deadband range + DrivetrainLNeedsToBeStopped_Controller1 = true; + } + // check if the value is inside of the deadband range + if (drivetrainRightSideSpeed < 5 && drivetrainRightSideSpeed > -5) { + // check if the right motor has already been stopped + if (DrivetrainRNeedsToBeStopped_Controller1) { + // stop the right drive motor + RightDriveSmart.stop(); + // tell the code that the right motor has been stopped + DrivetrainRNeedsToBeStopped_Controller1 = false; + } + } else { + // reset the toggle so that the deadband code knows to stop the right motor next time the input is in the deadband range + DrivetrainRNeedsToBeStopped_Controller1 = true; + } + + // only tell the left drive motor to spin if the values are not in the deadband range + if (DrivetrainLNeedsToBeStopped_Controller1) { + LeftDriveSmart.setVelocity(drivetrainLeftSideSpeed, percent); + LeftDriveSmart.spin(forward); + } + // only tell the right drive motor to spin if the values are not in the deadband range + if (DrivetrainRNeedsToBeStopped_Controller1) { + RightDriveSmart.setVelocity(drivetrainRightSideSpeed, percent); + RightDriveSmart.spin(forward); + } + + if (Controller1.ButtonR1()) { + Wings.setStopping(coast); + Wings.setMaxTorque(100.0, percent); + Wings.setVelocity(100.0, percent); + Wings.spin(forward); + //waitUntil((!Controller1.ButtonR1())); + } + else if (Controller1.ButtonR2()) { + Wings.setStopping(coast); + Wings.setMaxTorque(100.0, percent); + Wings.setVelocity(100.0, percent); + Wings.spin(reverse); + //waitUntil((!Controller1.ButtonR2())); + } + else if(Controller1.ButtonX()) { + Wings.stop(); + } + wait(5,msec); + // wait before repeating the process + + } +} +// "when autonomous" hat block +int onauton_autonomous_0() { + Controller1.startPlayback(); + drive(); + + + return 0; +} + +// "when driver control" hat block +int ondriver_drivercontrol_0() { + Controller1.stopPlayback(); + drive(); + + return 0; +} + +void VEXcode_driver_task() { + // Start the driver control tasks.... + vex::task drive0(ondriver_drivercontrol_0); + while(Competition.isDriverControl() && Competition.isEnabled()) {this_thread::sleep_for(10);} + drive0.stop(); + return; +} + +void VEXcode_auton_task() { + // Start the auton control tasks.... + vex::task auto0(onauton_autonomous_0); + while(Competition.isAutonomous() && Competition.isEnabled()) {this_thread::sleep_for(10);} + auto0.stop(); + return; +} + + + +int main() { + vex::competition::bStopTasksBetweenModes = false; + Competition.autonomous(VEXcode_auton_task); + Competition.drivercontrol(VEXcode_driver_task); + + // register event handlers + + wait(15, msec); + // post event registration + + // set default print color to black + printf("\033[30m"); + + // wait for rotation sensor to fully initialize + wait(30, msec); + + whenStarted1(); +} + diff --git a/vex/mkenv.mk b/vex/mkenv.mk new file mode 100644 index 0000000..264d3be --- /dev/null +++ b/vex/mkenv.mk @@ -0,0 +1,110 @@ +# VEXcode mkenv.mk 2022_06_26_01 + +# macros to help with paths that include spaces +sp = $() $() +qs = $(subst ?, ,$1) +sq = $(subst $(sp),?,$1) + +# default platform and build location +PLATFORM = vexv5 +BUILD = build + +# version for clang headers +ifneq ("$(origin HEADERS)", "command line") +HEADERS = 8.0.0 +endif + +# Project name passed from app +ifeq ("$(origin P)", "command line") +PROJECT := $(P) +else +PROJECT := $(call qs,$(notdir $(call sq,${CURDIR}))) +endif + +# check if the PROJECT name contains any whitespace +ifneq (1,$(words $(PROJECT))) +$(error Project name cannot contain whitespace: $(PROJECT)) +endif + +# SDK path passed from app +# if not set then environmental variabled used +ifeq ("$(origin T)", "command line") +VEX_SDK_PATH = $(T) +endif +# backup if still not set +VEX_SDK_PATH ?= ${HOME}/sdk + +# printf_float flag name passed from app (not used in this version) +ifeq ("$(origin PRINTF_FLOAT)", "command line") +PRINTF_FLAG = -u_printf_float +endif + +# Verbose flag passed from app +ifeq ("$(origin V)", "command line") +BUILD_VERBOSE=$(V) +endif + +# allow verbose to be set by makefile if not set by app +ifndef VERBOSE +BUILD_VERBOSE ?= 0 +else +BUILD_VERBOSE ?= $(VERBOSE) +endif + +# use verbose flag +ifeq ($(BUILD_VERBOSE),0) +Q = @ +else +Q = +endif + +# compile and link tools +CC = clang +CXX = clang +OBJCOPY = arm-none-eabi-objcopy +SIZE = arm-none-eabi-size +LINK = arm-none-eabi-ld +ARCH = arm-none-eabi-ar +ECHO = @echo +DEFINES = -DVexV5 + +# platform specific macros +ifeq ($(OS),Windows_NT) +$(info windows build for platform $(PLATFORM)) +SHELL = cmd.exe +MKDIR = md "$(@D)" 2> nul || : +RMDIR = rmdir /S /Q +CLEAN = $(RMDIR) $(BUILD) 2> nul || : +else +# which flavor of linux +UNAME := $(shell sh -c 'uname -sm 2>/dev/null || Unknown') +$(info unix build for platform $(PLATFORM) on $(UNAME)) +MKDIR = mkdir -p "$(@D)" 2> /dev/null || : +RMDIR = rm -rf +CLEAN = $(RMDIR) $(BUILD) 2> /dev/null || : +endif + +# toolchain include and lib locations +TOOL_INC = -I"$(VEX_SDK_PATH)/$(PLATFORM)/clang/$(HEADERS)/include" -I"$(VEX_SDK_PATH)/$(PLATFORM)/gcc/include/c++/4.9.3" -I"$(VEX_SDK_PATH)/$(PLATFORM)/gcc/include/c++/4.9.3/arm-none-eabi/armv7-ar/thumb" -I"$(VEX_SDK_PATH)/$(PLATFORM)/gcc/include" +TOOL_LIB = -L"$(VEX_SDK_PATH)/$(PLATFORM)/gcc/libs" + +# compiler flags +CFLAGS_CL = -target thumbv7-none-eabi -fshort-enums -Wno-unknown-attributes -U__INT32_TYPE__ -U__UINT32_TYPE__ -D__INT32_TYPE__=long -D__UINT32_TYPE__='unsigned long' +CFLAGS_V7 = -march=armv7-a -mfpu=neon -mfloat-abi=softfp +CFLAGS = ${CFLAGS_CL} ${CFLAGS_V7} -Os -Wall -Werror=return-type -ansi -std=gnu99 $(DEFINES) +CXX_FLAGS = ${CFLAGS_CL} ${CFLAGS_V7} -Os -Wall -Werror=return-type -fno-rtti -fno-threadsafe-statics -fno-exceptions -std=gnu++11 -ffunction-sections -fdata-sections $(DEFINES) + +# linker flags +LNK_FLAGS = -nostdlib -T "$(VEX_SDK_PATH)/$(PLATFORM)/lscript.ld" -R "$(VEX_SDK_PATH)/$(PLATFORM)/stdlib_0.lib" -Map="$(BUILD)/$(PROJECT).map" --gc-section -L"$(VEX_SDK_PATH)/$(PLATFORM)" ${TOOL_LIB} + +# future statuc library +PROJECTLIB = lib$(PROJECT) +ARCH_FLAGS = rcs + +# libraries +LIBS = --start-group -lv5rt -lstdc++ -lc -lm -lgcc --end-group + +# include file paths +INC += $(addprefix -I, ${INC_F}) +INC += -I"$(VEX_SDK_PATH)/$(PLATFORM)/include" +INC += ${TOOL_INC} diff --git a/vex/mkrules.mk b/vex/mkrules.mk new file mode 100644 index 0000000..a45bbdc --- /dev/null +++ b/vex/mkrules.mk @@ -0,0 +1,32 @@ +# VEXcode mkrules.mk 2019_03_26_01 + +# compile C files +$(BUILD)/%.o: %.c $(SRC_H) + $(Q)$(MKDIR) + $(ECHO) "CC $<" + $(Q)$(CC) $(CFLAGS) $(INC) -c -o $@ $< + +# compile C++ files +$(BUILD)/%.o: %.cpp $(SRC_H) $(SRC_A) + $(Q)$(MKDIR) + $(ECHO) "CXX $<" + $(Q)$(CXX) $(CXX_FLAGS) $(INC) -c -o $@ $< + +# create executable +$(BUILD)/$(PROJECT).elf: $(OBJ) + $(ECHO) "LINK $@" + $(Q)$(LINK) $(LNK_FLAGS) -o $@ $^ $(LIBS) + $(Q)$(SIZE) $@ + +# create binary +$(BUILD)/$(PROJECT).bin: $(BUILD)/$(PROJECT).elf + $(Q)$(OBJCOPY) -O binary $(BUILD)/$(PROJECT).elf $(BUILD)/$(PROJECT).bin + +# create archive +$(BUILD)/$(PROJECTLIB).a: $(OBJ) + $(Q)$(ARCH) $(ARCH_FLAGS) $@ $^ + +# clean project +clean: + $(info clean project) + $(Q)$(CLEAN)