Compare commits

...

73 Commits

Author SHA1 Message Date
Tyler Veness
35eb90c135 Fix "'dimensionless' ambiguous symbol" error (#2382)
A typedef for units::dimensionless::dimensionless is defined, which
conflicted with the namespace when we added "using namespace
dimensionless". This patch reverts the "using namespace" directive.
"using" directives were added to pull three of the four relevant
typedefs but avoid the "dimensionless" type conflict.

This issue was first introduced in #2301.
2020-02-21 00:41:50 -08:00
Dustin Spicuzza
761f79385a Add SimulationInit and SimulationPeriodic functions (#2377)
Fixes #2375
2020-02-18 23:05:16 -08:00
Thad House
554bda3332 HAL: Expose NetComm SendConsoleLine (#2337)
This can be use to synchronize writes between threads, assuming writes all go through this and not stdout.
2020-02-18 20:44:40 -08:00
Thad House
2a968df779 Add method for releasing a waiting interrupt (#2347)
Useful for a new high level interrupt implementation.
2020-02-18 20:41:42 -08:00
sciencewhiz
30ccd13b69 Add methods for getting color of an LED (#2366)
Also fix rounding in Color.
2020-02-18 20:40:03 -08:00
Thad House
60c09ea51f Fix notifier race happening with very fast notifiers (#2370)
What would happen is the Stop() call would happen between the notifier loop being triggered and calling UpdateAlarm(). This would cause the Update to overwrite the stop.
2020-02-18 20:38:05 -08:00
Oblarg
65eab93527 Fix DifferentialDriveVoltageConstraint for tight turns w/ zero velocity (#2341) 2020-02-15 12:36:16 -08:00
sciencewhiz
a226ad8509 Set a default option for Sendable Chooser in examples (#2361) 2020-02-15 09:54:12 -08:00
Peter Johnson
31f4fd70ce Sim GUI: Fix crash when field/robot image load is canceled (#2362) 2020-02-15 09:53:21 -08:00
Dustin Spicuzza
7275ab9837 Add headerpad_max_install_names to Mac builds (#2333)
This allows dylib paths to be rewritten to a larger size by downstream tools.
2020-02-10 21:52:58 -08:00
Dustin Spicuzza
5b3facc63b TrapezoidProfile: Make units public (#2342) 2020-02-10 21:44:21 -08:00
CircuitCraft42
0f313fb9ab cmake: Improved portability of OpenCV Java binding search (#2348)
The CMake option OPENCV_JAVA_INSTALL_DIR can be set to the location
to search for the jar file. Note that the file name cannot be
changed, as, after checking several Linux package repositories,
that seems to be constant across all of them.

Fixes #2346.
2020-02-10 17:30:54 -08:00
Oblarg
05b7593e66 C++ circular_buffer: support types not implicitly convertible from int (#2350)
Also fixes two cases of returning a reference to a constant.
2020-02-08 13:35:21 -08:00
sciencewhiz
1b85066d26 Fix C++ ParallelRaceGroup multiple calls behavior (#2339)
The Java version was correct, but the C++ version would only run once.
2020-02-08 10:26:06 -08:00
sciencewhiz
e93b64f58d Add note that only a single instance of ADXRS450 is supported (#2349) 2020-02-08 10:24:18 -08:00
Oblarg
f0a18f31e7 Timer: add hasElapsed, advanceIfElapsed (#2322)
The current hasPeriodPassed() function is confusing.  In preparation for deprecating it,
add new advanceIfElapsed() function with same functionality and hasElapsed() function
which only checks that the time period has elapsed and does not advance the timer.

Also fix a couple of incorrect usages of hasPeriodPassed().
2020-02-08 10:23:29 -08:00
Vasista Vovveti
29c82527a5 Fix typo in ADXL sim double creation (#2332)
Sets m_simY to the virtual Y acceleration.
2020-02-04 20:15:25 -08:00
Peter Johnson
c165dc5e50 Simulation GUI: Add 2D field view (#2261)
The field image and robot image can be loaded or just a wireframe used.
The robot can be moved and rotated with a mouse click + drag.
The robot position is settable in robot code via the Field2d class.
2020-02-01 21:30:23 -08:00
sciencewhiz
42da07396c Add missing references to f in PIDSubsystem javadoc (#2318) 2020-01-31 19:18:17 -08:00
Jonathan Noyola
20e6c04059 Fix cmake install of hal generated files (#2320) 2020-01-31 19:18:00 -08:00
Declan Freeman-Gleason
ff5d3e5b36 RamseteController: Add setEnabled method (#2313) 2020-01-27 21:53:00 -08:00
sciencewhiz
6cc68ab503 Update MavenArtifacts.md (#2289) 2020-01-27 19:45:53 -08:00
Thad House
068465146b Fix null check order in SendableRegistry (#2314) 2020-01-27 19:43:31 -08:00
Thad House
3bcf8057d4 Add more detail to RuntimeLoader failure message (#2309)
Now specifies the C++ runtime is needed, along with more detail to make it easier to troubleshoot and not lose exception information.
2020-01-27 14:10:46 -08:00
David Vo
8039a6c525 Add missing include to ShuffleboardEventImportance (#2310) 2020-01-26 21:03:15 -08:00
Prateek Machiraju
558c020cca Fix duplicated state when using quintic splines (#2307)
Generating a trajectory using quintic splines caused a duplicated state at all knot points.
2020-01-24 23:10:28 -08:00
Prateek Machiraju
7797da78f5 Add missing methods to Timed and TimedSkeleton templates (#2306) 2020-01-24 20:01:23 -08:00
Oblarg
0ab81d768f Add feed-forward and slew rate limiting to advanced drive examples (#2301) 2020-01-23 18:07:38 -08:00
Oblarg
1cee5ccb93 Feed RobotDrive watchdog in RamseteCommand example (#2298) 2020-01-23 17:41:45 -08:00
Dan Katzuv
3ce01b5ac2 Fix DriveSubsystem.getHeading Java documentation (#2282) 2020-01-23 16:46:53 -08:00
sciencewhiz
e6aa8f3ff4 Update toolchain link in readme (#2304) 2020-01-23 16:43:06 -08:00
Peter Johnson
9d7b087972 Simulation GUI: Add support for custom names (#2292)
This allows users to right click on just about any name in the GUI (e.g. "PWM[0]") and rename it (e.g. "Left Motor [0]"). The index portion is not editable. The name is saved into imgui.ini so it's persistent.
2020-01-20 22:47:36 -08:00
Peter Johnson
bb184ed481 Simulation GUI: Refactor ini saving (#2291) 2020-01-20 21:49:03 -08:00
Peter Johnson
b9b31069cc Fix C++ POVButton (#2294)
Also add unit test.
2020-01-20 21:35:19 -08:00
Peter Johnson
d0cf4e8882 Change sim Filesystem.getDeployDirectory() to src/main/deploy (#2293) 2020-01-19 16:34:45 -08:00
sciencewhiz
02fb850761 Add new speed controllers to shuffleboard docs (#2288)
Also fix java links in C++ docs and a few typos.
2020-01-19 14:26:44 -08:00
sciencewhiz
ac8177e10d Fix GearsBot log methods not being called periodically (#2280)
Add logging for C++ Wrist and Claw
2020-01-17 20:18:15 -08:00
Tyler Veness
2eb5c54476 TrapezoidProfile: Fix aliasing of m_initial to result in calculate() (#2284)
Fixes #2283.
2020-01-17 20:17:21 -08:00
Peter Johnson
0e206e69cf Remove Set Camera Server Shared message (#2285) 2020-01-17 20:16:24 -08:00
Peter Johnson
b1357cace7 Fix LiveWindow SetEnabled C++ std::bad_function_call (#2281)
It was missing a null check.
2020-01-16 00:34:51 -08:00
Thad House
37202b6f28 Add missing SensorUtil::kAnalogOutputs (#2276) 2020-01-15 21:34:28 -08:00
Thad House
2ac0d52960 Remove AnalogTrigger::SetDutyCycle (#2275) 2020-01-15 21:33:58 -08:00
Thad House
dbe1e6f466 Fix missing SetDutyCycleSimDevice on Rio (#2274) 2020-01-15 21:33:35 -08:00
Chris Russell
a61fcbd68d Make Button class concrete (#2244) 2020-01-15 18:59:51 -08:00
Thad House
fe597eeba1 Fix SPI DIO count for sim (#2272)
Only 26 DIO were detectable, not 31.
2020-01-15 18:58:14 -08:00
Jonathan Leitschuh
e213a47efd Official Gradle Wrapper Validation GitHub Action (#2273)
See: https://github.com/gradle/wrapper-validation-action
2020-01-15 14:21:50 -08:00
Peter Johnson
dcb96cb50c TrajectoryGenerator: Allow replacement of error reporting function (C++) (#2267)
C++ version of #2234.
2020-01-13 20:36:16 -08:00
Austin Shalit
60d48fec57 Fix Java static colors having zero values (#2269)
Also add test for this.
2020-01-13 12:21:44 -08:00
Austin Shalit
ee8475d21f Run wpiformat (#2270) 2020-01-13 12:19:08 -08:00
Peter Johnson
f47e318131 C++ units: Interoperate with Windows headers min/max (#2268) 2020-01-12 22:52:36 -08:00
Thad House
cb66bcca3c Add callback handlers for LiveWindow (#2053)
Fixes #2223
2020-01-12 22:37:24 -08:00
Simon Abrelat
73302f6162 Fix color name typos (#2265) 2020-01-12 22:15:19 -08:00
Oblarg
cba21a768f Fix C++ JoystickButton and POVButton (#2259)
C++ JoystickButton and POVButton were both nonfunctional due to slicing when trigger passes itself by value to the button scheduler it creates.

Fix is to remove the virtual Get() method entirely and use only the m_isActive functor; since the subclass now passes the button condition back as a functor to the base class, in which it's stored as a member, it will now still work after being sliced.
2020-01-12 14:57:28 -08:00
Peter Johnson
822e75ec45 Simulator GUI: Handle save file having window size=0 (#2260)
This should never happen, but if it does, it's not recoverable without
either deleting imgui.ini or editing it manually.
2020-01-12 01:37:53 -08:00
Peter Johnson
108ddfa1b4 Fix Pi Camera auto exposure property name (#2258) 2020-01-11 15:04:29 -08:00
Prateek Machiraju
d4c8ee5915 Add Axis enum in XboxController (#2253) 2020-01-10 23:43:19 -08:00
Peter Johnson
ab9647ff5b CommandScheduler: Don't store NetworkTableEntry 2020-01-10 23:42:18 -08:00
Peter Johnson
6666d3be42 SendableBuilder: Allow multiple updateTable functions
This fixes cases like CommandScheduler not working when added to both
LiveWindow and SmartDashboard.
2020-01-10 23:42:18 -08:00
Peter Johnson
795086b4cf Fix Demangle when used standalone (#2256) 2020-01-10 23:41:40 -08:00
Peter Johnson
56765cf49a C++ CommandBase: Don't add to LiveWindow (#2255) 2020-01-10 20:37:49 -08:00
Peter Johnson
bf7012fa2d Fix new CommandScheduler.cancelAll() (#2251)
When called outside the run loop, it would result in a CME in Java.
2020-01-10 16:10:16 -08:00
Peter Johnson
10e8fdb724 Make C++ IterativeRobotBase and RobotBase constructor and destructor public (#2242) 2020-01-08 23:17:12 -08:00
Peter Johnson
790dc552ca Add quirks support for Pi camera (#2241)
- Valid video modes (native modes plus some low-res modes)
- Exposure setting
2020-01-07 20:21:28 -08:00
Peter Johnson
0ec8ed6c05 Make C++ controller using declarations public (#2240) 2020-01-06 23:30:47 -08:00
Tyler Veness
832693617f Add missing definition for PIDController::SetPID() (#2239)
Fixes #2238.
2020-01-06 21:17:16 -08:00
sciencewhiz
772ef8f961 Update Maven location to artifactory (#2235) 2020-01-06 20:13:42 -08:00
Peter Johnson
95b6cd2dd9 TrajectoryGenerator: Allow replacement of error reporting function (#2234)
This is needed to avoid use of DriverStation if used from desktop applications
such as PathWeaver.
2020-01-05 16:01:31 -08:00
sciencewhiz
ce1ac17dfb Remove experimental from new command example descriptions (#2226) 2020-01-04 19:57:31 -08:00
Thad House
b2f7a6b651 Add clarification to LED about length and # of drivers (#2231) 2020-01-04 19:57:10 -08:00
Peter Johnson
bedbef7999 Revert "Remove -no-module-directories flag from javadoc build (#2201)" (#2229)
This reverts commit f9a11cce5e.
2020-01-04 19:52:43 -08:00
Thad House
bc159a92a7 Default sim voltage to 12v, make user rails active (#2224) 2020-01-04 15:07:47 -08:00
Austin Shalit
f50d710a5e Make color ctor public (#2222) 2020-01-04 08:28:18 -08:00
Peter Johnson
bc8f68bec7 Add sim HAL_WaitForCachedControlData (#2221) 2020-01-03 22:38:45 -08:00
210 changed files with 4741 additions and 866 deletions

View File

@@ -0,0 +1,10 @@
name: "Validate Gradle Wrapper"
on: [push]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1

View File

@@ -11,6 +11,7 @@ cppSrcFileInclude {
generatedFileExclude {
FRCNetComm\.java$
simulation/gz_msgs/src/include/simulation/gz_msgs/msgs\.h$
simulation/halsim_gui/src/main/native/include/portable-file-dialogs\.h$
}
repoRootNameOverride {

View File

@@ -55,6 +55,7 @@ option(USE_VCPKG_LIBUV "Use vcpkg libuv" OFF)
option(USE_VCPKG_EIGEN "Use vcpkg eigen" OFF)
option(FLAT_INSTALL_WPILIB "Use a flat install directory" OFF)
option(WITH_SIMULATION_MODULES "build simulation modules" OFF)
set(OPENCV_JAVA_INSTALL_DIR "" CACHE PATH "Location to search for the OpenCV jar file")
if (NOT WITHOUT_JAVA AND NOT BUILD_SHARED_LIBS)
message(FATAL_ERROR "
@@ -64,6 +65,15 @@ FATAL: Cannot build static libs with Java enabled.
")
endif()
if (WITHOUT_JAVA OR WITHOUT_CSCORE)
if(NOT "${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
message(WARNING "
WARNING: OpenCV Java dir set but java is not enabled!
It will be ignored.
")
endif()
endif()
set( wpilib_dest wpilib)
set( include_dest wpilib/include )
set( main_lib_dest wpilib/lib )

View File

@@ -5,8 +5,8 @@ WPILib publishes its built artifacts to our Maven server for use by downstream p
## Repositories
We provide two repositories. These repositories are:
* (Release) https://first.wpi.edu/FRC/roborio/maven/release/
* (Development) https://first.wpi.edu/FRC/roborio/maven/development/
* (Release) https://frcmaven.wpi.edu/artifactory/release/
* (Development) https://frcmaven.wpi.edu/artifactory/development/
The release repository is where official WPILib releases are pushed.
The development repository is where development releases of every commit to [master](https://github.com/wpilibsuite/allwpilib/tree/master) is pushed.
@@ -72,6 +72,10 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* hal
* wpiutil
* halsim
* imgui
* wpiutil
* ntcore
* wpiutil
@@ -85,7 +89,6 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* opencv
* wpiutil
* wpilibj
* hal
* cameraserver
@@ -93,10 +96,35 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* cscore
* wpiutil
* wpilibc
* hal
* cameraserver
* ntcore
* cscore
* wpiutil
* wpilibNewCommands
* wpilibc
* hal
* cameraserver
* ntcore
* cscore
* wpiutil
* wpilibNewCommands
* wpilibc
* hal
* cameraserver
* ntcore
* cscore
* wpiutil
### Third Party Artifacts
This repository provides the builds of the following third party software.
All artifacts are based at `edu.wpi.first.thirdparty.frcYEAR` in the repository.
* googletest
* imgui
* opencv

View File

@@ -34,6 +34,8 @@ The following build options are available:
* TODO
* EXTERNAL_HAL_FILE
* TODO
* OPENCV_JAVA_INSTALL_DIR
* Set this option to the location of the archive of the OpenCV Java bindings (it should be called opencv-xxx.jar, with the x'es being version numbers). NOTE: set it to the LOCATION of the file, not the file itself!
## Build Setup

View File

@@ -27,7 +27,7 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
- On Linux, GCC works fine
- On Windows, you need Visual Studio 2019 (the free community edition works fine).
Make sure to select the C++ Programming Language for installation
- [ARM Compiler Toolchain](https://github.com/wpilibsuite/toolchain-builder/releases)
- [ARM Compiler Toolchain](https://github.com/wpilibsuite/roborio-toolchain/releases)
* Note that for 2020 and beyond, you should use version 7 or greater of GCC
- Doxygen (Only required if you want to build the C++ documentation)

View File

@@ -44,6 +44,7 @@ Team 254 Library wpilibj/src/main/java/edu/wpi/first/wpilibj/spline/SplineP
wpilibc/src/main/native/include/spline/SplineParameterizer.h
wpilibc/src/main/native/include/trajectory/TrajectoryParameterizer.h
wpilibc/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp
Portable File Dialogs simulation/halsim_gui/src/main/native/include/portable-file-dialogs.h
==============================================================================

View File

@@ -69,7 +69,9 @@ if (NOT WITHOUT_JAVA)
#find java files, copy them locally
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/OpenCV/java/)
if("${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/OpenCV/java/)
endif()
find_file(OPENCV_JAR_FILE NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin NO_DEFAULT_PATH)
find_file(OPENCV_JNI_FILE NAMES libopencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.so

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -102,7 +102,7 @@ static bool IsPercentageProperty(wpi::StringRef name) {
if (name.startswith("raw_")) name = name.substr(4);
return name == "brightness" || name == "contrast" || name == "saturation" ||
name == "hue" || name == "sharpness" || name == "gain" ||
name == "exposure_absolute";
name == "exposure_absolute" || name == "exposure_time_absolute";
}
static constexpr const int quirkLifeCamHd3000[] = {
@@ -112,6 +112,11 @@ static constexpr char const* quirkPS3EyePropExAuto = "auto_exposure";
static constexpr char const* quirkPS3EyePropExValue = "exposure";
static constexpr const int quirkPS3EyePropExAutoOn = 0;
static constexpr const int quirkPS3EyePropExAutoOff = 1;
static constexpr char const* quirkPiCameraPropExAuto = "auto_exposure";
static constexpr char const* quirkPiCameraPropExValue =
"exposure_time_absolute";
static constexpr const int quirkPiCameraPropExAutoOn = 0;
static constexpr const int quirkPiCameraPropExAutoOff = 1;
int UsbCameraImpl::RawToPercentage(const UsbCameraProperty& rawProp,
int rawValue) {
@@ -1112,6 +1117,25 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
}
}
// The Pi camera reports mode ranges, which we don't currently handle, so only
// provide a set of discrete modes; list based on
// https://picamera.readthedocs.io/en/release-1.10/fov.html
if (modes.empty() && m_picamera) {
for (VideoMode::PixelFormat pixelFormat :
{VideoMode::kYUYV, VideoMode::kMJPEG, VideoMode::kBGR}) {
modes.emplace_back(pixelFormat, 1920, 1080, 30);
modes.emplace_back(pixelFormat, 2592, 1944, 15);
modes.emplace_back(pixelFormat, 1296, 972, 42);
modes.emplace_back(pixelFormat, 1296, 730, 49);
modes.emplace_back(pixelFormat, 640, 480, 90);
modes.emplace_back(pixelFormat, 320, 240, 90);
modes.emplace_back(pixelFormat, 160, 120, 90);
modes.emplace_back(pixelFormat, 640, 480, 60);
modes.emplace_back(pixelFormat, 320, 240, 60);
modes.emplace_back(pixelFormat, 160, 120, 60);
}
}
{
std::scoped_lock lock(m_mutex);
m_videoModes.swap(modes);
@@ -1192,6 +1216,7 @@ void UsbCameraImpl::SetQuirks() {
wpi::StringRef desc = GetDescription(descbuf);
m_lifecam_exposure =
desc.endswith("LifeCam HD-3000") || desc.endswith("LifeCam Cinema (TM)");
m_picamera = desc.startswith("mmal service");
int deviceNum = GetDeviceNum(m_path.c_str());
if (deviceNum >= 0) {
@@ -1248,7 +1273,9 @@ void UsbCameraImpl::SetExposureAuto(CS_Status* status) {
if (m_ps3eyecam_exposure) {
SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
quirkPS3EyePropExAutoOn, status);
} else if (m_picamera) {
SetProperty(GetPropertyIndex(quirkPiCameraPropExAuto),
quirkPiCameraPropExAutoOn, status);
} else {
SetProperty(GetPropertyIndex(kPropExAuto), 3, status);
}
@@ -1258,6 +1285,9 @@ void UsbCameraImpl::SetExposureHoldCurrent(CS_Status* status) {
if (m_ps3eyecam_exposure) {
SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
quirkPS3EyePropExAutoOff, status); // manual
} else if (m_picamera) {
SetProperty(GetPropertyIndex(quirkPiCameraPropExAuto),
quirkPiCameraPropExAutoOff, status); // manual
} else {
SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
}
@@ -1267,6 +1297,9 @@ void UsbCameraImpl::SetExposureManual(int value, CS_Status* status) {
if (m_ps3eyecam_exposure) {
SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
quirkPS3EyePropExAutoOff, status); // manual
} else if (m_picamera) {
SetProperty(GetPropertyIndex(quirkPiCameraPropExAuto),
quirkPiCameraPropExAutoOff, status); // manual
} else {
SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
}
@@ -1277,6 +1310,8 @@ void UsbCameraImpl::SetExposureManual(int value, CS_Status* status) {
}
if (m_ps3eyecam_exposure) {
SetProperty(GetPropertyIndex(quirkPS3EyePropExValue), value, status);
} else if (m_picamera) {
SetProperty(GetPropertyIndex(quirkPiCameraPropExValue), value, status);
} else {
SetProperty(GetPropertyIndex(kPropExValue), value, status);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -166,6 +166,7 @@ class UsbCameraImpl : public SourceImpl {
// Quirks
bool m_lifecam_exposure{false}; // Microsoft LifeCam exposure
bool m_ps3eyecam_exposure{false}; // PS3 Eyecam exposure
bool m_picamera{false}; // Raspberry Pi camera
//
// Variables protected by m_mutex

View File

@@ -125,6 +125,7 @@ task generateJavaDocs(type: Javadoc) {
ext.entryPoint = "$destinationDir/index.html"
if (JavaVersion.current().isJava11Compatible()) {
options.addBooleanOption('-no-module-directories', true)
doLast {
// This is a work-around for https://bugs.openjdk.java.net/browse/JDK-8211194. Can be removed once that issue is fixed on JDK's side
// Since JDK 11, package-list is missing from javadoc output files and superseded by element-list file, but a lot of external tools still need it

View File

@@ -57,7 +57,7 @@ set_property(TARGET hal PROPERTY FOLDER "libraries")
install(TARGETS hal EXPORT hal DESTINATION "${main_lib_dest}")
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/hal")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen DESTINATION "${include_dest}/hal")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen/ DESTINATION "${include_dest}/hal")
if (MSVC OR FLAT_INSTALL_WPILIB)
set (hal_config_dir ${wpilib_dest})

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -130,6 +130,8 @@ public final class HAL extends JNIWrapper {
String details, String location, String callStack,
boolean printMsg);
public static native int sendConsoleLine(String line);
public static native int getPortWithModule(byte module, byte channel);
public static native int getPort(byte channel);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -38,4 +38,6 @@ public class InterruptJNI extends JNIWrapper {
public static native void setInterruptUpSourceEdge(int interruptHandle, boolean risingEdge,
boolean fallingEdge);
public static native void releaseWaitingInterrupt(int interruptHandle);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -50,6 +50,7 @@ public class DriverStationDataJNI extends JNIWrapper {
public static native void notifyNewData();
public static native void setSendError(boolean shouldSend);
public static native void setSendConsoleLine(boolean shouldSend);
public static native void resetData();
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -75,6 +75,9 @@ void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {
dutyCycleHandles->Free(dutyCycleHandle);
}
void HAL_SetDutyCycleSimDevice(HAL_EncoderHandle handle,
HAL_SimDeviceHandle device) {}
int32_t HAL_GetDutyCycleFrequency(HAL_DutyCycleHandle dutyCycleHandle,
int32_t* status) {
auto dutyCycle = dutyCycleHandles->Get(dutyCycleHandle);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -176,27 +176,27 @@ int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
if (baseLength + detailsRef.size() + locationRef.size() +
callStackRef.size() <=
65536) {
65535) {
// Pass through
retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
details, location, callStack);
} else if (baseLength + detailsRef.size() > 65536) {
} else if (baseLength + detailsRef.size() > 65535) {
// Details too long, cut both location and stack
auto newLen = 65536 - baseLength;
auto newLen = 65535 - baseLength;
std::string newDetails{details, newLen};
char empty = '\0';
retval = FRC_NetworkCommunication_sendError(
isError, errorCode, isLVCode, newDetails.c_str(), &empty, &empty);
} else if (baseLength + detailsRef.size() + locationRef.size() > 65536) {
} else if (baseLength + detailsRef.size() + locationRef.size() > 65535) {
// Location too long, cut stack
auto newLen = 65536 - baseLength - detailsRef.size();
auto newLen = 65535 - baseLength - detailsRef.size();
std::string newLocation{location, newLen};
char empty = '\0';
retval = FRC_NetworkCommunication_sendError(
isError, errorCode, isLVCode, details, newLocation.c_str(), &empty);
} else {
// Stack too long
auto newLen = 65536 - baseLength - detailsRef.size() - locationRef.size();
auto newLen = 65535 - baseLength - detailsRef.size() - locationRef.size();
std::string newCallStack{callStack, newLen};
retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode,
details, location,
@@ -229,6 +229,18 @@ int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
return retval;
}
int32_t HAL_SendConsoleLine(const char* line) {
wpi::StringRef lineRef{line};
if (lineRef.size() <= 65535) {
// Send directly
return FRC_NetworkCommunication_sendConsoleLine(line);
} else {
// Need to truncate
std::string newLine{line, 65535};
return FRC_NetworkCommunication_sendConsoleLine(newLine.c_str());
}
}
int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
return HAL_GetControlWordInternal(controlWord);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -24,6 +24,7 @@
#include <wpi/timestamp.h>
#include "HALInitializer.h"
#include "HALInternal.h"
#include "ctre/ctre.h"
#include "hal/ChipObject.h"
#include "hal/DriverStation.h"
@@ -78,6 +79,15 @@ void InitializeHAL() {
InitializeThreads();
}
} // namespace init
void ReleaseFPGAInterrupt(int32_t interruptNumber) {
if (!global) {
return;
}
int32_t status = 0;
global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
&status);
}
} // namespace hal
extern "C" {

View File

@@ -0,0 +1,15 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <stdint.h>
namespace hal {
void ReleaseFPGAInterrupt(int32_t interruptNumber);
} // namespace hal

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -13,9 +13,11 @@
#include "DigitalInternal.h"
#include "HALInitializer.h"
#include "HALInternal.h"
#include "PortsInternal.h"
#include "hal/ChipObject.h"
#include "hal/Errors.h"
#include "hal/HALBase.h"
#include "hal/handles/HandlesInternal.h"
#include "hal/handles/LimitedHandleResource.h"
@@ -268,4 +270,19 @@ void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
anInterrupt->anInterrupt->writeConfig_FallingEdge(fallingEdge, status);
}
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
int32_t* status) {
auto anInterrupt = interruptHandles->Get(interruptHandle);
if (anInterrupt == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
uint32_t interruptIndex =
static_cast<uint32_t>(getHandleIndex(interruptHandle));
hal::ReleaseFPGAInterrupt(interruptIndex);
hal::ReleaseFPGAInterrupt(interruptIndex + 8);
}
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -448,6 +448,21 @@ Java_edu_wpi_first_hal_HAL_sendError
return returnValue;
}
/*
* Class: edu_wpi_first_hal_HAL
* Method: sendConsoleLine
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_HAL_sendConsoleLine
(JNIEnv* env, jclass, jstring line)
{
JStringRef lineStr{env, line};
jint returnValue = HAL_SendConsoleLine(lineStr.c_str());
return returnValue;
}
/*
* Class: edu_wpi_first_hal_HAL
* Method: getPortWithModule

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -294,4 +294,19 @@ Java_edu_wpi_first_hal_InterruptJNI_setInterruptUpSourceEdge
CheckStatus(env, status);
}
/*
* Class: edu_wpi_first_hal_InterruptJNI
* Method: releaseWaitingInterrupt
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_InterruptJNI_releaseWaitingInterrupt
(JNIEnv* env, jclass, jint interruptHandle)
{
int32_t status = 0;
HAL_ReleaseWaitingInterrupt((HAL_InterruptHandle)interruptHandle, &status);
CheckStatus(env, status);
}
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2013-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2013-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -37,6 +37,12 @@ extern "C" {
int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
const char* details, const char* location,
const char* callStack, HAL_Bool printMsg);
/**
* Sends a line to the driver station console.
*
* @param line the line to send (null terminated)
*/
int32_t HAL_SendConsoleLine(const char* line);
/**
* Gets the current control word of the driver station.

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -153,6 +153,16 @@ void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
HAL_Bool risingEdge, HAL_Bool fallingEdge,
int32_t* status);
/**
* Releases a waiting interrupt.
*
* This will release both rising and falling waiters.
*
* @param interruptHandle the interrupt handle to release
*/
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -24,4 +24,7 @@ typedef int32_t (*HALSIM_SendErrorHandler)(
const char* location, const char* callStack, HAL_Bool printMsg);
void HALSIM_SetSendError(HALSIM_SendErrorHandler handler);
typedef int32_t (*HALSIM_SendConsoleLineHandler)(const char* line);
void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler);
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -18,6 +18,7 @@
#include <wpi/condition_variable.h>
#include <wpi/mutex.h>
#include <wpi/raw_ostream.h>
#include "HALInitializer.h"
#include "mockdata/DriverStationDataInternal.h"
@@ -29,6 +30,8 @@ static wpi::mutex newDSDataAvailableMutex;
static int newDSDataAvailableCounter{0};
static std::atomic_bool isFinalized{false};
static std::atomic<HALSIM_SendErrorHandler> sendErrorHandler{nullptr};
static std::atomic<HALSIM_SendConsoleLineHandler> sendConsoleLineHandler{
nullptr};
namespace hal {
namespace init {
@@ -47,6 +50,10 @@ void HALSIM_SetSendError(HALSIM_SendErrorHandler handler) {
sendErrorHandler.store(handler);
}
void HALSIM_SetSendConsoleLine(HALSIM_SendConsoleLineHandler handler) {
sendConsoleLineHandler.store(handler);
}
int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
const char* details, const char* location,
const char* callStack, HAL_Bool printMsg) {
@@ -105,6 +112,16 @@ int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
return retval;
}
int32_t HAL_SendConsoleLine(const char* line) {
auto handler = sendConsoleLineHandler.load();
if (handler) {
return handler(line);
}
wpi::outs() << line << "\n";
wpi::outs().flush();
return 0;
}
int32_t HAL_GetControlWord(HAL_ControlWord* controlWord) {
controlWord->enabled = SimDriverStationData->enabled;
controlWord->autonomous = SimDriverStationData->autonomous;
@@ -230,6 +247,10 @@ static int& GetThreadLocalLastCount() {
return lastCount;
}
void HAL_WaitForCachedControlData(void) {
HAL_WaitForCachedControlDataTimeout(0);
}
HAL_Bool HAL_WaitForCachedControlDataTimeout(double timeout) {
int& lastCount = GetThreadLocalLastCount();
std::unique_lock lock(newDSDataAvailableMutex);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -566,4 +566,9 @@ void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
interrupt->fireOnDown = fallingEdge;
interrupt->fireOnUp = risingEdge;
}
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
int32_t* status) {
// Requires a fairly large rewrite to get working
}
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,7 +17,7 @@ constexpr int32_t kNumAnalogOutputs = 2;
constexpr int32_t kNumCounters = 8;
constexpr int32_t kNumDigitalHeaders = 10;
constexpr int32_t kNumPWMHeaders = 10;
constexpr int32_t kNumDigitalChannels = 26;
constexpr int32_t kNumDigitalChannels = 31;
constexpr int32_t kNumPWMChannels = 20;
constexpr int32_t kNumDigitalPWMOutputs = 6;
constexpr int32_t kNumEncoders = 8;

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -462,7 +462,23 @@ Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setSendError
HALSIM_SetSendError([](HAL_Bool isError, int32_t errorCode,
HAL_Bool isLVCode, const char* details,
const char* location, const char* callStack,
HAL_Bool printMsg) { return 1; });
HAL_Bool printMsg) { return 0; });
}
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
* Method: setSendConsoleLine
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setSendConsoleLine
(JNIEnv*, jclass, jboolean shouldSend)
{
if (shouldSend) {
HALSIM_SetSendConsoleLine(nullptr);
} else {
HALSIM_SetSendConsoleLine([](const char* line) { return 0; });
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -22,17 +22,17 @@ void InitializeRoboRioData() {
RoboRioData* hal::SimRoboRioData;
void RoboRioData::ResetData() {
fpgaButton.Reset(false);
vInVoltage.Reset(0.0);
vInVoltage.Reset(12.0);
vInCurrent.Reset(0.0);
userVoltage6V.Reset(6.0);
userCurrent6V.Reset(0.0);
userActive6V.Reset(false);
userActive6V.Reset(true);
userVoltage5V.Reset(5.0);
userCurrent5V.Reset(0.0);
userActive5V.Reset(false);
userActive5V.Reset(true);
userVoltage3V3.Reset(3.3);
userCurrent3V3.Reset(0.0);
userActive3V3.Reset(false);
userActive3V3.Reset(true);
userFaults6V.Reset(0);
userFaults5V.Reset(0);
userFaults3V3.Reset(0);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -30,22 +30,22 @@ class RoboRioData {
public:
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetFPGAButtonName> fpgaButton{false};
SimDataValue<double, HAL_MakeDouble, GetVInVoltageName> vInVoltage{0.0};
SimDataValue<double, HAL_MakeDouble, GetVInVoltageName> vInVoltage{12.0};
SimDataValue<double, HAL_MakeDouble, GetVInCurrentName> vInCurrent{0.0};
SimDataValue<double, HAL_MakeDouble, GetUserVoltage6VName> userVoltage6V{6.0};
SimDataValue<double, HAL_MakeDouble, GetUserCurrent6VName> userCurrent6V{0.0};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive6VName> userActive6V{
false};
true};
SimDataValue<double, HAL_MakeDouble, GetUserVoltage5VName> userVoltage5V{5.0};
SimDataValue<double, HAL_MakeDouble, GetUserCurrent5VName> userCurrent5V{0.0};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive5VName> userActive5V{
false};
true};
SimDataValue<double, HAL_MakeDouble, GetUserVoltage3V3Name> userVoltage3V3{
3.3};
SimDataValue<double, HAL_MakeDouble, GetUserCurrent3V3Name> userCurrent3V3{
0.0};
SimDataValue<HAL_Bool, HAL_MakeBoolean, GetUserActive3V3Name> userActive3V3{
false};
true};
SimDataValue<int32_t, HAL_MakeInt, GetUserFaults6VName> userFaults6V{0};
SimDataValue<int32_t, HAL_MakeInt, GetUserFaults5VName> userFaults5V{0};
SimDataValue<int32_t, HAL_MakeInt, GetUserFaults3V3Name> userFaults3V3{0};

View File

@@ -32,6 +32,11 @@ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/imgui_ProggyDotted.h
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/imgui_ProggyDotted.cpp
PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/ProggyDotted.inc)
# stb_image
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stb_image.cpp
CONTENT "#define STBI_WINDOWS_UTF8\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n"
)
# Add imgui directly to our build.
set(SAVE_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF)
@@ -46,8 +51,8 @@ add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/gl3w-src
set(imgui_srcdir ${CMAKE_CURRENT_BINARY_DIR}/imgui-src)
file(GLOB imgui_sources ${imgui_srcdir}/*.cpp)
add_library(imgui STATIC ${imgui_sources} ${imgui_srcdir}/examples/imgui_impl_glfw.cpp ${imgui_srcdir}/examples/imgui_impl_opengl3.cpp ${CMAKE_CURRENT_BINARY_DIR}/imgui_ProggyDotted.cpp)
add_library(imgui STATIC ${imgui_sources} ${imgui_srcdir}/examples/imgui_impl_glfw.cpp ${imgui_srcdir}/examples/imgui_impl_opengl3.cpp ${CMAKE_CURRENT_BINARY_DIR}/imgui_ProggyDotted.cpp ${CMAKE_CURRENT_BINARY_DIR}/stb_image.cpp)
target_link_libraries(imgui PUBLIC gl3w glfw)
target_include_directories(imgui PUBLIC "$<BUILD_INTERFACE:${imgui_srcdir}>" "$<BUILD_INTERFACE:${imgui_srcdir}/examples>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")
target_include_directories(imgui PUBLIC "$<BUILD_INTERFACE:${imgui_srcdir}>" "$<BUILD_INTERFACE:${imgui_srcdir}/examples>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/stb-src>")
set_property(TARGET imgui PROPERTY POSITION_INDEPENDENT_CODE ON)

View File

@@ -41,3 +41,13 @@ ExternalProject_Add(proggyfonts
INSTALL_COMMAND ""
TEST_COMMAND ""
)
ExternalProject_Add(stb
GIT_REPOSITORY https://github.com/nothings/stb.git
GIT_TAG f67165c2bb2af3060ecae7d20d6f731173485ad0
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/stb-src"
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/stb-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -11,7 +11,7 @@ nativeUtils {
niLibVersion = "2020.10.1"
opencvVersion = "3.4.7-2"
googleTestVersion = "1.9.0-4-437e100-1"
imguiVersion = "1.72b-2"
imguiVersion = "1.72b-3"
}
}
}
@@ -21,6 +21,10 @@ nativeUtils.wpi.addWarningsAsErrors()
nativeUtils.setSinglePrintPerPlatform()
nativeUtils.platformConfigs.named("osxx86-64").configure {
it.linker.args << "-headerpad_max_install_names"
}
model {
components {
all {

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,10 +7,6 @@
#include "AddressableLEDGui.h"
#include <cstdio>
#include <cstring>
#include <vector>
#include <hal/Ports.h>
#include <imgui.h>
#include <imgui_internal.h>
@@ -20,77 +16,55 @@
#include "ExtraGuiWidgets.h"
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
namespace {
struct LEDDisplaySettings {
struct LEDDisplayInfo {
int numColumns = 10;
LEDConfig config;
bool ReadIni(wpi::StringRef name, wpi::StringRef value);
void WriteIni(ImGuiTextBuffer* out);
};
} // namespace
static std::vector<LEDDisplaySettings> displaySettings;
static IniSaver<LEDDisplayInfo> gDisplaySettings{"AddressableLED"};
// read/write columns setting to ini file
static void* AddressableLEDReadOpen(ImGuiContext* ctx,
ImGuiSettingsHandler* handler,
const char* name) {
int num;
if (wpi::StringRef{name}.getAsInteger(10, num)) return nullptr;
if (num < 0) return nullptr;
if (num >= static_cast<int>(displaySettings.size()))
displaySettings.resize(num + 1);
return &displaySettings[num];
}
static void AddressableLEDReadLine(ImGuiContext* ctx,
ImGuiSettingsHandler* handler, void* entry,
const char* lineStr) {
auto* settings = static_cast<LEDDisplaySettings*>(entry);
// format: columns=#
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
bool LEDDisplayInfo::ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (name == "columns") {
int num;
if (value.getAsInteger(10, num)) return;
settings->numColumns = num;
if (value.getAsInteger(10, num)) return true;
numColumns = num;
} else if (name == "serpentine") {
int num;
if (value.getAsInteger(10, num)) return;
settings->config.serpentine = num != 0;
if (value.getAsInteger(10, num)) return true;
config.serpentine = num != 0;
} else if (name == "order") {
int num;
if (value.getAsInteger(10, num)) return;
settings->config.order = static_cast<LEDConfig::Order>(num);
if (value.getAsInteger(10, num)) return true;
config.order = static_cast<LEDConfig::Order>(num);
} else if (name == "start") {
int num;
if (value.getAsInteger(10, num)) return;
settings->config.start = static_cast<LEDConfig::Start>(num);
if (value.getAsInteger(10, num)) return true;
config.start = static_cast<LEDConfig::Start>(num);
} else {
return false;
}
return true;
}
static void AddressableLEDWriteAll(ImGuiContext* ctx,
ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
for (size_t i = 0; i < displaySettings.size(); ++i) {
out_buf->appendf(
"[AddressableLED][%d]\ncolumns=%d\nserpentine=%d\norder=%d\n"
"start=%d\n\n",
static_cast<int>(i), displaySettings[i].numColumns,
displaySettings[i].config.serpentine ? 1 : 0,
static_cast<int>(displaySettings[i].config.order),
static_cast<int>(displaySettings[i].config.start));
}
void LEDDisplayInfo::WriteIni(ImGuiTextBuffer* out) {
out->appendf("columns=%d\nserpentine=%d\norder=%d\nstart=%d\n", numColumns,
config.serpentine ? 1 : 0, static_cast<int>(config.order),
static_cast<int>(config.start));
}
static void DisplayAddressableLEDs() {
bool hasAny = false;
static const int numLED = HAL_GetNumAddressableLEDs();
if (numLED > static_cast<int>(displaySettings.size()))
displaySettings.resize(numLED);
for (int i = 0; i < numLED; ++i) {
if (!HALSIM_GetAddressableLEDInitialized(i)) continue;
@@ -101,26 +75,27 @@ static void DisplayAddressableLEDs() {
static HAL_AddressableLEDData data[HAL_kAddressableLEDMaxLength];
int length = HALSIM_GetAddressableLEDData(i, data);
bool running = HALSIM_GetAddressableLEDRunning(i);
auto& info = gDisplaySettings[i];
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
ImGui::LabelText("Length", "%d", length);
ImGui::LabelText("Running", "%s", running ? "Yes" : "No");
ImGui::InputInt("Columns", &displaySettings[i].numColumns);
ImGui::InputInt("Columns", &info.numColumns);
{
static const char* options[] = {"Row Major", "Column Major"};
int val = displaySettings[i].config.order;
int val = info.config.order;
if (ImGui::Combo("Order", &val, options, 2))
displaySettings[i].config.order = static_cast<LEDConfig::Order>(val);
info.config.order = static_cast<LEDConfig::Order>(val);
}
{
static const char* options[] = {"Upper Left", "Lower Left", "Upper Right",
"Lower Right"};
int val = displaySettings[i].config.start;
int val = info.config.start;
if (ImGui::Combo("Start", &val, options, 4))
displaySettings[i].config.start = static_cast<LEDConfig::Start>(val);
info.config.start = static_cast<LEDConfig::Start>(val);
}
ImGui::Checkbox("Serpentine", &displaySettings[i].config.serpentine);
if (displaySettings[i].numColumns < 1) displaySettings[i].numColumns = 1;
ImGui::Checkbox("Serpentine", &info.config.serpentine);
if (info.numColumns < 1) info.numColumns = 1;
ImGui::PopItemWidth();
// show as LED indicators
@@ -137,22 +112,13 @@ static void DisplayAddressableLEDs() {
}
}
DrawLEDs(values, length, displaySettings[i].numColumns, colors, 0, 0,
displaySettings[i].config);
DrawLEDs(values, length, info.numColumns, colors, 0, 0, info.config);
}
if (!hasAny) ImGui::Text("No addressable LEDs");
}
void AddressableLEDGui::Initialize() {
// hook ini handler to save columns settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = "AddressableLED";
iniHandler.TypeHash = ImHashStr(iniHandler.TypeName);
iniHandler.ReadOpenFn = AddressableLEDReadOpen;
iniHandler.ReadLineFn = AddressableLEDReadLine;
iniHandler.WriteAllFn = AddressableLEDWriteAll;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
gDisplaySettings.Initialize();
HALSimGui::AddWindow("Addressable LEDs", DisplayAddressableLEDs,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetWindowVisibility("Addressable LEDs", HALSimGui::kHide);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,8 +7,6 @@
#include "AnalogInputGui.h"
#include <cstdio>
#include <hal/Ports.h>
#include <imgui.h>
#include <mockdata/AnalogGyroData.h>
@@ -16,9 +14,13 @@
#include <mockdata/SimDeviceData.h>
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<NameInfo> gAnalogInputs{"AnalogInput"}; // indexed by channel
static void DisplayAnalogInputs() {
ImGui::Text("(Use Ctrl+Click to edit value)");
bool hasInputs = false;
@@ -36,8 +38,11 @@ static void DisplayAnalogInputs() {
first = false;
}
char name[32];
std::snprintf(name, sizeof(name), "In[%d]", i);
auto& info = gAnalogInputs[i];
// build name
char name[128];
info.GetName(name, sizeof(name), "In", i);
if (i < numAccum && HALSIM_GetAnalogGyroInitialized(i)) {
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(96, 96, 96, 255));
ImGui::LabelText(name, "AnalogGyro[%d]", i);
@@ -51,12 +56,16 @@ static void DisplayAnalogInputs() {
if (ImGui::SliderFloat(name, &val, 0.0, 5.0))
HALSIM_SetAnalogInVoltage(i, val);
}
// context menu to change name
info.PopupEditName(i);
}
}
if (!hasInputs) ImGui::Text("No analog inputs");
}
void AnalogInputGui::Initialize() {
gAnalogInputs.Initialize();
HALSimGui::AddWindow("Analog Inputs", DisplayAnalogInputs,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("Analog Inputs", 640, 20);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,18 +7,18 @@
#include "AnalogOutGui.h"
#include <cstdio>
#include <cstring>
#include <memory>
#include <hal/Ports.h>
#include <imgui.h>
#include <mockdata/AnalogOutData.h>
#include "IniSaver.h"
#include "IniSaverInfo.h"
#include "SimDeviceGui.h"
using namespace halsimgui;
static IniSaver<NameInfo> gAnalogOuts{"AnalogOut"}; // indexed by channel
static void DisplayAnalogOutputs() {
static const int numAnalog = HAL_GetNumAnalogOutputs();
static auto init = std::make_unique<bool[]>(numAnalog);
@@ -34,14 +34,20 @@ static void DisplayAnalogOutputs() {
if (SimDeviceGui::StartDevice("Analog Outputs")) {
for (int i = 0; i < numAnalog; ++i) {
if (!init[i]) continue;
char name[32];
std::snprintf(name, sizeof(name), "Out[%d]", i);
auto& info = gAnalogOuts[i];
char name[128];
info.GetName(name, sizeof(name), "Out", i);
HAL_Value value = HAL_MakeDouble(HALSIM_GetAnalogOutVoltage(i));
SimDeviceGui::DisplayValue(name, true, &value);
info.PopupEditName(i);
}
SimDeviceGui::FinishDevice();
}
}
void AnalogOutGui::Initialize() { SimDeviceGui::Add(DisplayAnalogOutputs); }
void AnalogOutGui::Initialize() {
gAnalogOuts.Initialize();
SimDeviceGui::Add(DisplayAnalogOutputs);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,10 +7,6 @@
#include "DIOGui.h"
#include <cstdio>
#include <cstring>
#include <memory>
#include <hal/Ports.h>
#include <imgui.h>
#include <mockdata/DIOData.h>
@@ -20,9 +16,13 @@
#include <mockdata/SimDeviceData.h>
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<NameInfo> gDIO{"DIO"};
static void LabelSimDevice(const char* name, HAL_SimDeviceHandle simDevice) {
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(96, 96, 96, 255));
ImGui::LabelText(name, "%s", HALSIM_GetSimDeviceName(simDevice));
@@ -71,9 +71,10 @@ static void DisplayDIO() {
for (int i = 0; i < numDIO; ++i) {
if (HALSIM_GetDIOInitialized(i)) {
hasAny = true;
char name[32];
auto& info = gDIO[i];
char name[128];
if (pwmMap[i] > 0) {
std::snprintf(name, sizeof(name), "PWM[%d]", i);
info.GetName(name, sizeof(name), "PWM", i);
if (auto simDevice = HALSIM_GetDIOSimDevice(i)) {
LabelSimDevice(name, simDevice);
} else {
@@ -81,7 +82,7 @@ static void DisplayDIO() {
HALSIM_GetDigitalPWMDutyCycle(pwmMap[i] - 1));
}
} else if (encoderMap[i] > 0) {
std::snprintf(name, sizeof(name), " In[%d]", i);
info.GetName(name, sizeof(name), " In", i);
if (auto simDevice = HALSIM_GetEncoderSimDevice(encoderMap[i] - 1)) {
LabelSimDevice(name, simDevice);
} else {
@@ -92,7 +93,7 @@ static void DisplayDIO() {
ImGui::PopStyleColor();
}
} else if (dutyCycleMap[i] > 0) {
std::snprintf(name, sizeof(name), "PWM[%d]", i);
info.GetName(name, sizeof(name), "Dty", i);
if (auto simDevice =
HALSIM_GetDutyCycleSimDevice(dutyCycleMap[i] - 1)) {
LabelSimDevice(name, simDevice);
@@ -102,7 +103,7 @@ static void DisplayDIO() {
HALSIM_SetDutyCycleOutput(dutyCycleMap[i] - 1, val);
}
} else if (!HALSIM_GetDIOIsInput(i)) {
std::snprintf(name, sizeof(name), "Out[%d]", i);
info.GetName(name, sizeof(name), "Out", i);
if (auto simDevice = HALSIM_GetDIOSimDevice(i)) {
LabelSimDevice(name, simDevice);
} else {
@@ -110,7 +111,7 @@ static void DisplayDIO() {
HALSIM_GetDIOValue(i) ? "1 (high)" : "0 (low)");
}
} else {
std::snprintf(name, sizeof(name), " In[%d]", i);
info.GetName(name, sizeof(name), " In", i);
if (auto simDevice = HALSIM_GetDIOSimDevice(i)) {
LabelSimDevice(name, simDevice);
} else {
@@ -119,6 +120,7 @@ static void DisplayDIO() {
if (ImGui::Combo(name, &val, options, 2)) HALSIM_SetDIOValue(i, val);
}
}
info.PopupEditName(i);
}
}
ImGui::PopItemWidth();
@@ -126,6 +128,7 @@ static void DisplayDIO() {
}
void DIOGui::Initialize() {
gDIO.Initialize();
HALSimGui::AddWindow("DIO", DisplayDIO, ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("DIO", 470, 20);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -22,6 +22,7 @@
#include "ExtraGuiWidgets.h"
#include "HALSimGui.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
@@ -45,6 +46,7 @@ struct SystemJoystick {
};
struct RobotJoystick {
NameInfo name;
std::string guid;
const SystemJoystick* sys = nullptr;
bool useGamepad = false;
@@ -93,6 +95,8 @@ static void JoystickReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
int num;
if (value.getAsInteger(10, num)) return;
joy->useGamepad = num;
} else {
joy->name.ReadIni(name, value);
}
}
@@ -100,11 +104,15 @@ static void JoystickWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
for (int i = 0; i < HAL_kMaxJoysticks; ++i) {
auto& joy = gRobotJoysticks[i];
if (!joy.sys) continue;
const char* guid = glfwGetJoystickGUID(joy.sys - gSystemJoysticks);
if (!guid) continue;
out_buf->appendf("[Joystick][%d]\nguid=%s\nuseGamepad=%d\n\n", i, guid,
if (!joy.name.HasName() && !joy.sys) continue;
out_buf->appendf("[Joystick][%d]\nuseGamepad=%d\n", i,
joy.useGamepad ? 1 : 0);
if (joy.name.HasName()) joy.name.WriteIni(out_buf);
if (joy.sys) {
const char* guid = glfwGetJoystickGUID(joy.sys - gSystemJoysticks);
if (guid) out_buf->appendf("guid=%s\n", guid);
}
out_buf->append("\n");
}
}
@@ -426,8 +434,8 @@ static void DisplayJoysticks() {
ImGui::Columns(HAL_kMaxJoysticks, "Joysticks", false);
for (int i = 0; i < HAL_kMaxJoysticks; ++i) {
auto& joy = gRobotJoysticks[i];
char label[30];
std::snprintf(label, sizeof(label), "Joystick %d", i);
char label[128];
joy.name.GetName(label, sizeof(label), "Joystick", i);
if (joy.sys) {
ImGui::Selectable(label, false);
if (ImGui::BeginDragDropSource()) {
@@ -455,6 +463,7 @@ static void DisplayJoysticks() {
}
ImGui::EndDragDropTarget();
}
joy.name.PopupEditName(i);
ImGui::NextColumn();
}
ImGui::Separator();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,49 +7,32 @@
#include "EncoderGui.h"
#include <cstdio>
#include <hal/Ports.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <mockdata/EncoderData.h>
#include <mockdata/SimDeviceData.h>
#include <wpi/DenseMap.h>
#include <wpi/StringRef.h>
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static wpi::DenseMap<int, bool> gEncodersOpen; // indexed by channel A
// read/write open state to ini file
static void* EncodersReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name) {
int num;
if (wpi::StringRef{name}.getAsInteger(10, num)) return nullptr;
return &gEncodersOpen[num];
}
static void EncodersReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr) {
bool* element = static_cast<bool*>(entry);
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
if (name == "open") {
int num;
if (value.getAsInteger(10, num)) return;
*element = num;
namespace {
struct EncoderInfo : public NameInfo, public OpenInfo {
bool ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (NameInfo::ReadIni(name, value)) return true;
if (OpenInfo::ReadIni(name, value)) return true;
return false;
}
}
void WriteIni(ImGuiTextBuffer* out) {
NameInfo::WriteIni(out);
OpenInfo::WriteIni(out);
}
};
} // namespace
static void EncodersWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
for (auto it : gEncodersOpen)
out_buf->appendf("[Encoder][%d]\nopen=%d\n\n", it.first, it.second ? 1 : 0);
}
static IniSaver<EncoderInfo> gEncoders{"Encoder"}; // indexed by channel A
static void DisplayEncoders() {
bool hasAny = false;
@@ -58,54 +41,61 @@ static void DisplayEncoders() {
for (int i = 0; i < numEncoder; ++i) {
if (HALSIM_GetEncoderInitialized(i)) {
hasAny = true;
char name[32];
int chA = HALSIM_GetEncoderDigitalChannelA(i);
int chB = HALSIM_GetEncoderDigitalChannelB(i);
std::snprintf(name, sizeof(name), "Encoder[%d,%d]", chA, chB);
if (auto simDevice = HALSIM_GetEncoderSimDevice(i)) {
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(96, 96, 96, 255));
ImGui::Text("%s", HALSIM_GetSimDeviceName(simDevice));
ImGui::PopStyleColor();
} else if (ImGui::CollapsingHeader(
name,
gEncodersOpen[chA] ? ImGuiTreeNodeFlags_DefaultOpen : 0)) {
gEncodersOpen[chA] = true;
ImGui::PushID(i);
// distance per pulse
double distancePerPulse = HALSIM_GetEncoderDistancePerPulse(i);
ImGui::LabelText("Dist/Count", "%.6f", distancePerPulse);
// count
int count = HALSIM_GetEncoderCount(i);
if (ImGui::InputInt("Count", &count)) HALSIM_SetEncoderCount(i, count);
ImGui::SameLine();
if (ImGui::Button("Reset")) HALSIM_SetEncoderCount(i, 0);
// max period
double maxPeriod = HALSIM_GetEncoderMaxPeriod(i);
ImGui::LabelText("Max Period", "%.6f", maxPeriod);
// period
double period = HALSIM_GetEncoderPeriod(i);
if (ImGui::InputDouble("Period", &period, 0, 0, "%.6g"))
HALSIM_SetEncoderPeriod(i, period);
// reverse direction
ImGui::LabelText(
"Reverse Direction", "%s",
HALSIM_GetEncoderReverseDirection(i) ? "true" : "false");
// direction
static const char* options[] = {"reverse", "forward"};
int direction = HALSIM_GetEncoderDirection(i) ? 1 : 0;
if (ImGui::Combo("Direction", &direction, options, 2))
HALSIM_SetEncoderDirection(i, direction);
ImGui::PopID();
} else {
gEncodersOpen[chA] = false;
int chA = HALSIM_GetEncoderDigitalChannelA(i);
int chB = HALSIM_GetEncoderDigitalChannelB(i);
// build header name
auto& info = gEncoders[chA];
char name[128];
info.GetName(name, sizeof(name), "Encoder", chA, chB);
// header
bool open = ImGui::CollapsingHeader(
name, gEncoders[chA].IsOpen() ? ImGuiTreeNodeFlags_DefaultOpen : 0);
info.SetOpen(open);
// context menu to change name
info.PopupEditName(chA);
if (open) {
ImGui::PushID(i);
// distance per pulse
double distancePerPulse = HALSIM_GetEncoderDistancePerPulse(i);
ImGui::LabelText("Dist/Count", "%.6f", distancePerPulse);
// count
int count = HALSIM_GetEncoderCount(i);
if (ImGui::InputInt("Count", &count))
HALSIM_SetEncoderCount(i, count);
ImGui::SameLine();
if (ImGui::Button("Reset")) HALSIM_SetEncoderCount(i, 0);
// max period
double maxPeriod = HALSIM_GetEncoderMaxPeriod(i);
ImGui::LabelText("Max Period", "%.6f", maxPeriod);
// period
double period = HALSIM_GetEncoderPeriod(i);
if (ImGui::InputDouble("Period", &period, 0, 0, "%.6g"))
HALSIM_SetEncoderPeriod(i, period);
// reverse direction
ImGui::LabelText(
"Reverse Direction", "%s",
HALSIM_GetEncoderReverseDirection(i) ? "true" : "false");
// direction
static const char* options[] = {"reverse", "forward"};
int direction = HALSIM_GetEncoderDirection(i) ? 1 : 0;
if (ImGui::Combo("Direction", &direction, options, 2))
HALSIM_SetEncoderDirection(i, direction);
ImGui::PopID();
}
}
}
}
@@ -114,15 +104,7 @@ static void DisplayEncoders() {
}
void EncoderGui::Initialize() {
// hook ini handler to save settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = "Encoder";
iniHandler.TypeHash = ImHashStr(iniHandler.TypeName);
iniHandler.ReadOpenFn = EncodersReadOpen;
iniHandler.ReadLineFn = EncodersReadLine;
iniHandler.WriteAllFn = EncodersWriteAll;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
gEncoders.Initialize();
HALSimGui::AddWindow("Encoders", DisplayEncoders,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("Encoders", 640, 215);

View File

@@ -0,0 +1,649 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "Field2D.h"
#include <cmath>
#include <GL/gl3w.h>
#include <hal/SimDevice.h>
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <mockdata/SimDeviceData.h>
#include <units/units.h>
#include <wpi/Path.h>
#include <wpi/SmallString.h>
#include <wpi/json.h>
#include <wpi/raw_istream.h>
#include <wpi/raw_ostream.h>
#include "GuiUtil.h"
#include "HALSimGui.h"
#include "SimDeviceGui.h"
#include "portable-file-dialogs.h"
using namespace halsimgui;
namespace {
// Per-frame field data (not persistent)
struct FieldFrameData {
// in window coordinates
ImVec2 imageMin;
ImVec2 imageMax;
ImVec2 min;
ImVec2 max;
float scale; // scaling from field units to screen units
};
class FieldInfo {
public:
static constexpr float kDefaultWidth = 15.98f;
static constexpr float kDefaultHeight = 8.21f;
std::unique_ptr<pfd::open_file> m_fileOpener;
float m_width = kDefaultWidth;
float m_height = kDefaultHeight;
void Reset();
void LoadImage();
void LoadJson(const wpi::Twine& jsonfile);
FieldFrameData GetFrameData() const;
void Draw(ImDrawList* drawList, const ImVec2& windowPos,
const FieldFrameData& frameData) const;
bool ReadIni(wpi::StringRef name, wpi::StringRef value);
void WriteIni(ImGuiTextBuffer* out) const;
private:
bool LoadImageImpl(const wpi::Twine& fn);
std::string m_filename;
GLuint m_texture = 0;
int m_imageWidth = 0;
int m_imageHeight = 0;
int m_top = 0;
int m_left = 0;
int m_bottom = -1;
int m_right = -1;
};
// Per-frame robot data (not persistent)
struct RobotFrameData {
// in window coordinates
ImVec2 center;
ImVec2 corners[4];
ImVec2 arrow[3];
// scaled width/2 and length/2, in screen units
float width2;
float length2;
};
class RobotInfo {
public:
static constexpr float kDefaultWidth = 0.6858f;
static constexpr float kDefaultLength = 0.8204f;
std::unique_ptr<pfd::open_file> m_fileOpener;
float m_width = kDefaultWidth;
float m_length = kDefaultLength;
void Reset();
void LoadImage();
void UpdateFromSimDevice();
void SetPosition(double x, double y);
// set and get rotation in radians
void SetRotation(double rot);
double GetRotation() const {
return units::convert<units::degrees, units::radians>(m_rot);
}
RobotFrameData GetFrameData(const FieldFrameData& ffd) const;
void Draw(ImDrawList* drawList, const ImVec2& windowPos,
const RobotFrameData& frameData, int hit, float hitRadius) const;
bool ReadIni(wpi::StringRef name, wpi::StringRef value);
void WriteIni(ImGuiTextBuffer* out) const;
private:
bool LoadImageImpl(const wpi::Twine& fn);
std::string m_filename;
GLuint m_texture = 0;
HAL_SimDeviceHandle m_devHandle = 0;
hal::SimDouble m_xHandle;
hal::SimDouble m_yHandle;
hal::SimDouble m_rotHandle;
double m_x = 0;
double m_y = 0;
double m_rot = 0;
};
} // namespace
static FieldInfo gField;
static RobotInfo gRobot;
static int gDragRobot = 0;
static ImVec2 gDragInitialOffset;
static double gDragInitialAngle;
// read/write settings to ini file
static void* Field2DReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name) {
if (name == wpi::StringRef{"Field"}) return &gField;
if (name == wpi::StringRef{"Robot"}) return &gRobot;
return nullptr;
}
static void Field2DReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr) {
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
if (entry == &gField)
gField.ReadIni(name, value);
else if (entry == &gRobot)
gRobot.ReadIni(name, value);
}
static void Field2DWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
gField.WriteIni(out_buf);
gRobot.WriteIni(out_buf);
}
void FieldInfo::Reset() {
if (m_texture != 0) glDeleteTextures(1, &m_texture);
m_texture = 0;
m_filename.clear();
m_imageWidth = 0;
m_imageHeight = 0;
m_top = 0;
m_left = 0;
m_bottom = -1;
m_right = -1;
}
void FieldInfo::LoadImage() {
if (m_fileOpener && m_fileOpener->ready(0)) {
auto result = m_fileOpener->result();
if (!result.empty()) {
if (wpi::StringRef(result[0]).endswith(".json")) {
LoadJson(result[0]);
} else {
LoadImageImpl(result[0]);
m_top = 0;
m_left = 0;
m_bottom = -1;
m_right = -1;
}
}
m_fileOpener.reset();
}
if (m_texture == 0 && !m_filename.empty()) {
if (!LoadImageImpl(m_filename)) m_filename.clear();
}
}
void FieldInfo::LoadJson(const wpi::Twine& jsonfile) {
std::error_code ec;
wpi::raw_fd_istream f(jsonfile, ec);
if (ec) {
wpi::errs() << "GUI: could not open field JSON file\n";
return;
}
// parse file
wpi::json j;
try {
j = wpi::json::parse(f);
} catch (const wpi::json::parse_error& e) {
wpi::errs() << "GUI: JSON: could not parse: " << e.what() << '\n';
}
// top level must be an object
if (!j.is_object()) {
wpi::errs() << "GUI: JSON: does not contain a top object\n";
return;
}
// image filename
std::string image;
try {
image = j.at("field-image").get<std::string>();
} catch (const wpi::json::exception& e) {
wpi::errs() << "GUI: JSON: could not read field-image: " << e.what()
<< '\n';
return;
}
// corners
int top, left, bottom, right;
try {
top = j.at("field-corners").at("top-left").at(1).get<int>();
left = j.at("field-corners").at("top-left").at(0).get<int>();
bottom = j.at("field-corners").at("bottom-right").at(1).get<int>();
right = j.at("field-corners").at("bottom-right").at(0).get<int>();
} catch (const wpi::json::exception& e) {
wpi::errs() << "GUI: JSON: could not read field-corners: " << e.what()
<< '\n';
return;
}
// size
float width;
float height;
try {
width = j.at("field-size").at(0).get<float>();
height = j.at("field-size").at(1).get<float>();
} catch (const wpi::json::exception& e) {
wpi::errs() << "GUI: JSON: could not read field-size: " << e.what() << '\n';
return;
}
// units for size
std::string unit;
try {
unit = j.at("field-unit").get<std::string>();
} catch (const wpi::json::exception& e) {
wpi::errs() << "GUI: JSON: could not read field-unit: " << e.what() << '\n';
return;
}
// convert size units to meters
if (unit == "foot" || unit == "feet") {
width = units::convert<units::feet, units::meters>(width);
height = units::convert<units::feet, units::meters>(height);
}
// the image filename is relative to the json file
wpi::SmallString<128> pathname;
jsonfile.toVector(pathname);
wpi::sys::path::remove_filename(pathname);
wpi::sys::path::append(pathname, image);
// load field image
if (!LoadImageImpl(pathname)) return;
// save to field info
m_filename = pathname.str();
m_top = top;
m_left = left;
m_bottom = bottom;
m_right = right;
m_width = width;
m_height = height;
}
bool FieldInfo::LoadImageImpl(const wpi::Twine& fn) {
wpi::outs() << "GUI: loading field image '" << fn << "'\n";
GLuint oldTexture = m_texture;
if (!LoadTextureFromFile(fn, &m_texture, &m_imageWidth, &m_imageHeight)) {
wpi::errs() << "GUI: could not read field image\n";
return false;
}
if (oldTexture != 0) glDeleteTextures(1, &oldTexture);
m_filename = fn.str();
return true;
}
FieldFrameData FieldInfo::GetFrameData() const {
FieldFrameData ffd;
// get window content region
ffd.imageMin = ImGui::GetWindowContentRegionMin();
ffd.imageMax = ImGui::GetWindowContentRegionMax();
// fit the image into the window
if (m_texture != 0 && m_imageHeight != 0 && m_imageWidth != 0)
MaxFit(&ffd.imageMin, &ffd.imageMax, m_imageWidth, m_imageHeight);
ImVec2 min = ffd.imageMin;
ImVec2 max = ffd.imageMax;
// size down the box by the image corners (if any)
if (m_bottom > 0 && m_right > 0) {
min.x += m_left * (max.x - min.x) / m_imageWidth;
min.y += m_top * (max.y - min.y) / m_imageHeight;
max.x -= (m_imageWidth - m_right) * (max.x - min.x) / m_imageWidth;
max.y -= (m_imageHeight - m_bottom) * (max.y - min.y) / m_imageHeight;
}
// draw the field "active area" as a yellow boundary box
MaxFit(&min, &max, m_width, m_height);
ffd.min = min;
ffd.max = max;
ffd.scale = (max.x - min.x) / m_width;
return ffd;
}
void FieldInfo::Draw(ImDrawList* drawList, const ImVec2& windowPos,
const FieldFrameData& ffd) const {
if (m_texture != 0 && m_imageHeight != 0 && m_imageWidth != 0) {
drawList->AddImage(
reinterpret_cast<ImTextureID>(static_cast<uintptr_t>(m_texture)),
windowPos + ffd.imageMin, windowPos + ffd.imageMax);
}
// draw the field "active area" as a yellow boundary box
drawList->AddRect(windowPos + ffd.min, windowPos + ffd.max,
IM_COL32(255, 255, 0, 255));
}
bool FieldInfo::ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (name == "image") {
m_filename = value;
} else if (name == "top") {
int num;
if (value.getAsInteger(10, num)) return true;
m_top = num;
} else if (name == "left") {
int num;
if (value.getAsInteger(10, num)) return true;
m_left = num;
} else if (name == "bottom") {
int num;
if (value.getAsInteger(10, num)) return true;
m_bottom = num;
} else if (name == "right") {
int num;
if (value.getAsInteger(10, num)) return true;
m_right = num;
} else if (name == "width") {
std::sscanf(value.data(), "%f", &m_width);
} else if (name == "height") {
std::sscanf(value.data(), "%f", &m_height);
} else {
return false;
}
return true;
}
void FieldInfo::WriteIni(ImGuiTextBuffer* out) const {
out->appendf(
"[Field2D][Field]\nimage=%s\ntop=%d\nleft=%d\nbottom=%d\nright=%d\nwidth="
"%f\nheight=%f\n\n",
m_filename.c_str(), m_top, m_left, m_bottom, m_right, m_width, m_height);
}
void RobotInfo::Reset() {
if (m_texture != 0) glDeleteTextures(1, &m_texture);
m_texture = 0;
m_filename.clear();
}
void RobotInfo::LoadImage() {
if (m_fileOpener && m_fileOpener->ready(0)) {
auto result = m_fileOpener->result();
if (!result.empty()) LoadImageImpl(result[0]);
m_fileOpener.reset();
}
if (m_texture == 0 && !m_filename.empty()) {
if (!LoadImageImpl(m_filename)) m_filename.clear();
}
}
bool RobotInfo::LoadImageImpl(const wpi::Twine& fn) {
wpi::outs() << "GUI: loading robot image '" << fn << "'\n";
GLuint oldTexture = m_texture;
if (!LoadTextureFromFile(fn, &m_texture, nullptr, nullptr)) {
wpi::errs() << "GUI: could not read robot image\n";
return false;
}
if (oldTexture != 0) glDeleteTextures(1, &oldTexture);
m_filename = fn.str();
return true;
}
void RobotInfo::UpdateFromSimDevice() {
if (m_devHandle == 0) m_devHandle = HALSIM_GetSimDeviceHandle("Field2D");
if (m_devHandle == 0) return;
if (!m_xHandle) m_xHandle = HALSIM_GetSimValueHandle(m_devHandle, "x");
if (m_xHandle) m_x = m_xHandle.Get();
if (!m_yHandle) m_yHandle = HALSIM_GetSimValueHandle(m_devHandle, "y");
if (m_yHandle) m_y = m_yHandle.Get();
if (!m_rotHandle) m_rotHandle = HALSIM_GetSimValueHandle(m_devHandle, "rot");
if (m_rotHandle) m_rot = m_rotHandle.Get();
}
void RobotInfo::SetPosition(double x, double y) {
m_x = x;
m_y = y;
if (m_xHandle) m_xHandle.Set(x);
if (m_yHandle) m_yHandle.Set(y);
}
void RobotInfo::SetRotation(double rot) {
double rotDegrees = units::convert<units::radians, units::degrees>(rot);
// force to -180 to +180 range
rotDegrees = rotDegrees + std::ceil((-rotDegrees - 180) / 360) * 360;
m_rot = rotDegrees;
if (m_rotHandle) m_rotHandle.Set(rotDegrees);
}
RobotFrameData RobotInfo::GetFrameData(const FieldFrameData& ffd) const {
RobotFrameData rfd;
float width2 = ffd.scale * m_width / 2;
float length2 = ffd.scale * m_length / 2;
// (0,0) origin is bottom left
ImVec2 center(ffd.min.x + ffd.scale * m_x, ffd.max.y - ffd.scale * m_y);
// build rotated points around center
double rot = GetRotation();
float cos_a = std::cos(-rot);
float sin_a = std::sin(-rot);
rfd.corners[0] = center + ImRotate(ImVec2(-length2, -width2), cos_a, sin_a);
rfd.corners[1] = center + ImRotate(ImVec2(length2, -width2), cos_a, sin_a);
rfd.corners[2] = center + ImRotate(ImVec2(length2, width2), cos_a, sin_a);
rfd.corners[3] = center + ImRotate(ImVec2(-length2, width2), cos_a, sin_a);
rfd.arrow[0] =
center + ImRotate(ImVec2(-length2 / 2, -width2 / 2), cos_a, sin_a);
rfd.arrow[1] = center + ImRotate(ImVec2(length2 / 2, 0), cos_a, sin_a);
rfd.arrow[2] =
center + ImRotate(ImVec2(-length2 / 2, width2 / 2), cos_a, sin_a);
rfd.center = center;
rfd.width2 = width2;
rfd.length2 = length2;
return rfd;
}
void RobotInfo::Draw(ImDrawList* drawList, const ImVec2& windowPos,
const RobotFrameData& rfd, int hit,
float hitRadius) const {
if (m_texture != 0) {
drawList->AddImageQuad(
reinterpret_cast<ImTextureID>(static_cast<uintptr_t>(m_texture)),
windowPos + rfd.corners[0], windowPos + rfd.corners[1],
windowPos + rfd.corners[2], windowPos + rfd.corners[3]);
} else {
drawList->AddQuad(windowPos + rfd.corners[0], windowPos + rfd.corners[1],
windowPos + rfd.corners[2], windowPos + rfd.corners[3],
IM_COL32(255, 0, 0, 255), 4.0);
drawList->AddTriangle(windowPos + rfd.arrow[0], windowPos + rfd.arrow[1],
windowPos + rfd.arrow[2], IM_COL32(0, 255, 0, 255),
4.0);
}
if (hit > 0) {
if (hit == 1) {
drawList->AddCircle(windowPos + rfd.center, hitRadius,
IM_COL32(0, 255, 0, 255));
} else {
drawList->AddCircle(windowPos + rfd.corners[hit - 2], hitRadius,
IM_COL32(0, 255, 0, 255));
}
}
}
bool RobotInfo::ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (name == "image") {
m_filename = value;
} else if (name == "width") {
std::sscanf(value.data(), "%f", &m_width);
} else if (name == "length") {
std::sscanf(value.data(), "%f", &m_length);
} else {
return false;
}
return true;
}
void RobotInfo::WriteIni(ImGuiTextBuffer* out) const {
out->appendf("[Field2D][Robot]\nimage=%s\nwidth=%f\nlength=%f\n\n",
m_filename.c_str(), m_width, m_length);
}
static void OptionMenuField2D() {
if (ImGui::BeginMenu("2D Field View")) {
if (ImGui::MenuItem("Choose field image...")) {
gField.m_fileOpener = std::make_unique<pfd::open_file>(
"Choose field image", "",
std::vector<std::string>{"Image File",
"*.jpg *.jpeg *.png *.bmp *.psd *.tga *.gif "
"*.hdr *.pic *.ppm *.pgm",
"PathWeaver JSON File", "*.json"});
}
if (ImGui::MenuItem("Reset field image")) {
gField.Reset();
}
if (ImGui::MenuItem("Choose robot image...")) {
gRobot.m_fileOpener = std::make_unique<pfd::open_file>(
"Choose robot image", "",
std::vector<std::string>{"Image File",
"*.jpg *.jpeg *.png *.bmp *.psd *.tga *.gif "
"*.hdr *.pic *.ppm *.pgm"});
}
if (ImGui::MenuItem("Reset robot image")) {
gRobot.Reset();
}
ImGui::EndMenu();
}
}
static void DisplayField2DSettings() {
ImGui::PushItemWidth(ImGui::GetFontSize() * 4);
ImGui::InputFloat("Field Width", &gField.m_width);
ImGui::InputFloat("Field Height", &gField.m_height);
// ImGui::InputInt("Field Top", &gField.m_top);
// ImGui::InputInt("Field Left", &gField.m_left);
// ImGui::InputInt("Field Right", &gField.m_right);
// ImGui::InputInt("Field Bottom", &gField.m_bottom);
ImGui::InputFloat("Robot Width", &gRobot.m_width);
ImGui::InputFloat("Robot Length", &gRobot.m_length);
ImGui::PopItemWidth();
}
static void DisplayField2D() {
// load images
gField.LoadImage();
gRobot.LoadImage();
// get robot coordinates from SimDevice
gRobot.UpdateFromSimDevice();
FieldFrameData ffd = gField.GetFrameData();
RobotFrameData rfd = gRobot.GetFrameData(ffd);
ImVec2 windowPos = ImGui::GetWindowPos();
// for dragging to work, there needs to be a button (otherwise the window is
// dragged)
ImGui::InvisibleButton("field", ImGui::GetContentRegionAvail());
// allow dragging the robot around
ImVec2 cursor = ImGui::GetIO().MousePos - windowPos;
int hit = 0;
float hitRadius = (std::min)(rfd.width2, rfd.length2) / 2;
// only allow initiation of dragging when invisible button is hovered; this
// prevents the window resize handles from simultaneously activating the drag
// functionality
if (ImGui::IsItemHovered()) {
float hitRadiusSquared = hitRadius * hitRadius;
// it's within the hit radius of the center?
if (GetDistSquared(cursor, rfd.center) < hitRadiusSquared)
hit = 1;
else if (GetDistSquared(cursor, rfd.corners[0]) < hitRadiusSquared)
hit = 2;
else if (GetDistSquared(cursor, rfd.corners[1]) < hitRadiusSquared)
hit = 3;
else if (GetDistSquared(cursor, rfd.corners[2]) < hitRadiusSquared)
hit = 4;
else if (GetDistSquared(cursor, rfd.corners[3]) < hitRadiusSquared)
hit = 5;
if (hit > 0 && ImGui::IsMouseClicked(0)) {
if (hit == 1) {
gDragRobot = hit;
gDragInitialOffset = cursor - rfd.center;
} else {
gDragRobot = hit;
ImVec2 off = cursor - rfd.center;
gDragInitialAngle = std::atan2(off.y, off.x) + gRobot.GetRotation();
}
}
}
if (gDragRobot > 0 && ImGui::IsMouseDown(0)) {
if (gDragRobot == 1) {
ImVec2 newPos = cursor - gDragInitialOffset;
gRobot.SetPosition(
(std::clamp(newPos.x, ffd.min.x, ffd.max.x) - ffd.min.x) / ffd.scale,
(ffd.max.y - std::clamp(newPos.y, ffd.min.y, ffd.max.y)) / ffd.scale);
rfd = gRobot.GetFrameData(ffd);
} else {
ImVec2 off = cursor - rfd.center;
gRobot.SetRotation(gDragInitialAngle - std::atan2(off.y, off.x));
}
hit = gDragRobot; // keep it highlighted
} else {
gDragRobot = 0;
}
// draw
auto drawList = ImGui::GetWindowDrawList();
gField.Draw(drawList, windowPos, ffd);
gRobot.Draw(drawList, windowPos, rfd, hit, hitRadius);
}
void Field2D::Initialize() {
// hook ini handler to save settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = "Field2D";
iniHandler.TypeHash = ImHashStr(iniHandler.TypeName);
iniHandler.ReadOpenFn = Field2DReadOpen;
iniHandler.ReadLineFn = Field2DReadLine;
iniHandler.WriteAllFn = Field2DWriteAll;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
HALSimGui::AddOptionMenu(OptionMenuField2D);
HALSimGui::AddWindow("2D Field Settings", DisplayField2DSettings,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetWindowVisibility("2D Field Settings", HALSimGui::kHide);
HALSimGui::SetDefaultWindowPos("2D Field Settings", 200, 150);
HALSimGui::AddWindow("2D Field View", DisplayField2D);
HALSimGui::SetWindowVisibility("2D Field View", HALSimGui::kHide);
HALSimGui::SetDefaultWindowPos("2D Field View", 200, 200);
HALSimGui::SetDefaultWindowSize("2D Field View", 400, 200);
HALSimGui::SetWindowPadding("2D Field View", 0, 0);
// SimDeviceGui::Hide("Field2D");
}

View File

@@ -0,0 +1,17 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
namespace halsimgui {
class Field2D {
public:
static void Initialize();
};
} // namespace halsimgui

View File

@@ -0,0 +1,62 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "GuiUtil.h"
#include <stb_image.h>
#include <wpi/SmallString.h>
bool halsimgui::LoadTextureFromFile(const wpi::Twine& filename,
GLuint* out_texture, int* out_width,
int* out_height) {
wpi::SmallString<128> buf;
// Load from file
int width = 0;
int height = 0;
unsigned char* data =
stbi_load(filename.toNullTerminatedStringRef(buf).data(), &width, &height,
nullptr, 4);
if (!data) return false;
// Create a OpenGL texture identifier
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Setup filtering parameters for display
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Upload pixels into texture
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
*out_texture = texture;
if (out_width) *out_width = width;
if (out_height) *out_height = height;
return true;
}
void halsimgui::MaxFit(ImVec2* min, ImVec2* max, float width, float height) {
float destWidth = max->x - min->x;
float destHeight = max->y - min->y;
if (width == 0 || height == 0) return;
if (destWidth * height > destHeight * width) {
float outputWidth = width * destHeight / height;
min->x += (destWidth - outputWidth) / 2;
max->x -= (destWidth - outputWidth) / 2;
} else {
float outputHeight = height * destWidth / width;
min->y += (destHeight - outputHeight) / 2;
max->y -= (destHeight - outputHeight) / 2;
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -40,6 +40,8 @@ struct WindowInfo {
ImGuiCond sizeCond = 0;
ImVec2 pos;
ImVec2 size;
bool setPadding = false;
ImVec2 padding;
};
} // namespace
@@ -248,6 +250,14 @@ void HALSimGui::SetDefaultWindowSize(const char* name, float width,
window.size = ImVec2{width, height};
}
void HALSimGui::SetWindowPadding(const char* name, float x, float y) {
auto it = gWindowMap.find(name);
if (it == gWindowMap.end()) return;
auto& window = gWindows[it->second];
window.setPadding = true;
window.padding = ImVec2{x, y};
}
bool HALSimGui::AreOutputsDisabled() {
return gDisableOutputsOnDSDisable && !HALSIM_GetDriverStationEnabled();
}
@@ -301,6 +311,12 @@ bool HALSimGui::Initialize() {
// Set initial window settings
glfwWindowHint(GLFW_MAXIMIZED, gWindowMaximized ? GLFW_TRUE : GLFW_FALSE);
if (gWindowWidth == 0 || gWindowHeight == 0) {
gWindowWidth = 1280;
gWindowHeight = 720;
gWindowLoadedWidthHeight = false;
}
float windowScale = 1.0;
if (!gWindowLoadedWidthHeight) {
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
@@ -515,9 +531,12 @@ void HALSimGui::Main(void*) {
ImGui::SetNextWindowPos(window.pos, window.posCond);
if (window.sizeCond != 0)
ImGui::SetNextWindowSize(window.size, window.sizeCond);
if (window.setPadding)
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, window.padding);
if (ImGui::Begin(window.name.c_str(), &window.visible, window.flags))
window.display();
ImGui::End();
if (window.setPadding) ImGui::PopStyleVar();
}
}
@@ -591,6 +610,10 @@ void HALSIMGUI_SetDefaultWindowSize(const char* name, float width,
HALSimGui::SetDefaultWindowSize(name, width, height);
}
void HALSIMGUI_SetWindowPadding(const char* name, float x, float y) {
HALSimGui::SetDefaultWindowSize(name, x, y);
}
int HALSIMGUI_AreOutputsDisabled(void) {
return HALSimGui::AreOutputsDisabled();
}

View File

@@ -0,0 +1,78 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "IniSaverInfo.h"
#include <cstdio>
#include <cstring>
#include <imgui_internal.h>
using namespace halsimgui;
void NameInfo::GetName(char* buf, size_t size, const char* defaultName,
int index) {
if (m_name[0] != '\0') {
std::snprintf(buf, size, "%s [%d]###Name%d", m_name, index, index);
} else {
std::snprintf(buf, size, "%s[%d]###Name%d", defaultName, index, index);
}
}
void NameInfo::GetName(char* buf, size_t size, const char* defaultName,
int index, int index2) {
if (m_name[0] != '\0') {
std::snprintf(buf, size, "%s [%d,%d]###Name%d", m_name, index, index2,
index);
} else {
std::snprintf(buf, size, "%s[%d,%d]###Name%d", defaultName, index, index2,
index);
}
}
bool NameInfo::ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (name != "name") return false;
size_t len = (std::min)(value.size(), sizeof(m_name) - 1);
std::memcpy(m_name, value.data(), len);
m_name[len] = '\0';
return true;
}
void NameInfo::WriteIni(ImGuiTextBuffer* out) {
out->appendf("name=%s\n", m_name);
}
void NameInfo::PushEditNameId(int index) {
char id[64];
std::snprintf(id, sizeof(id), "Name%d", index);
ImGui::PushID(id);
}
void NameInfo::PopupEditName(int index) {
char id[64];
std::snprintf(id, sizeof(id), "Name%d", index);
if (ImGui::BeginPopupContextItem(id)) {
ImGui::Text("Edit name:");
if (ImGui::InputText("##edit", m_name, sizeof(m_name),
ImGuiInputTextFlags_EnterReturnsTrue))
ImGui::CloseCurrentPopup();
if (ImGui::Button("Close")) ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
}
bool OpenInfo::ReadIni(wpi::StringRef name, wpi::StringRef value) {
if (name != "open") return false;
int num;
if (value.getAsInteger(10, num)) return true;
m_open = num;
return true;
}
void OpenInfo::WriteIni(ImGuiTextBuffer* out) {
out->appendf("open=%d\n", m_open ? 1 : 0);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,7 +7,9 @@
#include "PDPGui.h"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <memory>
#include <hal/Ports.h>
@@ -15,64 +17,82 @@
#include <mockdata/PDPData.h>
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<NameInfo> gChannels{"PDP"};
static void DisplayPDP() {
bool hasAny = false;
static int numPDP = HAL_GetNumPDPModules();
static int numChannels = HAL_GetNumPDPChannels();
static auto channelCurrents = std::make_unique<double[]>(numChannels);
ImGui::PushItemWidth(ImGui::GetFontSize() * 13);
for (int i = 0; i < numPDP; ++i) {
if (HALSIM_GetPDPInitialized(i)) {
hasAny = true;
char name[32];
char name[128];
std::snprintf(name, sizeof(name), "PDP[%d]", i);
if (ImGui::CollapsingHeader(name, ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::PushID(i);
// temperature
double temp = HALSIM_GetPDPTemperature(i);
if (ImGui::InputDouble("Temp", &temp))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
if (ImGui::InputDouble("Temp", &temp, 0, 0, "%.3f"))
HALSIM_SetPDPTemperature(i, temp);
// voltage
double volts = HALSIM_GetPDPVoltage(i);
if (ImGui::InputDouble("Voltage", &volts))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
if (ImGui::InputDouble("Voltage", &volts, 0, 0, "%.3f"))
HALSIM_SetPDPVoltage(i, volts);
// channel currents; show as two columns laid out like PDP
HALSIM_GetPDPAllCurrents(i, channelCurrents.get());
ImGui::Text("Channel Current (A)");
ImGui::Columns(2, "channels", false);
float maxWidth = ImGui::GetFontSize() * 13;
for (int left = 0, right = numChannels - 1; left < right;
++left, --right) {
double val;
std::snprintf(name, sizeof(name), "[%d]", left);
auto& leftInfo = gChannels[i * numChannels + left];
leftInfo.GetName(name, sizeof(name), "", left);
val = channelCurrents[left];
if (ImGui::InputDouble(name, &val))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
if (ImGui::InputDouble(name, &val, 0, 0, "%.3f"))
HALSIM_SetPDPCurrent(i, left, val);
float leftWidth = ImGui::GetItemRectSize().x;
leftInfo.PopupEditName(left);
ImGui::NextColumn();
std::snprintf(name, sizeof(name), "[%d]", right);
auto& rightInfo = gChannels[i * numChannels + right];
rightInfo.GetName(name, sizeof(name), "", right);
val = channelCurrents[right];
if (ImGui::InputDouble(name, &val))
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
if (ImGui::InputDouble(name, &val, 0, 0, "%.3f"))
HALSIM_SetPDPCurrent(i, right, val);
float rightWidth = ImGui::GetItemRectSize().x;
rightInfo.PopupEditName(right);
ImGui::NextColumn();
float width = (std::max)(leftWidth, rightWidth) * 2;
if (width > maxWidth) maxWidth = width;
}
ImGui::Columns(1);
ImGui::Dummy(ImVec2(maxWidth, 0));
ImGui::PopID();
}
}
}
ImGui::PopItemWidth();
if (!hasAny) ImGui::Text("No PDPs");
}
void PDPGui::Initialize() {
gChannels.Initialize();
HALSimGui::AddWindow("PDP", DisplayPDP, ImGuiWindowFlags_AlwaysAutoResize);
// hide it by default
HALSimGui::SetWindowVisibility("PDP", HALSimGui::kHide);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,9 +17,13 @@
#include <mockdata/PWMData.h>
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<NameInfo> gPWM{"PWM"};
static void DisplayPWMs() {
bool hasOutputs = false;
static const int numPWM = HAL_GetNumPWMChannels();
@@ -45,6 +49,7 @@ static void DisplayPWMs() {
//};
// static std::vector<std::unique_ptr<History>> history;
bool first = true;
ImGui::PushItemWidth(ImGui::GetFontSize() * 4);
for (int i = 0; i < numPWM; ++i) {
if (HALSIM_GetPWMInitialized(i)) {
hasOutputs = true;
@@ -54,14 +59,16 @@ static void DisplayPWMs() {
else
first = false;
char name[32];
std::snprintf(name, sizeof(name), "PWM[%d]", i);
char name[128];
auto& info = gPWM[i];
info.GetName(name, sizeof(name), "PWM", i);
if (ledMap[i] > 0) {
ImGui::Text("%s: LED[%d]", name, ledMap[i] - 1);
ImGui::LabelText(name, "LED[%d]", ledMap[i] - 1);
} else {
float val = HALSimGui::AreOutputsDisabled() ? 0 : HALSIM_GetPWMSpeed(i);
ImGui::Value(name, val, "%0.3f");
ImGui::LabelText(name, "%0.3f", val);
}
info.PopupEditName(i);
// lazily build history storage
// if (static_cast<unsigned int>(i) > history.size())
@@ -74,10 +81,12 @@ static void DisplayPWMs() {
// );
}
}
ImGui::PopItemWidth();
if (!hasOutputs) ImGui::Text("No PWM outputs");
}
void PWMGui::Initialize() {
gPWM.Initialize();
HALSimGui::AddWindow("PWM Outputs", DisplayPWMs,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("PWM Outputs", 910, 20);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -16,9 +16,13 @@
#include "ExtraGuiWidgets.h"
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<NameInfo> gRelays{"Relay"};
static void DisplayRelays() {
bool hasOutputs = false;
bool first = true;
@@ -42,7 +46,14 @@ static void DisplayRelays() {
forward = HALSIM_GetRelayForward(i);
}
ImGui::Text("Relay[%d]", i);
auto& info = gRelays[i];
info.PushEditNameId(i);
if (info.HasName())
ImGui::Text("%s [%d]", info.GetName(), i);
else
ImGui::Text("Relay[%d]", i);
ImGui::PopID();
info.PopupEditName(i);
ImGui::SameLine();
// show forward and reverse as LED indicators
@@ -58,6 +69,7 @@ static void DisplayRelays() {
}
void RelayGui::Initialize() {
gRelays.Initialize();
HALSimGui::AddWindow("Relays", DisplayRelays,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("Relays", 180, 20);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -13,51 +13,22 @@
#include <hal/SimDevice.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <mockdata/SimDeviceData.h>
#include <wpi/StringMap.h>
#include "HALSimGui.h"
#include "IniSaverInfo.h"
#include "IniSaverString.h"
using namespace halsimgui;
namespace {
struct ElementInfo {
bool open = false;
bool visible = true;
struct ElementInfo : public OpenInfo {
bool visible = true; // not saved
};
} // namespace
static std::vector<std::function<void()>> gDeviceExecutors;
static wpi::StringMap<ElementInfo> gElements;
// read/write open state to ini file
static void* DevicesReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name) {
return &gElements[name];
}
static void DevicesReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr) {
ElementInfo* element = static_cast<ElementInfo*>(entry);
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
if (name == "open") {
int num;
if (value.getAsInteger(10, num)) return;
element->open = num;
}
}
static void DevicesWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
for (auto&& entry : gElements) {
out_buf->appendf("[Device][%s]\nopen=%d\n\n", entry.getKey().data(),
entry.getValue().open ? 1 : 0);
}
}
static IniSaverString<ElementInfo> gElements{"Device"};
void SimDeviceGui::Hide(const char* name) { gElements[name].visible = false; }
@@ -70,12 +41,13 @@ bool SimDeviceGui::StartDevice(const char* label, ImGuiTreeNodeFlags flags) {
if (!element.visible) return false;
if (ImGui::CollapsingHeader(
label, flags | (element.open ? ImGuiTreeNodeFlags_DefaultOpen : 0))) {
label,
flags | (element.IsOpen() ? ImGuiTreeNodeFlags_DefaultOpen : 0))) {
ImGui::PushID(label);
element.open = true;
element.SetOpen(true);
return true;
}
element.open = false;
element.SetOpen(false);
return false;
}
@@ -201,15 +173,7 @@ static void DisplayDeviceTree() {
}
void SimDeviceGui::Initialize() {
// hook ini handler to save device settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = "Device";
iniHandler.TypeHash = ImHashStr(iniHandler.TypeName);
iniHandler.ReadOpenFn = DevicesReadOpen;
iniHandler.ReadLineFn = DevicesReadLine;
iniHandler.WriteAllFn = DevicesWriteAll;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
gElements.Initialize();
HALSimGui::AddWindow("Other Devices", DisplayDeviceTree);
HALSimGui::SetDefaultWindowPos("Other Devices", 1025, 20);
HALSimGui::SetDefaultWindowSize("Other Devices", 250, 695);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,9 +17,14 @@
#include "ExtraGuiWidgets.h"
#include "HALSimGui.h"
#include "IniSaver.h"
#include "IniSaverInfo.h"
using namespace halsimgui;
static IniSaver<OpenInfo> gPCMs{"PCM"};
static IniSaver<NameInfo> gSolenoids{"Solenoid"};
static void DisplaySolenoids() {
bool hasOutputs = false;
static const int numPCM = HAL_GetNumPCMModules();
@@ -43,18 +48,40 @@ static void DisplaySolenoids() {
if (!anyInit) continue;
hasOutputs = true;
ImGui::Text("PCM[%d]", i);
char name[128];
std::snprintf(name, sizeof(name), "PCM[%d]", i);
auto& pcmInfo = gPCMs[i];
bool open = ImGui::CollapsingHeader(
name, pcmInfo.IsOpen() ? ImGuiTreeNodeFlags_DefaultOpen : 0);
pcmInfo.SetOpen(open);
ImGui::SetItemAllowOverlap();
ImGui::SameLine();
// show channels as LED indicators
static const ImU32 colors[] = {IM_COL32(255, 255, 102, 255),
IM_COL32(128, 128, 128, 255)};
DrawLEDs(channels.data(), channels.size(), channels.size(), colors);
if (open) {
ImGui::PushID(i);
ImGui::PushItemWidth(ImGui::GetFontSize() * 4);
for (int j = 0; j < numChannels; ++j) {
if (channels[j] == -2) continue;
auto& info = gSolenoids[i * numChannels + j];
info.GetName(name, sizeof(name), "Solenoid", j);
ImGui::LabelText(name, "%s", channels[j] == 1 ? "On" : "Off");
info.PopupEditName(j);
}
ImGui::PopItemWidth();
ImGui::PopID();
}
}
if (!hasOutputs) ImGui::Text("No solenoids");
}
void SolenoidGui::Initialize() {
gPCMs.Initialize();
gSolenoids.Initialize();
HALSimGui::AddWindow("Solenoids", DisplaySolenoids,
ImGuiWindowFlags_AlwaysAutoResize);
HALSimGui::SetDefaultWindowPos("Solenoids", 290, 20);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,6 +17,7 @@
#include "DIOGui.h"
#include "DriverStationGui.h"
#include "EncoderGui.h"
#include "Field2D.h"
#include "HALSimGui.h"
#include "PDPGui.h"
#include "PWMGui.h"
@@ -42,6 +43,7 @@ __declspec(dllexport)
HALSimGui::Add(DriverStationGui::Initialize);
HALSimGui::Add(DIOGui::Initialize);
HALSimGui::Add(EncoderGui::Initialize);
HALSimGui::Add(Field2D::Initialize);
HALSimGui::Add(PDPGui::Initialize);
HALSimGui::Add(PWMGui::Initialize);
HALSimGui::Add(RelayGui::Initialize);

View File

@@ -0,0 +1,29 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <GL/gl3w.h>
#include <imgui.h>
#include <wpi/Twine.h>
namespace halsimgui {
bool LoadTextureFromFile(const wpi::Twine& filename, GLuint* out_texture,
int* out_width, int* out_height);
// get distance^2 between two ImVec's
inline float GetDistSquared(const ImVec2& a, const ImVec2& b) {
float deltaX = b.x - a.x;
float deltaY = b.y - a.y;
return deltaX * deltaX + deltaY * deltaY;
}
// maximize fit while preserving aspect ratio
void MaxFit(ImVec2* min, ImVec2* max, float width, float height);
} // namespace halsimgui

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -23,6 +23,7 @@ void HALSIMGUI_SetWindowVisibility(const char* name, int32_t visibility);
void HALSIMGUI_SetDefaultWindowPos(const char* name, float x, float y);
void HALSIMGUI_SetDefaultWindowSize(const char* name, float width,
float height);
void HALSIMGUI_SetWindowPadding(const char* name, float x, float y);
int HALSIMGUI_AreOutputsDisabled(void);
} // extern "C"
@@ -127,6 +128,14 @@ class HALSimGui {
*/
static void SetDefaultWindowSize(const char* name, float width, float height);
/**
* Sets internal padding of window added with AddWindow().
* @param name window name (same as name passed to AddWindow())
* @param x horizontal padding
* @param y vertical padding
*/
static void SetWindowPadding(const char* name, float x, float y);
/**
* Returns true if outputs are disabled.
*

View File

@@ -0,0 +1,47 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <imgui.h>
#include <imgui_internal.h>
#include <wpi/DenseMap.h>
namespace halsimgui {
template <typename Info>
class IniSaver {
public:
explicit IniSaver(const char* typeName) : m_typeName(typeName) {}
void Initialize();
// pass through useful functions to map
Info& operator[](int index) { return m_map[index]; }
auto begin() { return m_map.begin(); }
auto end() { return m_map.end(); }
auto find(int index) { return m_map.find(index); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }
auto find(int index) const { return m_map.find(index); }
private:
static void* ReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name);
static void ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr);
static void WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf);
const char* m_typeName;
wpi::DenseMap<int, Info> m_map;
};
} // namespace halsimgui
#include "IniSaver.inl"

View File

@@ -0,0 +1,56 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
namespace halsimgui {
template <typename Info>
void IniSaver<Info>::Initialize() {
// hook ini handler to save settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = m_typeName;
iniHandler.TypeHash = ImHashStr(m_typeName);
iniHandler.ReadOpenFn = ReadOpen;
iniHandler.ReadLineFn = ReadLine;
iniHandler.WriteAllFn = WriteAll;
iniHandler.UserData = this;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
}
template <typename Info>
void* IniSaver<Info>::ReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name) {
auto self = static_cast<IniSaver*>(handler->UserData);
int num;
if (wpi::StringRef{name}.getAsInteger(10, num)) return nullptr;
return &self->m_map[num];
}
template <typename Info>
void IniSaver<Info>::ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr) {
auto element = static_cast<Info*>(entry);
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
element->ReadIni(name, value);
}
template <typename Info>
void IniSaver<Info>::WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
auto self = static_cast<IniSaver*>(handler->UserData);
for (auto&& it : self->m_map) {
out_buf->appendf("[%s][%d]\n", self->m_typeName, it.first);
it.second.WriteIni(out_buf);
out_buf->append("\n");
}
}
} // namespace halsimgui

View File

@@ -0,0 +1,47 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <imgui.h>
#include <wpi/StringRef.h>
namespace halsimgui {
class NameInfo {
public:
NameInfo() { m_name[0] = '\0'; }
bool HasName() const { return m_name[0] != '\0'; }
const char* GetName() const { return m_name; }
void GetName(char* buf, size_t size, const char* defaultName, int index);
void GetName(char* buf, size_t size, const char* defaultName, int index,
int index2);
bool ReadIni(wpi::StringRef name, wpi::StringRef value);
void WriteIni(ImGuiTextBuffer* out);
void PushEditNameId(int index);
void PopupEditName(int index);
private:
char m_name[64];
};
class OpenInfo {
public:
OpenInfo() = default;
explicit OpenInfo(bool open) : m_open(open) {}
bool IsOpen() const { return m_open; }
void SetOpen(bool open) { m_open = open; }
bool ReadIni(wpi::StringRef name, wpi::StringRef value);
void WriteIni(ImGuiTextBuffer* out);
private:
bool m_open = false;
};
} // namespace halsimgui

View File

@@ -0,0 +1,48 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <imgui.h>
#include <imgui_internal.h>
#include <wpi/StringMap.h>
#include <wpi/StringRef.h>
namespace halsimgui {
template <typename Info>
class IniSaverString {
public:
explicit IniSaverString(const char* typeName) : m_typeName(typeName) {}
void Initialize();
// pass through useful functions to map
Info& operator[](wpi::StringRef key) { return m_map[key]; }
auto begin() { return m_map.begin(); }
auto end() { return m_map.end(); }
auto find(wpi::StringRef key) { return m_map.find(key); }
auto begin() const { return m_map.begin(); }
auto end() const { return m_map.end(); }
auto find(wpi::StringRef key) const { return m_map.find(key); }
private:
static void* ReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
const char* name);
static void ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
void* entry, const char* lineStr);
static void WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf);
const char* m_typeName;
wpi::StringMap<Info> m_map;
};
} // namespace halsimgui
#include "IniSaverString.inl"

View File

@@ -0,0 +1,57 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
namespace halsimgui {
template <typename Info>
void IniSaverString<Info>::Initialize() {
// hook ini handler to save settings
ImGuiSettingsHandler iniHandler;
iniHandler.TypeName = m_typeName;
iniHandler.TypeHash = ImHashStr(m_typeName);
iniHandler.ReadOpenFn = ReadOpen;
iniHandler.ReadLineFn = ReadLine;
iniHandler.WriteAllFn = WriteAll;
iniHandler.UserData = this;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(iniHandler);
}
template <typename Info>
void* IniSaverString<Info>::ReadOpen(ImGuiContext* ctx,
ImGuiSettingsHandler* handler,
const char* name) {
auto self = static_cast<IniSaverString*>(handler->UserData);
return &self->m_map[name];
}
template <typename Info>
void IniSaverString<Info>::ReadLine(ImGuiContext* ctx,
ImGuiSettingsHandler* handler, void* entry,
const char* lineStr) {
auto element = static_cast<Info*>(entry);
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
name = name.trim();
value = value.trim();
element->ReadIni(name, value);
}
template <typename Info>
void IniSaverString<Info>::WriteAll(ImGuiContext* ctx,
ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
auto self = static_cast<IniSaverString*>(handler->UserData);
for (auto&& it : self->m_map) {
out_buf->appendf("[%s][%s]\n", self->m_typeName, it.getKey().data());
it.second.WriteIni(out_buf);
out_buf->append("\n");
}
}
} // namespace halsimgui

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -24,6 +24,7 @@ import edu.wpi.first.hal.HAL;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.RobotState;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
@@ -35,7 +36,7 @@ import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
* Subsystem#periodic()} methods to be called and for their default commands to be scheduled.
*/
@SuppressWarnings({"PMD.GodClass", "PMD.TooManyMethods", "PMD.TooManyFields"})
public final class CommandScheduler implements Sendable {
public final class CommandScheduler implements Sendable, AutoCloseable {
/**
* The Singleton Instance.
*/
@@ -70,11 +71,6 @@ public final class CommandScheduler implements Sendable {
private boolean m_disabled;
//NetworkTable entries for use in Sendable impl
private NetworkTableEntry m_namesEntry;
private NetworkTableEntry m_idsEntry;
private NetworkTableEntry m_cancelEntry;
//Lists of user-supplied actions to be executed on scheduling events for every command.
private final List<Consumer<Command>> m_initActions = new ArrayList<>();
private final List<Consumer<Command>> m_executeActions = new ArrayList<>();
@@ -91,6 +87,20 @@ public final class CommandScheduler implements Sendable {
CommandScheduler() {
HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand2_Scheduler);
SendableRegistry.addLW(this, "Scheduler");
LiveWindow.setEnabledListener(() -> {
disable();
cancelAll();
});
LiveWindow.setDisabledListener(() -> {
enable();
});
}
@Override
public void close() {
SendableRegistry.remove(this);
LiveWindow.setEnabledListener(null);
LiveWindow.setDisabledListener(null);
}
/**
@@ -375,7 +385,7 @@ public final class CommandScheduler implements Sendable {
* Cancels all commands that are currently scheduled.
*/
public void cancelAll() {
for (Command command : m_scheduledCommands.keySet()) {
for (Command command : m_scheduledCommands.keySet().toArray(new Command[0])) {
cancel(command);
}
}
@@ -473,12 +483,12 @@ public final class CommandScheduler implements Sendable {
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Scheduler");
m_namesEntry = builder.getEntry("Names");
m_idsEntry = builder.getEntry("Ids");
m_cancelEntry = builder.getEntry("Cancel");
final NetworkTableEntry namesEntry = builder.getEntry("Names");
final NetworkTableEntry idsEntry = builder.getEntry("Ids");
final NetworkTableEntry cancelEntry = builder.getEntry("Cancel");
builder.setUpdateTable(() -> {
if (m_namesEntry == null || m_idsEntry == null || m_cancelEntry == null) {
if (namesEntry == null || idsEntry == null || cancelEntry == null) {
return;
}
@@ -489,21 +499,21 @@ public final class CommandScheduler implements Sendable {
ids.put((double) command.hashCode(), command);
}
double[] toCancel = m_cancelEntry.getDoubleArray(new double[0]);
double[] toCancel = cancelEntry.getDoubleArray(new double[0]);
if (toCancel.length > 0) {
for (double hash : toCancel) {
cancel(ids.get(hash));
ids.remove(hash);
}
m_cancelEntry.setDoubleArray(new double[0]);
cancelEntry.setDoubleArray(new double[0]);
}
List<String> names = new ArrayList<>();
ids.values().forEach(command -> names.add(command.getName()));
m_namesEntry.setStringArray(names.toArray(new String[0]));
m_idsEntry.setNumberArray(ids.keySet().toArray(new Double[0]));
namesEntry.setStringArray(names.toArray(new String[0]));
idsEntry.setNumberArray(ids.keySet().toArray(new Double[0]));
});
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -348,6 +348,6 @@ public class MecanumControllerCommand extends CommandBase {
@Override
public boolean isFinished() {
return m_timer.hasPeriodPassed(m_trajectory.getTotalTimeSeconds());
return m_timer.hasElapsed(m_trajectory.getTotalTimeSeconds());
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -201,6 +201,6 @@ public class RamseteCommand extends CommandBase {
@Override
public boolean isFinished() {
return m_timer.hasPeriodPassed(m_trajectory.getTotalTimeSeconds());
return m_timer.hasElapsed(m_trajectory.getTotalTimeSeconds());
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -153,6 +153,6 @@ public class SwerveControllerCommand extends CommandBase {
@Override
public boolean isFinished() {
return m_timer.hasPeriodPassed(m_trajectory.getTotalTimeSeconds());
return m_timer.hasElapsed(m_trajectory.getTotalTimeSeconds());
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -59,6 +59,6 @@ public class TrapezoidProfileCommand extends CommandBase {
@Override
public boolean isFinished() {
return m_timer.hasPeriodPassed(m_profile.totalTime());
return m_timer.hasElapsed(m_profile.totalTime());
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -41,7 +41,7 @@ public class WaitCommand extends CommandBase {
@Override
public boolean isFinished() {
return m_timer.hasPeriodPassed(m_duration);
return m_timer.hasElapsed(m_duration);
}
@Override

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -23,7 +23,7 @@ import edu.wpi.first.wpilibj2.command.Subsystem;
* wrapper around Trigger with the method names renamed to fit the Button object use.
*/
@SuppressWarnings("PMD.TooManyMethods")
public abstract class Button extends Trigger {
public class Button extends Trigger {
/**
* Default constructor; creates a button that is never pressed (unless {@link Button#get()} is
* overridden).

View File

@@ -13,7 +13,7 @@
using namespace frc2;
CommandBase::CommandBase() {
frc::SendableRegistry::GetInstance().AddLW(this, GetTypeName(*this));
frc::SendableRegistry::GetInstance().Add(this, GetTypeName(*this));
}
void CommandBase::AddRequirements(

View File

@@ -9,12 +9,14 @@
#include <frc/RobotState.h>
#include <frc/WPIErrors.h>
#include <frc/livewindow/LiveWindow.h>
#include <frc/smartdashboard/SendableBuilder.h>
#include <frc/smartdashboard/SendableRegistry.h>
#include <hal/FRCUsageReporting.h>
#include <hal/HALBase.h>
#include <networktables/NetworkTableEntry.h>
#include <wpi/DenseMap.h>
#include <wpi/SmallVector.h>
#include "frc2/command/CommandGroupBase.h"
#include "frc2/command/CommandState.h"
@@ -42,11 +44,6 @@ class CommandScheduler::Impl {
bool disabled{false};
// NetworkTable entries for use in Sendable impl
nt::NetworkTableEntry namesEntry;
nt::NetworkTableEntry idsEntry;
nt::NetworkTableEntry cancelEntry;
// Lists of user-supplied actions to be executed on scheduling events for
// every command.
wpi::SmallVector<Action, 4> initActions;
@@ -71,9 +68,20 @@ CommandScheduler::CommandScheduler() : m_impl(new Impl) {
HAL_Report(HALUsageReporting::kResourceType_Command,
HALUsageReporting::kCommand2_Scheduler);
frc::SendableRegistry::GetInstance().AddLW(this, "Scheduler");
auto scheduler = frc::LiveWindow::GetInstance();
scheduler->enabled = [this] {
this->Disable();
this->CancelAll();
};
scheduler->disabled = [this] { this->Enable(); };
}
CommandScheduler::~CommandScheduler() {}
CommandScheduler::~CommandScheduler() {
frc::SendableRegistry::GetInstance().Remove(this);
auto scheduler = frc::LiveWindow::GetInstance();
scheduler->enabled = nullptr;
scheduler->disabled = nullptr;
}
CommandScheduler& CommandScheduler::GetInstance() {
static CommandScheduler scheduler;
@@ -310,9 +318,11 @@ void CommandScheduler::Cancel(std::initializer_list<Command*> commands) {
}
void CommandScheduler::CancelAll() {
wpi::SmallVector<Command*, 16> commands;
for (auto&& command : m_impl->scheduledCommands) {
Cancel(command.first);
commands.emplace_back(command.first);
}
Cancel(commands);
}
double CommandScheduler::TimeSinceScheduled(const Command* command) const {
@@ -379,14 +389,14 @@ void CommandScheduler::OnCommandFinish(Action action) {
void CommandScheduler::InitSendable(frc::SendableBuilder& builder) {
builder.SetSmartDashboardType("Scheduler");
m_impl->namesEntry = builder.GetEntry("Names");
m_impl->idsEntry = builder.GetEntry("Ids");
m_impl->cancelEntry = builder.GetEntry("Cancel");
auto namesEntry = builder.GetEntry("Names");
auto idsEntry = builder.GetEntry("Ids");
auto cancelEntry = builder.GetEntry("Cancel");
builder.SetUpdateTable([this] {
builder.SetUpdateTable([=] {
double tmp[1];
tmp[0] = 0;
auto toCancel = m_impl->cancelEntry.GetDoubleArray(tmp);
auto toCancel = cancelEntry.GetDoubleArray(tmp);
for (auto cancel : toCancel) {
uintptr_t ptrTmp = static_cast<uintptr_t>(cancel);
Command* command = reinterpret_cast<Command*>(ptrTmp);
@@ -394,7 +404,8 @@ void CommandScheduler::InitSendable(frc::SendableBuilder& builder) {
m_impl->scheduledCommands.end()) {
Cancel(command);
}
m_impl->cancelEntry.SetDoubleArray(wpi::ArrayRef<double>{});
nt::NetworkTableEntry(cancelEntry)
.SetDoubleArray(wpi::ArrayRef<double>{});
}
wpi::SmallVector<std::string, 8> names;
@@ -404,8 +415,8 @@ void CommandScheduler::InitSendable(frc::SendableBuilder& builder) {
uintptr_t ptrTmp = reinterpret_cast<uintptr_t>(command.first);
ids.emplace_back(static_cast<double>(ptrTmp));
}
m_impl->namesEntry.SetStringArray(names);
m_impl->idsEntry.SetDoubleArray(ids);
nt::NetworkTableEntry(namesEntry).SetStringArray(names);
nt::NetworkTableEntry(idsEntry).SetDoubleArray(ids);
});
}

View File

@@ -247,5 +247,5 @@ void MecanumControllerCommand::Execute() {
void MecanumControllerCommand::End(bool interrupted) { m_timer.Stop(); }
bool MecanumControllerCommand::IsFinished() {
return m_timer.HasPeriodPassed(m_trajectory.TotalTime());
return m_timer.HasElapsed(m_trajectory.TotalTime());
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -15,6 +15,7 @@ ParallelRaceGroup::ParallelRaceGroup(
}
void ParallelRaceGroup::Initialize() {
m_finished = false;
for (auto& commandRunning : m_commands) {
commandRunning->Initialize();
}

View File

@@ -138,5 +138,5 @@ void RamseteCommand::Execute() {
void RamseteCommand::End(bool interrupted) { m_timer.Stop(); }
bool RamseteCommand::IsFinished() {
return m_timer.HasPeriodPassed(m_trajectory.TotalTime());
return m_timer.HasElapsed(m_trajectory.TotalTime());
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -21,6 +21,6 @@ void WaitCommand::Initialize() {
void WaitCommand::End(bool interrupted) { m_timer.Stop(); }
bool WaitCommand::IsFinished() { return m_timer.HasPeriodPassed(m_duration); }
bool WaitCommand::IsFinished() { return m_timer.HasElapsed(m_duration); }
bool WaitCommand::RunsWhenDisabled() const { return true; }

View File

@@ -15,8 +15,8 @@ Trigger::Trigger(const Trigger& other) : m_isActive(other.m_isActive) {}
Trigger Trigger::WhenActive(Command* command, bool interruptible) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command, interruptible]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command, interruptible]() mutable {
bool pressed = m_isActive();
if (!pressedLast && pressed) {
command->Schedule(interruptible);
@@ -41,8 +41,8 @@ Trigger Trigger::WhenActive(std::function<void()> toRun,
Trigger Trigger::WhileActiveContinous(Command* command, bool interruptible) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command, interruptible]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command, interruptible]() mutable {
bool pressed = m_isActive();
if (pressed) {
command->Schedule(interruptible);
@@ -70,8 +70,8 @@ Trigger Trigger::WhileActiveContinous(std::function<void()> toRun,
Trigger Trigger::WhileActiveOnce(Command* command, bool interruptible) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command, interruptible]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command, interruptible]() mutable {
bool pressed = m_isActive();
if (!pressedLast && pressed) {
command->Schedule(interruptible);
@@ -86,8 +86,8 @@ Trigger Trigger::WhileActiveOnce(Command* command, bool interruptible) {
Trigger Trigger::WhenInactive(Command* command, bool interruptible) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command, interruptible]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command, interruptible]() mutable {
bool pressed = m_isActive();
if (pressedLast && !pressed) {
command->Schedule(interruptible);
@@ -111,8 +111,8 @@ Trigger Trigger::WhenInactive(std::function<void()> toRun,
Trigger Trigger::ToggleWhenActive(Command* command, bool interruptible) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command, interruptible]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command, interruptible]() mutable {
bool pressed = m_isActive();
if (!pressedLast && pressed) {
if (command->IsScheduled()) {
@@ -129,8 +129,8 @@ Trigger Trigger::ToggleWhenActive(Command* command, bool interruptible) {
Trigger Trigger::CancelWhenActive(Command* command) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this, command]() mutable {
bool pressed = Get();
[pressedLast = m_isActive(), *this, command]() mutable {
bool pressed = m_isActive();
if (!pressedLast && pressed) {
command->Cancel();

View File

@@ -103,7 +103,7 @@ void SwerveControllerCommand<NumModules>::End(bool interrupted) {
template <size_t NumModules>
bool SwerveControllerCommand<NumModules>::IsFinished() {
return m_timer.HasPeriodPassed(m_trajectory.TotalTime());
return m_timer.HasElapsed(m_trajectory.TotalTime());
}
} // namespace frc2

View File

@@ -72,7 +72,7 @@ class TrapezoidProfileCommand
void End(bool interrupted) override { m_timer.Stop(); }
bool IsFinished() override {
return m_timer.HasPeriodPassed(m_profile.TotalTime());
return m_timer.HasElapsed(m_profile.TotalTime());
}
private:

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -26,12 +26,8 @@ class JoystickButton : public Button {
* @param buttonNumber The number of the button on the joystic.
*/
explicit JoystickButton(frc::GenericHID* joystick, int buttonNumber)
: m_joystick{joystick}, m_buttonNumber{buttonNumber} {}
bool Get() const override { return m_joystick->GetRawButton(m_buttonNumber); }
private:
frc::GenericHID* m_joystick;
int m_buttonNumber;
: Button([joystick, buttonNumber] {
return joystick->GetRawButton(buttonNumber);
}) {}
};
} // namespace frc2

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -27,15 +27,8 @@ class POVButton : public Button {
* @param povNumber The number of the POV on the joystick.
*/
POVButton(frc::GenericHID* joystick, int angle, int povNumber = 0)
: m_joystick{joystick}, m_angle{angle}, m_povNumber{povNumber} {}
bool Get() const override {
return m_joystick->GetPOV(m_povNumber) == m_angle;
}
private:
frc::GenericHID* m_joystick;
int m_angle;
int m_povNumber;
: Button([joystick, angle, povNumber] {
return joystick->GetPOV(povNumber) == angle;
}) {}
};
} // namespace frc2

View File

@@ -47,13 +47,6 @@ class Trigger {
Trigger(const Trigger& other);
/**
* Returns whether the trigger is active. Can be overridden by a subclass.
*
* @return Whether the trigger is active.
*/
virtual bool Get() const { return m_isActive(); }
/**
* Binds a command to start when the trigger becomes active. Takes a
* raw pointer, and so is non-owning; users are responsible for the lifespan
@@ -79,11 +72,11 @@ class Trigger {
Command, std::remove_reference_t<T>>>>
Trigger WhenActive(T&& command, bool interruptible = true) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this,
[pressedLast = m_isActive(), *this,
command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command)),
interruptible]() mutable {
bool pressed = Get();
bool pressed = m_isActive();
if (!pressedLast && pressed) {
command->Schedule(interruptible);
@@ -138,11 +131,11 @@ class Trigger {
Command, std::remove_reference_t<T>>>>
Trigger WhileActiveContinous(T&& command, bool interruptible = true) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this,
[pressedLast = m_isActive(), *this,
command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command)),
interruptible]() mutable {
bool pressed = Get();
bool pressed = m_isActive();
if (pressed) {
command->Schedule(interruptible);
@@ -198,11 +191,11 @@ class Trigger {
Command, std::remove_reference_t<T>>>>
Trigger WhileActiveOnce(T&& command, bool interruptible = true) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this,
[pressedLast = m_isActive(), *this,
command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command)),
interruptible]() mutable {
bool pressed = Get();
bool pressed = m_isActive();
if (!pressedLast && pressed) {
command->Schedule(interruptible);
@@ -240,11 +233,11 @@ class Trigger {
Command, std::remove_reference_t<T>>>>
Trigger WhenInactive(T&& command, bool interruptible = true) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this,
[pressedLast = m_isActive(), *this,
command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command)),
interruptible]() mutable {
bool pressed = Get();
bool pressed = m_isActive();
if (pressedLast && !pressed) {
command->Schedule(interruptible);
@@ -298,11 +291,11 @@ class Trigger {
Command, std::remove_reference_t<T>>>>
Trigger ToggleWhenActive(T&& command, bool interruptible = true) {
CommandScheduler::GetInstance().AddButton(
[pressedLast = Get(), *this,
[pressedLast = m_isActive(), *this,
command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command)),
interruptible]() mutable {
bool pressed = Get();
bool pressed = m_isActive();
if (!pressedLast && pressed) {
if (command->IsScheduled()) {
@@ -333,7 +326,7 @@ class Trigger {
* @return A trigger which is active when both component triggers are active.
*/
Trigger operator&&(Trigger rhs) {
return Trigger([*this, rhs] { return Get() && rhs.Get(); });
return Trigger([*this, rhs] { return m_isActive() && rhs.m_isActive(); });
}
/**
@@ -342,7 +335,7 @@ class Trigger {
* @return A trigger which is active when either component trigger is active.
*/
Trigger operator||(Trigger rhs) {
return Trigger([*this, rhs] { return Get() || rhs.Get(); });
return Trigger([*this, rhs] { return m_isActive() || rhs.m_isActive(); });
}
/**
@@ -352,7 +345,7 @@ class Trigger {
* and vice-versa.
*/
Trigger operator!() {
return Trigger([*this] { return !Get(); });
return Trigger([*this] { return !m_isActive(); });
}
private:

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -15,6 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -160,4 +161,50 @@ class ParallelRaceGroupTest extends CommandTestBase {
}
@Test
void parallelRaceScheduleTwiceTest() {
CommandScheduler scheduler = new CommandScheduler();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
MockCommandHolder command2Holder = new MockCommandHolder(true);
Command command2 = command2Holder.getMock();
Command group = new ParallelRaceGroup(command1, command2);
scheduler.schedule(group);
verify(command1).initialize();
verify(command2).initialize();
command1Holder.setFinished(true);
scheduler.run();
command2Holder.setFinished(true);
scheduler.run();
verify(command1).execute();
verify(command1).end(false);
verify(command2).execute();
verify(command2).end(true);
verify(command2, never()).end(false);
assertFalse(scheduler.isScheduled(group));
reset(command1);
reset(command2);
scheduler.schedule(group);
verify(command1).initialize();
verify(command2).initialize();
scheduler.run();
scheduler.run();
assertTrue(scheduler.isScheduled(group));
command2Holder.setFinished(true);
scheduler.run();
assertFalse(scheduler.isScheduled(group));
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -54,4 +54,22 @@ class SchedulerTest extends CommandTestBase {
scheduler.registerSubsystem(system);
assertDoesNotThrow(() -> scheduler.unregisterSubsystem(system));
}
@Test
void schedulerCancelAllTest() {
CommandScheduler scheduler = new CommandScheduler();
Counter counter = new Counter();
scheduler.onCommandInterrupt(command -> counter.increment());
Command command = new WaitCommand(10);
Command command2 = new WaitCommand(10);
scheduler.schedule(command);
scheduler.schedule(command2);
scheduler.cancelAll();
assertEquals(counter.m_counter, 2);
}
}

View File

@@ -0,0 +1,47 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include <frc/Joystick.h>
#include <mockdata/DriverStationData.h>
#include "CommandTestBase.h"
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/RunCommand.h"
#include "frc2/command/WaitUntilCommand.h"
#include "frc2/command/button/POVButton.h"
#include "gtest/gtest.h"
using namespace frc2;
class POVButtonTest : public CommandTestBase {};
TEST_F(POVButtonTest, SetPOVTest) {
HAL_JoystickPOVs povs;
povs.count = 1;
povs.povs[0] = 0;
HALSIM_SetJoystickPOVs(1, &povs);
HALSIM_NotifyDriverStationNewData();
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
WaitUntilCommand command([&finished] { return finished; });
frc::Joystick joy(1);
POVButton(&joy, 90).WhenPressed(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
povs.povs[0] = 90;
HALSIM_SetJoystickPOVs(1, &povs);
HALSIM_NotifyDriverStationNewData();
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command));
finished = true;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -154,3 +154,54 @@ TEST_F(ParallelRaceGroupTest, ParallelRaceOnlyCallsEndOnceTest) {
EXPECT_NO_FATAL_FAILURE(scheduler.Run());
EXPECT_FALSE(scheduler.IsScheduled(&group2));
}
TEST_F(ParallelRaceGroupTest, ParallelRaceScheduleTwiceTest) {
CommandScheduler scheduler = GetScheduler();
std::unique_ptr<MockCommand> command1Holder = std::make_unique<MockCommand>();
std::unique_ptr<MockCommand> command2Holder = std::make_unique<MockCommand>();
std::unique_ptr<MockCommand> command3Holder = std::make_unique<MockCommand>();
MockCommand* command1 = command1Holder.get();
MockCommand* command2 = command2Holder.get();
MockCommand* command3 = command3Holder.get();
ParallelRaceGroup group{tcb::make_vector<std::unique_ptr<Command>>(
std::move(command1Holder), std::move(command2Holder),
std::move(command3Holder))};
EXPECT_CALL(*command1, Initialize()).Times(2);
EXPECT_CALL(*command1, Execute()).Times(5);
EXPECT_CALL(*command1, End(true)).Times(2);
EXPECT_CALL(*command2, Initialize()).Times(2);
EXPECT_CALL(*command2, Execute()).Times(5);
EXPECT_CALL(*command2, End(false)).Times(2);
EXPECT_CALL(*command3, Initialize()).Times(2);
EXPECT_CALL(*command3, Execute()).Times(5);
EXPECT_CALL(*command3, End(true)).Times(2);
scheduler.Schedule(&group);
scheduler.Run();
command2->SetFinished(true);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&group));
command2->SetFinished(false);
scheduler.Schedule(&group);
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&group));
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&group));
command2->SetFinished(true);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&group));
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -54,3 +54,21 @@ TEST_F(SchedulerTest, UnregisterSubsystemTest) {
EXPECT_NO_FATAL_FAILURE(scheduler.UnregisterSubsystem(&system));
}
TEST_F(SchedulerTest, SchedulerCancelAllTest) {
CommandScheduler scheduler = GetScheduler();
RunCommand command([] {}, {});
RunCommand command2([] {}, {});
int counter = 0;
scheduler.OnCommandInterrupt([&counter](const Command&) { counter++; });
scheduler.Schedule(&command);
scheduler.Schedule(&command2);
scheduler.Run();
scheduler.CancelAll();
EXPECT_EQ(counter, 2);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -66,7 +66,7 @@ public abstract class PIDSubsystem extends Subsystem {
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values.
* Instantiates a {@link PIDSubsystem} that will use the given p, i, d, and f values.
*
* @param name the name
* @param p the proportional value
@@ -82,7 +82,7 @@ public abstract class PIDSubsystem extends Subsystem {
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will also
* Instantiates a {@link PIDSubsystem} that will use the given p, i, d, and f values. It will also
* space the time between PID loop calculations to be equal to the given period.
*
* @param name the name
@@ -114,9 +114,9 @@ public abstract class PIDSubsystem extends Subsystem {
}
/**
* Instantiates a {@link PIDSubsystem} that will use the given p, i and d values. It will use the
* class name as its name. It will also space the time between PID loop calculations to be equal
* to the given period.
* Instantiates a {@link PIDSubsystem} that will use the given p, i, d, and f values. It will use
* the class name as its name. It will also space the time between PID loop calculations to be
* equal to the given period.
*
* @param p the proportional value
* @param i the integral value

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,6 +17,7 @@ import edu.wpi.first.hal.HAL;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.wpilibj.Sendable;
import edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;
import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
import edu.wpi.first.wpilibj.smartdashboard.SendableRegistry;
@@ -81,9 +82,6 @@ public final class Scheduler implements Sendable, AutoCloseable {
*/
@SuppressWarnings({"PMD.LooseCoupling", "PMD.UseArrayListInsteadOfVector"})
private final Vector<Command> m_additions = new Vector<>();
private NetworkTableEntry m_namesEntry;
private NetworkTableEntry m_idsEntry;
private NetworkTableEntry m_cancelEntry;
/**
* A list of all {@link edu.wpi.first.wpilibj.buttons.Trigger.ButtonScheduler Buttons}. It is
* created lazily.
@@ -98,11 +96,20 @@ public final class Scheduler implements Sendable, AutoCloseable {
private Scheduler() {
HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
SendableRegistry.addLW(this, "Scheduler");
LiveWindow.setEnabledListener(() -> {
disable();
removeAll();
});
LiveWindow.setDisabledListener(() -> {
enable();
});
}
@Override
public void close() {
SendableRegistry.remove(this);
LiveWindow.setEnabledListener(null);
LiveWindow.setDisabledListener(null);
}
/**
@@ -319,13 +326,13 @@ public final class Scheduler implements Sendable, AutoCloseable {
@Override
public void initSendable(SendableBuilder builder) {
builder.setSmartDashboardType("Scheduler");
m_namesEntry = builder.getEntry("Names");
m_idsEntry = builder.getEntry("Ids");
m_cancelEntry = builder.getEntry("Cancel");
final NetworkTableEntry namesEntry = builder.getEntry("Names");
final NetworkTableEntry idsEntry = builder.getEntry("Ids");
final NetworkTableEntry cancelEntry = builder.getEntry("Cancel");
builder.setUpdateTable(() -> {
if (m_namesEntry != null && m_idsEntry != null && m_cancelEntry != null) {
if (namesEntry != null && idsEntry != null && cancelEntry != null) {
// Get the commands to cancel
double[] toCancel = m_cancelEntry.getDoubleArray(new double[0]);
double[] toCancel = cancelEntry.getDoubleArray(new double[0]);
if (toCancel.length > 0) {
for (LinkedListElement e = m_firstCommand; e != null; e = e.getNext()) {
for (double d : toCancel) {
@@ -334,7 +341,7 @@ public final class Scheduler implements Sendable, AutoCloseable {
}
}
}
m_cancelEntry.setDoubleArray(new double[0]);
cancelEntry.setDoubleArray(new double[0]);
}
if (m_runningCommandsChanged) {
@@ -351,8 +358,8 @@ public final class Scheduler implements Sendable, AutoCloseable {
ids[number] = e.getData().hashCode();
number++;
}
m_namesEntry.setStringArray(commands);
m_idsEntry.setDoubleArray(ids);
namesEntry.setStringArray(commands);
idsEntry.setDoubleArray(ids);
}
}
});

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2011-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2011-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -20,6 +20,7 @@
#include "frc/buttons/ButtonScheduler.h"
#include "frc/commands/Command.h"
#include "frc/commands/Subsystem.h"
#include "frc/livewindow/LiveWindow.h"
#include "frc/smartdashboard/SendableBuilder.h"
#include "frc/smartdashboard/SendableRegistry.h"
@@ -198,9 +199,20 @@ Scheduler::Scheduler() : m_impl(new Impl) {
HAL_Report(HALUsageReporting::kResourceType_Command,
HALUsageReporting::kCommand_Scheduler);
SendableRegistry::GetInstance().AddLW(this, "Scheduler");
auto scheduler = frc::LiveWindow::GetInstance();
scheduler->enabled = [this] {
this->SetEnabled(false);
this->RemoveAll();
};
scheduler->disabled = [this] { this->SetEnabled(true); };
}
Scheduler::~Scheduler() {}
Scheduler::~Scheduler() {
SendableRegistry::GetInstance().Remove(this);
auto scheduler = frc::LiveWindow::GetInstance();
scheduler->enabled = nullptr;
scheduler->disabled = nullptr;
}
void Scheduler::Impl::Remove(Command* command) {
if (!commands.erase(command)) return;

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2011-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2011-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -40,7 +40,7 @@ class PIDSubsystem : public Subsystem, public PIDOutput, public PIDSource {
PIDSubsystem(const wpi::Twine& name, double p, double i, double d);
/**
* Instantiates a PIDSubsystem that will use the given P, I, and D values.
* Instantiates a PIDSubsystem that will use the given P, I, D, and F values.
*
* @param name the name
* @param p the proportional value
@@ -51,7 +51,7 @@ class PIDSubsystem : public Subsystem, public PIDOutput, public PIDSource {
PIDSubsystem(const wpi::Twine& name, double p, double i, double d, double f);
/**
* Instantiates a PIDSubsystem that will use the given P, I, and D values.
* Instantiates a PIDSubsystem that will use the given P, I, D, and F values.
*
* It will also space the time between PID loop calculations to be equal to
* the given period.
@@ -78,7 +78,7 @@ class PIDSubsystem : public Subsystem, public PIDOutput, public PIDSource {
PIDSubsystem(double p, double i, double d);
/**
* Instantiates a PIDSubsystem that will use the given P, I, and D values.
* Instantiates a PIDSubsystem that will use the given P, I, D, and F values.
*
* It will use the class name as its name.
*
@@ -90,7 +90,7 @@ class PIDSubsystem : public Subsystem, public PIDOutput, public PIDSource {
PIDSubsystem(double p, double i, double d, double f);
/**
* Instantiates a PIDSubsystem that will use the given P, I, and D values.
* Instantiates a PIDSubsystem that will use the given P, I, D, and F values.
*
* It will use the class name as its name. It will also space the time
* between PID loop calculations to be equal to the given period.

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -21,7 +21,7 @@ ADXL345_I2C::ADXL345_I2C(I2C::Port port, Range range, int deviceAddress)
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simY = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}
// Turn on the measurements

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -20,7 +20,7 @@ ADXL345_SPI::ADXL345_SPI(SPI::Port port, ADXL345_SPI::Range range)
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simY = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}
m_spi.SetClockRate(500000);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -40,7 +40,7 @@ ADXL362::ADXL362(SPI::Port port, Range range)
m_simRange =
m_simDevice.CreateEnum("Range", true, {"2G", "4G", "8G", "16G"}, 0);
m_simX = m_simDevice.CreateDouble("X Accel", false, 0.0);
m_simX = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simY = m_simDevice.CreateDouble("Y Accel", false, 0.0);
m_simZ = m_simDevice.CreateDouble("Z Accel", false, 0.0);
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -18,7 +18,7 @@ void frc::filesystem::GetLaunchDirectory(wpi::SmallVectorImpl<char>& result) {
void frc::filesystem::GetOperatingDirectory(
wpi::SmallVectorImpl<char>& result) {
if (RobotBase::IsReal()) {
if constexpr (RobotBase::IsReal()) {
wpi::sys::path::native("/home/lvuser", result);
} else {
frc::filesystem::GetLaunchDirectory(result);
@@ -27,5 +27,11 @@ void frc::filesystem::GetOperatingDirectory(
void frc::filesystem::GetDeployDirectory(wpi::SmallVectorImpl<char>& result) {
frc::filesystem::GetOperatingDirectory(result);
wpi::sys::path::append(result, "deploy");
if constexpr (RobotBase::IsReal()) {
wpi::sys::path::append(result, "deploy");
} else {
wpi::sys::path::append(result, "src");
wpi::sys::path::append(result, "main");
wpi::sys::path::append(result, "deploy");
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -24,6 +24,10 @@ IterativeRobot::IterativeRobot() : IterativeRobotBase(kPacketPeriod) {
void IterativeRobot::StartCompetition() {
RobotInit();
if (IsSimulation()) {
SimulationInit();
}
// Tell the DS that the robot is ready to be enabled
HAL_ObserveUserProgramStarting();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -34,6 +34,10 @@ void IterativeRobotBase::RobotInit() {
wpi::outs() << "Default " << __FUNCTION__ << "() method... Override me!\n";
}
void IterativeRobotBase::SimulationInit() {
wpi::outs() << "Default " << __FUNCTION__ << "() method... Override me!\n";
}
void IterativeRobotBase::DisabledInit() {
wpi::outs() << "Default " << __FUNCTION__ << "() method... Override me!\n";
}
@@ -58,6 +62,14 @@ void IterativeRobotBase::RobotPeriodic() {
}
}
void IterativeRobotBase::SimulationPeriodic() {
static bool firstRun = true;
if (firstRun) {
wpi::outs() << "Default " << __FUNCTION__ << "() method... Override me!\n";
firstRun = false;
}
}
void IterativeRobotBase::DisabledPeriodic() {
static bool firstRun = true;
if (firstRun) {
@@ -161,6 +173,12 @@ void IterativeRobotBase::LoopFunc() {
m_watchdog.AddEpoch("LiveWindow::UpdateValues()");
Shuffleboard::Update();
m_watchdog.AddEpoch("Shuffleboard::Update()");
if (IsSimulation()) {
SimulationPeriodic();
m_watchdog.AddEpoch("SimulationPeriodic()");
}
m_watchdog.Disable();
// Warn on loop time overruns

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -129,6 +129,8 @@ void Notifier::StartPeriodic(units::second_t period) {
}
void Notifier::Stop() {
std::scoped_lock lock(m_processMutex);
m_periodic = false;
int32_t status = 0;
HAL_CancelNotifierAlarm(m_notifier, &status);
wpi_setHALError(status);

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2008-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -21,6 +21,7 @@ using namespace frc;
const int SensorUtil::kDigitalChannels = HAL_GetNumDigitalChannels();
const int SensorUtil::kAnalogInputs = HAL_GetNumAnalogInputs();
const int SensorUtil::kAnalogOutputs = HAL_GetNumAnalogOutputs();
const int SensorUtil::kSolenoidChannels = HAL_GetNumSolenoidChannels();
const int SensorUtil::kSolenoidModules = HAL_GetNumPCMModules();
const int SensorUtil::kPwmChannels = HAL_GetNumPWMChannels();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -24,6 +24,10 @@ using namespace frc;
void TimedRobot::StartCompetition() {
RobotInit();
if (IsSimulation()) {
SimulationInit();
}
// Tell the DS that the robot is ready to be enabled
HAL_ObserveUserProgramStarting();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,25 +17,25 @@ XboxController::XboxController(int port) : GenericHID(port) {
double XboxController::GetX(JoystickHand hand) const {
if (hand == kLeftHand) {
return GetRawAxis(0);
return GetRawAxis(static_cast<int>(Axis::kLeftX));
} else {
return GetRawAxis(4);
return GetRawAxis(static_cast<int>(Axis::kRightX));
}
}
double XboxController::GetY(JoystickHand hand) const {
if (hand == kLeftHand) {
return GetRawAxis(1);
return GetRawAxis(static_cast<int>(Axis::kLeftY));
} else {
return GetRawAxis(5);
return GetRawAxis(static_cast<int>(Axis::kRightY));
}
}
double XboxController::GetTriggerAxis(JoystickHand hand) const {
if (hand == kLeftHand) {
return GetRawAxis(2);
return GetRawAxis(static_cast<int>(Axis::kLeftTrigger));
} else {
return GetRawAxis(3);
return GetRawAxis(static_cast<int>(Axis::kRightTrigger));
}
}

Some files were not shown because too many files have changed in this diff Show More