Compare commits

...

108 Commits

Author SHA1 Message Date
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
Peter Johnson
32c62449be Add ArrayRef overloads to new command classes (#2216)
Also default requirements to {} in all cases for consistency.
2020-01-01 20:09:17 -08:00
Tyler Veness
6190fcb237 Run wpiformat (#2218) 2020-01-01 20:04:56 -08:00
Declan Freeman-Gleason
012d93b2bd Use an explicit stack instead of recursion when parameterizing splines (#2197)
This PR changes the spline parameterizer to use an explicit stack instead of recursion. This is motivated by the fact that splines with adjacent waypoints with approximately opposite headings will never parameterize. In this case the parameterizer subdivides these malformed splines fine for a while, and then gets stuck parameterizing infinitely on some interval. In the recursive approach, this would lead to a stack overflow. We could implement a recursion depth counter (this is what my team did on our similar trajectory code last season), but it's hard to choose a good number for max depth because the initial amount of stack used varies based on how the user calls Parameterize.

A good solution for this is converting the recursion to an "explicit stack," which basically simulates recursion, but allows us to have a much larger maximum stack size. Because we avoid the stack overflow, we can instead throws a more informative MalformedSplineException. If the user is using the TrajectoryGenerator instead of the SplineParameterizer directly then the TrajectoryGenerator will go ahead and catch the exception, return a harmless empty trajectory, and report and error to the driver station.
2020-01-01 18:23:08 -08:00
Matt
222669dc2c Fix trapezoidal profile PID controller setpoint bug (#2210)
Co-Authored-By: Austin Shalit <austinshalit@gmail.com>
2020-01-01 15:23:25 -08:00
Peter Johnson
abe25b795b TrajectoryUtil.toPathweaverJson: Create parent directories (#2214) 2020-01-01 13:35:04 -08:00
sciencewhiz
354185189c Update ProjectYear to 2020 (#2212) 2020-01-01 11:14:31 -08:00
sciencewhiz
f14fe434a1 Add (Old) qualifier to old subsystem (#2211) 2019-12-31 23:00:35 -06:00
Prateek Machiraju
e874ba9313 Add Color classes for use with AddressableLED (#2127)
Both floating point and 8-bit integer classes are included, as well as a wide selection of color constants.

Co-authored-by: Austin Shalit <austinshalit@gmail.com>
2019-12-30 00:01:20 -06:00
Peter Johnson
96348e835a Fix C++ SendableRegistry::AddChild() (#2207)
Add a Sendable* overload so pointers to sendable objects work appropriately.
Otherwise an AddLW(this) in a child (which is a Sendable*) could be a
different pointer than a void* to the same object.

For example:
  AnalogInput constructor calls AddLW(this)
  AnalogPotentiometer constructor calls AddChild(analog input pointer)

Also add handling for the child object moving (if it's Sendable).
2019-12-29 23:37:14 -06:00
Oblarg
d91796f8d2 fix clang-format version number (#2206) 2019-12-29 21:31:26 -06:00
Peter Johnson
9abce8eb06 Fix subsystem LiveWindow usage (#2202) 2019-12-29 21:28:38 -06:00
Peter Johnson
8b4508ad53 Use default path for networktables.ini in simulation (#2205) 2019-12-29 18:55:02 -06:00
Oblarg
5b7dd186d2 Add templates for new commands for vscode plugin (#2016) 2019-12-29 15:02:49 -06:00
Peter Johnson
6ea13ea8f3 ntcore: Add support for local-only operation (#2204)
StartLocal() causes future calls to StartServer() or StartClient() to have
no effect. StopLocal() re-enables these calls.
2019-12-29 14:56:41 -06:00
Oblarg
44bcf7fb4d Java examples: use non-static imports for constants (#2191) 2019-12-29 14:55:49 -06:00
Oblarg
c7a1dfc0bc Add SlewRateLimiter class (#2192)
This is extremely useful for implementing various "ramping" functions
(such as voltage ramps, setpoint ramps, etc). Usage is straightforward;
it behaves like all of our other filter classes. C++ version is unit-safe.
2019-12-29 13:36:28 -06:00
Peter Johnson
a12bb447e4 Fail cmake build if python3 generate_numbers.py fails (#2203) 2019-12-29 13:12:00 -06:00
Declan Freeman-Gleason
c4bd54ef44 Add JNI binding to suppress driver station error/warning messages (#2200)
This is to allow suppressing an ugly stack trace/error message in a unit test in #2197. It doesn't support the full HALSIM_SetSendError callback stuff (i.e. you can only suppress, not intercept, stack traces with this).
2019-12-27 21:11:26 -06:00
Austin Shalit
f9a11cce5e Remove -no-module-directories flag from javadoc build (#2201) 2019-12-27 10:19:49 -06:00
Peter Johnson
6008671c30 Report WPILib version as part of usage reporting (#2199) 2019-12-26 22:34:10 -06:00
Peter Johnson
7b952d599d Add usage reporting for many new things (#2184)
- new CommandScheduler
- kinematics and odometry classes
- new PIDController
- ProfiledPIDController
- TrapezoidProfile (reported in Constraints class)

Also update instances.txt to match latest NI version.

One side effect is that a couple of classes are no longer constexpr.
2019-12-25 00:42:14 -06:00
Peter Johnson
93cdf68694 Add Constants.cpp for MecanumControllerCommand example (#2196) 2019-12-24 16:19:02 -06:00
Peter Johnson
0c6f24562f Fix bug in ULEB128 decoding (#2195) 2019-12-24 14:12:42 -06:00
Thad House
bdc1cab013 Add support for configuring SPI Auto Stall Config (#2193) 2019-12-24 12:52:58 -06:00
Prateek Machiraju
3259cffc63 Add transform methods to Trajectory (#2187) 2019-12-23 13:16:30 -06:00
Oblarg
67b59f2b31 Minor improvements/fixes to new command framework (#2186) 2019-12-23 01:09:25 -06:00
sciencewhiz
1ce24a7a2f Add 2020 speed controllers (#2188)
Add CTRE TalonFX (PWMTalonFX)
Add Playing with Fusion Venom (PWMVenom)
2019-12-22 13:51:43 -06:00
Prateek Machiraju
635882a9f7 Add getter for initial pose in Trajectory (#2180) 2019-12-21 06:57:39 -08:00
Thad House
71a22861eb Use ManagedStatic for CameraServer (#2174) 2019-12-20 14:20:38 -08:00
Thad House
9cb69c5b46 Add a way to pass in a preconstructed value to ManagedStatic (#2175)
A lot of our cases don't need the lazy construction, but do need manual destruction.
2019-12-20 14:06:22 -08:00
Thad House
5e08bb28f8 Add docs and lifecycle tasks for faster dev builds (#2182) 2019-12-20 13:48:26 -08:00
Oblarg
ea4d1a39e1 Update characterization values to match real robot (#2183)
This is in preparation for an end-to-end trajectory tutorial example.

Co-Authored-By: Dalton Smith <gamefollower26@gmail.com>
2019-12-20 13:46:13 -08:00
Prateek Machiraju
31b588d961 Fix ArmFeedforward Javadocs (#2176) 2019-12-15 14:34:18 -08:00
Thad House
0b80d566ad Use ChipObject HMB function for LED (#2173)
It's fixed in v9 and up.
2019-12-14 21:15:32 -08:00
Peter Johnson
f8294e689b Sim GUI: Add a bit of spacing to the analog inputs (#2170)
This helps make it clear they are separate controls.
2019-12-14 10:49:01 -08:00
Peter Johnson
b78f115fcf Work around VS2019 16.4.0 bugs (#2171)
Work around frontend bug in scoped_lock and code generation bug in reverse_iterator in gtest.

See https://github.com/google/googletest/pull/2635
2019-12-14 10:48:19 -08:00
sciencewhiz
b468c51251 Change AddressableLED example to use consistent PWM port (#2168) 2019-12-11 15:39:36 -08:00
Prateek Machiraju
023c088290 Add toString() to relevant kinematics classes (#2160) 2019-12-09 21:35:43 -08:00
Thad House
8a11d13a39 Fix C++ DutyCycleEncoder int constructor (#2166) 2019-12-09 21:35:00 -08:00
Claudius Tewari
daa81c64a7 Minor javadoc fix in SwerveDriveKinematicsConstraint (#2167) 2019-12-09 21:34:32 -08:00
Peter Johnson
e20d96ea4e Use __has_include for WPILib.h (#2164)
Now that commands and cameraserver libraries are no longer direct dependencies,
it's necessary to check for their presence.
2019-12-07 21:39:58 -08:00
Thad House
a76d006a07 Update native-utils to 2020.7.2 (#2161)
Fixes a bug where source directories were being added to the header search path
2019-12-07 17:18:50 -08:00
Thad House
24c031d692 Increase SPI auto byte count to allow 32 bytes to be sent (#2163)
The FPGA now supports 32 bytes.
2019-12-07 17:18:25 -08:00
Thad House
6b4eecf5fe Add hidden functions to get the SPI system and SPI DMA (#2162)
With the addition of stall configuration, its not very clear how it works, and seems like it would be different
per use. So adding ways to manually get them, so the functionality can be figured out how to be used.
2019-12-07 17:16:14 -08:00
Oblarg
ccdd0fbdb2 Add TrapezoidProfile external PID examples (#2131) 2019-12-07 13:37:54 -08:00
Tyler Veness
5c6b8a0f45 Replace std::is_pod_v with std::is_standard_layout_v (#2159)
The former is deprecated in C++20.
2019-12-07 13:34:52 -08:00
Thad House
67d2fed685 Add DutyCycleEncoder channel constructor (#2158)
Avoids extra boilerplate at user level.
2019-12-06 20:58:04 -08:00
Thad House
d8f11eb149 Hardcode channels for LSB weight (#2153)
Avoids a mutex and a lookup.
2019-12-06 20:56:40 -08:00
Thad House
b2ae75acd8 Add way to disable "no extensions found" message (#2134)
We want it enabled by default, but there have been requests for a way to disable it.
2019-12-06 20:55:36 -08:00
Austin Shalit
4f951789fe Build testbench tests online inorder to improve speed (#2144)
* Attempt to build testbench tests online inorder to improve speed

* Fix contianer reference

* Start to remove jenkins shell script

* Change job names

* Remove sshpass

* Remove teststand code

* Copy test results back

* Fix build by using athena container

* Fail if any command fails

* Remove jenkins test script

* Remove name argument

* Fix param count

* Add build display name

* Fix scp to copy into dir

* Update display names

* Update stage name

* Fix test results scp

* Create local test report dir

* Remove commented out old code

* Remove force pseudo-terminal allocation

* Remove extra variables

* Update readme

* Remove old test runs

* Update license header
2019-12-06 17:46:29 -05:00
Austin Shalit
005c4c5beb Try catch around task dependencies to fix loading in editor (#2156) 2019-12-06 11:46:21 -08:00
Tyler Veness
34f6b3f4c0 Fix C++ RamseteCommand param doxygen (#2157) 2019-12-05 23:54:32 -08:00
Oblarg
f7a93713fa Fix up templated TrapezoidProfile classes (#2151)
* Fix two-phase name lookup bug

* Fix param in ProfiledPIDCommand constructor overload

* Fix ProfiledPIDCommand/Controller
2019-12-04 20:40:37 -08:00
Tyler Veness
8c2ff94d70 Rename MathUtils to MathUtil for consistency with other util classes (#2155) 2019-12-04 20:39:12 -08:00
Thad House
d003ec2dc9 Update to 2020v9 image (#2154)
- Fix VISA include and FPGA header
- Fix missing VISA lib from executables
2019-12-04 20:38:43 -08:00
Peter Johnson
8e7cc3fe78 Add user-friendly SimDeviceSim wrappers (#2150)
This makes unit testing with SimDevice devices much easier.
2019-12-02 23:27:33 -08:00
Matt
6c8f6cf479 Fix bug in cubic and quintic hermetic spline generation (#2139)
Add documentation for spline derivatives and explicitly zero matrices.
2019-12-01 21:29:52 -08:00
Peter Johnson
e37ecd33ae Sim GUI: Add support for LED displays (#2138)
LED displays connect the LEDs in various ways (column major vs row major,
different starting locations, serpentine connection order), so add
configuration parameters for these options.
2019-12-01 21:28:02 -08:00
Prateek Machiraju
57c5523d67 Fix documentation in RamseteCommand (#2149) 2019-12-01 21:27:02 -08:00
Matt
7b9c6ebc2f Fix wpiutilJNIShared linkage typo in wpilibj (#2143) 2019-12-01 13:25:46 -08:00
Oblarg
9a515c80f8 Template C++ LinearFilter to work with unit types (#2142) 2019-11-30 23:12:02 -08:00
Prateek Machiraju
5b73c17f25 Remove encoder velocities methods in DifferentialDriveOdometry (#2147)
It doesn't make sense to continue to provide a less accurate method of performing odometry
when a more accurate method using distances exists.

This also removes the need to pass DifferentialDriveKinematics to the constructor.
2019-11-30 23:10:29 -08:00
Banks T
b8c1024261 Fix PS3Eye VID and PID (#2146) 2019-11-30 12:35:47 -08:00
Prateek Machiraju
2622c6c291 Add default values for b and zeta in RamseteController (#2145)
Values b=2.0 and zeta=0.7 have been well-tested to produce desirable results.
2019-11-29 21:16:01 -08:00
Austin Shalit
f66ae59992 Add HSV helpers to AddressableLED (#2135)
Also change the setLED() method to setRGB() for consistency and clarity.

Add rainbow example to demonstrate HSV usage.
2019-11-29 15:16:57 -08:00
Oblarg
5e97c81d80 Add MedianFilter class for moving-window median (#2136)
This kind of filter is extremely useful for signals that are susceptible to sudden
outliers - ultrasonics, 1-D LIDAR, and results from vision processing are all
good use-cases.

This also modifies the existing ultrasonic examples accordingly.
2019-11-29 15:13:40 -08:00
Tyler Veness
f79b7a058a Remove unnecessary constructor arg for LinearFilter's circular buffers (#2140)
They are initialized in LinearFilter's constructor, so the default is
never used.
2019-11-28 23:27:20 -08:00
Austin Shalit
e49494830f Replace Jenkins with Azure agent (#1914) 2019-11-25 22:00:35 -08:00
sciencewhiz
b67d049ac2 Check status of PDP CAN reads (#2126)
Fixes #2124
2019-11-25 21:47:35 -08:00
Peter Johnson
70102a60b7 SendableRegistry.foreachLiveWindow: Prevent concurrent modification (#2129)
Copy the internal map values into an array before iterating.

In C++, change to recursive mutex as well.
2019-11-25 21:47:06 -08:00
Oblarg
6dcd2b0e2c Improve various subsystem APIs (#2130)
Improves the APIs for various prebuilt subsystems (PIDSubsystem, TrapezoidProfileSubsystem, ProfiledPIDSubsystem). Addresses #2128, and also changes the rather cumbersome getSetpoint API to a more intuitive setSetpoint one. Updates examples to match.
2019-11-25 21:46:47 -08:00
Thad House
ce3973435e HAL_CAN_ReceiveMessage: return MessageNotFound if no callbacks registered (#2133) 2019-11-25 21:45:44 -08:00
Thad House
3fcfc8ea72 Fix double disable segfaulting interrupts (#2132)
Also fixes DigitalOutput not closing correctly.
2019-11-25 21:43:58 -08:00
sciencewhiz
6ceafe3cd0 Fix class reference for logger (#2123) 2019-11-23 07:47:02 -08:00
420 changed files with 11172 additions and 2026 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

@@ -1,6 +1,6 @@
{
"enableCppIntellisense": true,
"currentLanguage": "cpp",
"projectYear": "Beta2020",
"projectYear": "2020",
"teamNumber": 0
}

View File

@@ -37,7 +37,7 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
## Coding Guidelines
WPILib uses modified Google style guides for both C++ and Java, which can be found in the [styleguide repository](https://github.com/wpilibsuite/styleguide). Autoformatters are available for many popular editors at https://github.com/google/styleguide. Running wpiformat is required for all contributions and is enforced by our continuous integration system. We currently use clang-format 5.0 with wpiformat.
WPILib uses modified Google style guides for both C++ and Java, which can be found in the [styleguide repository](https://github.com/wpilibsuite/styleguide). Autoformatters are available for many popular editors at https://github.com/google/styleguide. Running wpiformat is required for all contributions and is enforced by our continuous integration system. We currently use clang-format 6.0 with wpiformat.
While the library should be fully formatted according to the styles, additional elements of the style guide were not followed when the library was initially created. All new code should follow the guidelines. If you are looking for some easy ramp-up tasks, finding areas that don't follow the style guide and fixing them is very welcome.

15
FasterBuilds.md Normal file
View File

@@ -0,0 +1,15 @@
# Faster Builds for Developers
When you run `./gradlew build`, it builds EVERYTHING. This means debug and release builds for desktop and all installed cross compilers. For many developers, this is way too much, and causes much developer pain.
To help with some of these things, common tasks have shortcuts to only build necessary things for common development and testing tasks.
## Development (Desktop)
For projects `wpiutil`, `ntcore`, `cscore`, `hal` `wpilibOldCommands`, `wpilibNewCommands` and `cameraserver`, a `testDesktopJava` and a `testDesktopCpp` task exists. These can be ran with `./gradlew :projectName:task`, and will only build the minimum things required to run those tests.
For `wpilibc`, a `testDesktopCpp` task exists. For `wpilibj`, a `testDesktopJava` task exists.
For `wpilibcExamples`, a `buildDesktopCpp` task exists (These can't be ran, but they can compile).
For `wpilibjExamples`, a `buildDesktopJava` task exists.

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.

View File

@@ -1,19 +1,91 @@
# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- script: echo Hello, world!
displayName: 'Run a one-line script'
- script: |
echo Add other tasks to build, test, and deploy your project.
echo See https://aka.ms/yaml
displayName: 'Run a multi-line script'
# Testing steps for real hardware
trigger:
batch: true
branches:
include:
- master
stages:
- stage: Build
jobs:
- job: IntegrationTests
displayName: Integration Tests
pool:
vmImage: 'Ubuntu 16.04'
container:
image: wpilib/roborio-cross-ubuntu:2020-18.04
timeoutInMinutes: 0
steps:
- task: Gradle@2
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
inputs:
workingDirectory: ''
gradleWrapperFile: 'gradlew'
gradleOptions: '-Xmx3072m'
publishJUnitResults: false
testResultsFiles: '**/TEST-*.xml'
tasks: 'copyWpilibJIntegrationTestJarToOutput copyWpilibCTestLibrariesToOutput'
options: '-Ponlylinuxathena -PbuildServer'
- task: PublishPipelineArtifact@0
inputs:
artifactName: 'Integration Tests'
targetPath: 'build/integrationTestFiles'
- stage: TestBench
displayName: Test Bench
jobs:
- job: Cpp
displayName: C++
pool: RoboRioConnections
timeoutInMinutes: 30
workspace:
clean: all
steps:
- task: DownloadPipelineArtifact@0
inputs:
artifactName: 'Integration Tests'
targetPath: 'build/integrationTestFiles'
- task: ShellScript@2
displayName: Run C++ Tests
inputs:
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
args: 'cpp -A "--gtest_output=xml:/home/admin/testResults/cppreport.xml"'
- task: PublishTestResults@2
displayName: Publish C++ Test Results
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
testRunTitle: 'C++ Test Report'
searchFolder: '$(System.DefaultWorkingDirectory)/test-reports'
- job: Java
pool: RoboRioConnections
timeoutInMinutes: 30
workspace:
clean: all
steps:
- task: DownloadPipelineArtifact@0
inputs:
artifactName: 'Integration Tests'
targetPath: 'build/integrationTestFiles'
- task: ShellScript@2
displayName: Run Java Tests
inputs:
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
args: 'java'
- task: PublishTestResults@2
displayName: Publish Java Test Results
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '*.xml'
testRunTitle: 'Java Test Report'
searchFolder: '$(System.DefaultWorkingDirectory)/test-reports'

View File

@@ -6,7 +6,7 @@ plugins {
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2'
id 'edu.wpi.first.NativeUtils' apply false
id 'edu.wpi.first.GradleJni' version '0.10.1'
id 'edu.wpi.first.GradleVsCode' version '0.10.0'
id 'edu.wpi.first.GradleVsCode' version '0.11.0'
id 'idea'
id 'visual-studio'
id 'net.ltgt.errorprone' version '1.1.1' apply false

View File

@@ -5,5 +5,5 @@ repositories {
}
}
dependencies {
implementation "edu.wpi.first:native-utils:2020.5.2"
implementation "edu.wpi.first:native-utils:2020.7.2"
}

View File

@@ -13,6 +13,7 @@
#include <networktables/NetworkTable.h>
#include <networktables/NetworkTableInstance.h>
#include <wpi/DenseMap.h>
#include <wpi/ManagedStatic.h>
#include <wpi/SmallString.h>
#include <wpi/StringMap.h>
#include <wpi/mutex.h>
@@ -47,8 +48,14 @@ struct CameraServer::Impl {
};
CameraServer* CameraServer::GetInstance() {
static CameraServer instance;
return &instance;
struct Creator {
static void* call() { return new CameraServer{}; }
};
struct Deleter {
static void call(void* ptr) { delete static_cast<CameraServer*>(ptr); }
};
static wpi::ManagedStatic<CameraServer, Creator, Deleter> instance;
return &(*instance);
}
static wpi::StringRef MakeSourceValue(CS_Source source,

View File

@@ -412,7 +412,11 @@ std::unique_ptr<PropertyImpl> HttpCameraImpl::CreateEmptyProperty(
}
bool HttpCameraImpl::CacheProperties(CS_Status* status) const {
#ifdef _MSC_VER // work around VS2019 16.4.0 bug
std::scoped_lock<wpi::mutex> lock(m_mutex);
#else
std::scoped_lock lock(m_mutex);
#endif
// Pretty typical set of video modes
m_videoModes.clear();

View File

@@ -78,7 +78,11 @@ template <typename THandle, typename TStruct, int typeValue, typename TMutex>
template <typename... Args>
THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
Args&&... args) {
#ifdef _MSC_VER // work around VS2019 16.4.0 bug
std::scoped_lock<TMutex> lock(m_handleMutex);
#else
std::scoped_lock sync(m_handleMutex);
#endif
size_t i;
for (i = 0; i < m_structures.size(); i++) {
if (m_structures[i] == nullptr) {

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,12 +1216,13 @@ 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) {
int vendorId, productId;
if (GetVendorProduct(deviceNum, &vendorId, &productId)) {
m_ps3eyecam_exposure = vendorId == 0x2000 && productId == 0x0145;
m_ps3eyecam_exposure = vendorId == 0x1415 && productId == 0x2000;
}
}
}
@@ -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

@@ -192,7 +192,7 @@ model {
if (!(it instanceof NativeBinarySpec)) return
if (it.component.name != 'hal' && it.component.name != 'halBase') return
if (it.targetPlatform.name != nativeUtils.wpi.platforms.roborio) return
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared')
}
}
}

View File

@@ -3,6 +3,7 @@ kLanguage_CPlusPlus = 2
kLanguage_Java = 3
kLanguage_Python = 4
kLanguage_DotNet = 5
kLanguage_Kotlin = 6
kCANPlugin_BlackJagBridge = 1
kCANPlugin_2CAN = 2
kFramework_Iterative = 1
@@ -41,4 +42,11 @@ kDriverStationEIO_TouchSlider = 11
kADXL345_SPI = 1
kADXL345_I2C = 2
kCommand_Scheduler = 1
kCommand2_Scheduler = 2
kSmartDashboard_Instance = 1
kKinematics_DifferentialDrive = 1
kKinematics_MecanumDrive = 2
kKinematics_SwerveDrive = 3
kOdometry_DifferentialDrive = 1
kOdometry_MecanumDrive = 2
kOdometry_SwerveDrive = 3

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2019 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. */
@@ -61,4 +61,6 @@ public class SPIJNI extends JNIWrapper {
double timeout);
public static native int spiGetAutoDroppedCount(int port);
public static native void spiConfigureAutoStall(int port, int csToSclkTicks, int stallTicks, int pow2BytesPerRead);
}

View File

@@ -79,6 +79,15 @@ public class DriverStationSim {
DriverStationDataJNI.notifyNewData();
}
/**
* Toggles suppression of DriverStation.reportError and reportWarning messages.
*
* @param shouldSend If false then messages will will be suppressed.
*/
public void setSendError(boolean shouldSend) {
DriverStationDataJNI.setSendError(shouldSend);
}
public void resetData() {
DriverStationDataJNI.resetData();
}

View File

@@ -0,0 +1,94 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 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. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.hal.sim;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDouble;
import edu.wpi.first.hal.SimEnum;
import edu.wpi.first.hal.SimValue;
import edu.wpi.first.hal.sim.mockdata.SimDeviceDataJNI;
public class SimDeviceSim {
private final int m_handle;
public SimDeviceSim(String name) {
m_handle = SimDeviceDataJNI.getSimDeviceHandle(name);
}
public SimValue getValue(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
return null;
}
return new SimValue(handle);
}
public SimDouble getDouble(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
return null;
}
return new SimDouble(handle);
}
public SimEnum getEnum(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
return null;
}
return new SimEnum(handle);
}
public SimBoolean getBoolean(String name) {
int handle = SimDeviceDataJNI.getSimValueHandle(m_handle, name);
if (handle <= 0) {
return null;
}
return new SimBoolean(handle);
}
public static String[] getEnumOptions(SimEnum val) {
return SimDeviceDataJNI.getSimValueEnumOptions(val.getNativeHandle());
}
public SimDeviceDataJNI.SimValueInfo[] enumerateValues() {
return SimDeviceDataJNI.enumerateSimValues(m_handle);
}
public int getNativeHandle() {
return m_handle;
}
public CallbackStore registerValueCreatedCallback(SimValueCallback callback, boolean initialNotify) {
int uid = SimDeviceDataJNI.registerSimValueCreatedCallback(m_handle, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueCreatedCallback);
}
public CallbackStore registerValueChangedCallback(SimValueCallback callback, boolean initialNotify) {
int uid = SimDeviceDataJNI.registerSimValueChangedCallback(m_handle, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimValueChangedCallback);
}
public static SimDeviceDataJNI.SimDeviceInfo[] enumerateDevices(String prefix) {
return SimDeviceDataJNI.enumerateSimDevices(prefix);
}
public CallbackStore registerDeviceCreatedCallback(String prefix, SimDeviceCallback callback, boolean initialNotify) {
int uid = SimDeviceDataJNI.registerSimDeviceCreatedCallback(prefix, callback, initialNotify);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimDeviceCreatedCallback);
}
public CallbackStore registerDeviceFreedCallback(String prefix, SimDeviceCallback callback) {
int uid = SimDeviceDataJNI.registerSimDeviceFreedCallback(prefix, callback);
return new CallbackStore(uid, SimDeviceDataJNI::cancelSimDeviceFreedCallback);
}
public static void resetData() {
SimDeviceDataJNI.resetSimDeviceData();
}
}

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2019 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. */
@@ -49,5 +49,7 @@ public class DriverStationDataJNI extends JNIWrapper {
public static native void registerAllCallbacks(NotifyCallback callback, boolean initialNotify);
public static native void notifyNewData();
public static native void setSendError(boolean shouldSend);
public static native void resetData();
}

View File

@@ -21,14 +21,6 @@
using namespace hal;
extern "C" {
NiFpga_Status NiFpga_ClientFunctionCall(NiFpga_Session session, uint32_t group,
uint32_t functionId,
const void* inBuffer,
size_t inBufferSize, void* outBuffer,
size_t outBufferSize);
} // extern "C"
namespace {
struct AddressableLED {
std::unique_ptr<tLED> led;
@@ -54,43 +46,6 @@ void InitializeAddressableLED() {
} // namespace init
} // namespace hal
// Shim for broken ChipObject function
static const uint32_t clientFeature_hostMemoryBuffer = 0;
static const uint32_t hostMemoryBufferFunction_open = 2;
// Input arguments for HMB open
struct AtomicHMBOpenInputs {
const char* memoryName;
};
// Output arguments for HMB open
struct AtomicHMBOpenOutputs {
size_t size;
void* virtualAddress;
};
static NiFpga_Status OpenHostMemoryBuffer(NiFpga_Session session,
const char* memoryName,
void** virtualAddress, size_t* size) {
struct AtomicHMBOpenOutputs outputs;
struct AtomicHMBOpenInputs inputs;
inputs.memoryName = memoryName;
NiFpga_Status retval = NiFpga_ClientFunctionCall(
session, clientFeature_hostMemoryBuffer, hostMemoryBufferFunction_open,
&inputs, sizeof(struct AtomicHMBOpenInputs), &outputs,
sizeof(struct AtomicHMBOpenOutputs));
if (NiFpga_IsError(retval)) {
return retval;
}
*virtualAddress = outputs.virtualAddress;
if (size != NULL) {
*size = outputs.size;
}
return retval;
}
extern "C" {
HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
@@ -148,8 +103,8 @@ HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
uint32_t session = led->led->getSystemInterface()->getHandle();
*status = OpenHostMemoryBuffer(session, "HMB_0_LED", &led->ledBuffer,
&led->ledBufferSize);
*status = NiFpga_OpenHostMemoryBuffer(session, "HMB_0_LED", &led->ledBuffer,
&led->ledBufferSize);
if (*status != 0) {
addressableLEDHandles->Free(handle);

View File

@@ -224,26 +224,38 @@ double HAL_GetAnalogAverageVoltage(HAL_AnalogInputHandle analogPortHandle,
int32_t HAL_GetAnalogLSBWeight(HAL_AnalogInputHandle analogPortHandle,
int32_t* status) {
auto port = analogInputHandles->Get(analogPortHandle);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
int32_t lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(
0, port->channel, status); // XXX: aiSystemIndex == 0?
return lsbWeight;
// On the roboRIO, LSB is the same for all channels. So the channel lookup can
// be avoided
return FRC_NetworkCommunication_nAICalibration_getLSBWeight(0, 0, status);
// Keep the old code for future hardware
// auto port = analogInputHandles->Get(analogPortHandle);
// if (port == nullptr) {
// *status = HAL_HANDLE_ERROR;
// return 0;
// }
// int32_t lsbWeight = FRC_NetworkCommunication_nAICalibration_getLSBWeight(
// 0, port->channel, status); // XXX: aiSystemIndex == 0?
// return lsbWeight;
}
int32_t HAL_GetAnalogOffset(HAL_AnalogInputHandle analogPortHandle,
int32_t* status) {
auto port = analogInputHandles->Get(analogPortHandle);
if (port == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
int32_t offset = FRC_NetworkCommunication_nAICalibration_getOffset(
0, port->channel, status); // XXX: aiSystemIndex == 0?
return offset;
// On the roboRIO, offset is the same for all channels. So the channel lookup
// can be avoided
return FRC_NetworkCommunication_nAICalibration_getOffset(0, 0, status);
// Keep the old code for future hardware
// auto port = analogInputHandles->Get(analogPortHandle);
// if (port == nullptr) {
// *status = HAL_HANDLE_ERROR;
// return 0;
// }
// int32_t offset = FRC_NetworkCommunication_nAICalibration_getOffset(
// 0, port->channel, status); // XXX: aiSystemIndex == 0?
// return offset;
}
} // extern "C"

View File

@@ -11,6 +11,7 @@
#include <cstddef>
#include <cstring>
#include <memory>
#include <type_traits>
#include "AnalogInternal.h"
#include "DigitalInternal.h"
@@ -28,7 +29,8 @@
using namespace hal;
static_assert(std::is_pod_v<HAL_DMASample>, "DMA Sample must be POD");
static_assert(std::is_standard_layout_v<HAL_DMASample>,
"HAL_DMASample must have standard layout");
namespace {

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

@@ -118,7 +118,11 @@ void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
if (anInterrupt == nullptr) {
return nullptr;
}
anInterrupt->manager->disable(status);
if (anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->disable(status);
}
void* param = anInterrupt->param;
return param;
}
@@ -152,7 +156,10 @@ void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
*status = HAL_HANDLE_ERROR;
return;
}
anInterrupt->manager->enable(status);
if (!anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->enable(status);
}
}
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
@@ -162,7 +169,9 @@ void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
*status = HAL_HANDLE_ERROR;
return;
}
anInterrupt->manager->disable(status);
if (anInterrupt->manager->isEnabled(status)) {
anInterrupt->manager->disable(status);
}
}
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,

View File

@@ -175,7 +175,11 @@ double HAL_GetPDPTemperature(HAL_PDPHandle handle, int32_t* status) {
HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
if (*status != 0) {
return 0;
} else {
return pdpStatus.bits.temp * 1.03250836957542 - 67.8564500484966;
}
}
double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
@@ -186,7 +190,11 @@ double HAL_GetPDPVoltage(HAL_PDPHandle handle, int32_t* status) {
HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
if (*status != 0) {
return 0;
} else {
return pdpStatus.bits.busVoltage * 0.05 + 4.0; /* 50mV per unit plus 4V. */
}
}
double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
@@ -205,6 +213,9 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
PdpStatus1 pdpStatus;
HAL_ReadCANPacketTimeout(handle, Status1, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
switch (channel) {
case 0:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan1_h8) << 2) |
@@ -235,6 +246,9 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
PdpStatus2 pdpStatus;
HAL_ReadCANPacketTimeout(handle, Status2, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
switch (channel) {
case 6:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan7_h8) << 2) |
@@ -265,6 +279,9 @@ double HAL_GetPDPChannelCurrent(HAL_PDPHandle handle, int32_t channel,
PdpStatus3 pdpStatus;
HAL_ReadCANPacketTimeout(handle, Status3, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
switch (channel) {
case 12:
raw = (static_cast<uint32_t>(pdpStatus.bits.chan13_h8) << 2) |
@@ -365,6 +382,9 @@ double HAL_GetPDPTotalCurrent(HAL_PDPHandle handle, int32_t* status) {
HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
uint32_t raw;
raw = pdpStatus.bits.TotalCurrent_125mAperunit_h8;
@@ -380,6 +400,9 @@ double HAL_GetPDPTotalPower(HAL_PDPHandle handle, int32_t* status) {
HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
uint32_t raw;
raw = pdpStatus.bits.Power_125mWperunit_h4;
@@ -397,6 +420,9 @@ double HAL_GetPDPTotalEnergy(HAL_PDPHandle handle, int32_t* status) {
HAL_ReadCANPacketTimeout(handle, StatusEnergy, pdpStatus.data, &length,
&receivedTimestamp, TimeoutMs, status);
if (*status != 0) {
return 0;
}
uint32_t raw;
raw = pdpStatus.bits.Energy_125mWPerUnitXTmeas_h4;

View File

@@ -565,7 +565,7 @@ void HAL_StopSPIAuto(HAL_SPIPort port, int32_t* status) {
void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
int32_t dataSize, int32_t zeroSize,
int32_t* status) {
if (dataSize < 0 || dataSize > 16) {
if (dataSize < 0 || dataSize > 32) {
*status = PARAMETER_OUT_OF_RANGE;
return;
}
@@ -589,7 +589,7 @@ void HAL_SetSPIAutoTransmitData(HAL_SPIPort port, const uint8_t* dataToSend,
// set byte counts
tSPI::tAutoByteCount config;
config.ZeroByteCount = static_cast<unsigned>(zeroSize) & 0x7f;
config.TxByteCount = static_cast<unsigned>(dataSize) & 0xf;
config.TxByteCount = static_cast<unsigned>(dataSize) & 0x1f;
spiSystem->writeAutoByteCount(config, status);
}
@@ -631,4 +631,21 @@ int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status) {
return spiSystem->readTransferSkippedFullCount(status);
}
void HAL_ConfigureSPIAutoStall(HAL_SPIPort port, int32_t csToSclkTicks,
int32_t stallTicks, int32_t pow2BytesPerRead,
int32_t* status) {
std::scoped_lock lock(spiAutoMutex);
// FPGA only has one auto SPI engine
if (port != spiAutoPort) {
*status = INCOMPATIBLE_STATE;
return;
}
tSPI::tStallConfig stallConfig;
stallConfig.CsToSclkTicks = static_cast<uint8_t>(csToSclkTicks);
stallConfig.StallTicks = static_cast<uint16_t>(stallTicks);
stallConfig.Pow2BytesPerRead = static_cast<uint8_t>(pow2BytesPerRead);
spiSystem->writeStallConfig(stallConfig, status);
}
} // extern "C"

View File

@@ -394,4 +394,20 @@ Java_edu_wpi_first_hal_SPIJNI_spiGetAutoDroppedCount
return retval;
}
/*
* Class: edu_wpi_first_hal_SPIJNI
* Method: spiConfigureAutoStall
* Signature: (IIII)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_SPIJNI_spiConfigureAutoStall
(JNIEnv* env, jclass, jint port, jint csToSclkTicks, jint stallTicks,
jint pow2BytesPerRead)
{
int32_t status = 0;
HAL_ConfigureSPIAutoStall(static_cast<HAL_SPIPort>(port), csToSclkTicks,
stallTicks, pow2BytesPerRead, &status);
CheckStatus(env, status);
}
} // extern "C"

View File

@@ -27,6 +27,7 @@
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tDutyCycle.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tEncoder.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tGlobal.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tHMB.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tInterrupt.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tLED.h>
#include <FRC_FPGA_ChipObject/nRoboRIO_FPGANamespace/tPWM.h>

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2019 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,6 +7,8 @@
#pragma once
#include "hal/Types.h"
/**
* @defgroup hal_extensions Simulator Extensions
* @ingroup hal_capi
@@ -41,5 +43,19 @@ int HAL_LoadOneExtension(const char* library);
* @return the succes state of the initialization
*/
int HAL_LoadExtensions(void);
/**
* Enables or disables the message saying no HAL extensions were found.
*
* Some apps don't care, and the message create clutter. For general team code,
* we want it.
*
* This must be called before HAL_Initialize is called.
*
* This defaults to true.
*
* @param showMessage true to show message, false to not.
*/
void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage);
} // extern "C"
/** @} */

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2019 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. */
@@ -244,6 +244,19 @@ int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
*/
int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status);
/**
* Configure the Auto SPI Stall time between reads.
*
* @param port The number of the port to use. 0-3 for Onboard CS0-CS2, 4 for
* MXP.
* @param csToSclkTicks the number of ticks to wait before asserting the cs pin
* @param stallTicks the number of ticks to stall for
* @param pow2BytesPerRead the number of bytes to read before stalling
*/
void HAL_ConfigureSPIAutoStall(HAL_SPIPort port, int32_t csToSclkTicks,
int32_t stallTicks, int32_t pow2BytesPerRead,
int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -74,7 +74,11 @@ class SimCallbackRegistry : public impl::SimCallbackRegistryBase {
template <typename... U>
void Invoke(U&&... u) const {
#ifdef _MSC_VER // work around VS2019 16.4.0 bug
std::scoped_lock<wpi::recursive_spinlock> lock(m_mutex);
#else
std::scoped_lock lock(m_mutex);
#endif
if (m_callbacks) {
const char* name = GetName();
for (auto&& cb : *m_callbacks)

View File

@@ -0,0 +1,79 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 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 <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "CallbackStore.h"
#include "hal/SimDevice.h"
#include "mockdata/SimDeviceData.h"
namespace frc {
namespace sim {
class SimDeviceSim {
public:
explicit SimDeviceSim(const char* name)
: m_handle{HALSIM_GetSimDeviceHandle(name)} {}
hal::SimValue GetValue(const char* name) const {
return HALSIM_GetSimValueHandle(m_handle, name);
}
hal::SimDouble GetDouble(const char* name) const {
return HALSIM_GetSimValueHandle(m_handle, name);
}
hal::SimEnum GetEnum(const char* name) const {
return HALSIM_GetSimValueHandle(m_handle, name);
}
hal::SimBoolean GetBoolean(const char* name) const {
return HALSIM_GetSimValueHandle(m_handle, name);
}
static std::vector<std::string> GetEnumOptions(hal::SimEnum val) {
int32_t numOptions;
const char** options = HALSIM_GetSimValueEnumOptions(val, &numOptions);
std::vector<std::string> rv;
rv.reserve(numOptions);
for (int32_t i = 0; i < numOptions; ++i) rv.emplace_back(options[i]);
return rv;
}
template <typename F>
void EnumerateValues(F callback) const {
return HALSIM_EnumerateSimValues(
m_handle, &callback,
[](const char* name, void* param, HAL_SimValueHandle handle,
HAL_Bool readonly, const struct HAL_Value* value) {
std::invoke(*static_cast<F*>(param), name, handle, readonly, value);
});
}
operator HAL_SimDeviceHandle() const { return m_handle; }
template <typename F>
static void EnumerateDevices(const char* prefix, F callback) {
return HALSIM_EnumerateSimDevices(
prefix, &callback,
[](const char* name, void* param, HAL_SimDeviceHandle handle) {
std::invoke(*static_cast<F*>(param), name, handle);
});
}
static void ResetData() { HALSIM_ResetSimDeviceData(); }
private:
HAL_SimDeviceHandle m_handle;
};
} // namespace sim
} // namespace frc

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2016-2019 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,8 +26,16 @@ void HAL_CAN_SendMessage(uint32_t messageID, const uint8_t* data,
void HAL_CAN_ReceiveMessage(uint32_t* messageID, uint32_t messageIDMask,
uint8_t* data, uint8_t* dataSize,
uint32_t* timeStamp, int32_t* status) {
// Use a data size of 42 as call check. Difficult to add check to invoke
// handler
*dataSize = 42;
auto tmpStatus = *status;
SimCanData->receiveMessage(messageID, messageIDMask, data, dataSize,
timeStamp, status);
// If no handler invoked, return message not found
if (*dataSize == 42 && *status == tmpStatus) {
*status = HAL_ERR_CANSessionMux_MessageNotFound;
}
}
void HAL_CAN_OpenStreamSession(uint32_t* sessionHandle, uint32_t messageID,
uint32_t messageIDMask, uint32_t maxMessages,

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. */
@@ -230,6 +230,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

@@ -41,6 +41,11 @@ void InitializeExtensions() {}
} // namespace init
} // namespace hal
static bool& GetShowNotFoundMessage() {
static bool showMsg = true;
return showMsg;
}
extern "C" {
int HAL_LoadOneExtension(const char* library) {
@@ -91,8 +96,10 @@ int HAL_LoadExtensions(void) {
wpi::SmallVector<wpi::StringRef, 2> libraries;
const char* e = std::getenv("HALSIM_EXTENSIONS");
if (!e) {
wpi::outs() << "HAL Extensions: No extensions found\n";
wpi::outs().flush();
if (GetShowNotFoundMessage()) {
wpi::outs() << "HAL Extensions: No extensions found\n";
wpi::outs().flush();
}
return rc;
}
wpi::StringRef env{e};
@@ -105,4 +112,8 @@ int HAL_LoadExtensions(void) {
return rc;
}
void HAL_SetShowExtensionsNotFoundMessages(HAL_Bool showMessage) {
GetShowNotFoundMessage() = showMessage;
}
} // 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) 2017-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2019 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,8 @@ void InitializeSPI() {}
} // namespace init
} // namespace hal
extern "C" {
void HAL_InitializeSPI(HAL_SPIPort port, int32_t* status) {
hal::init::CheckInit();
SimSPIData[port].initialized = true;
@@ -63,3 +65,9 @@ int32_t HAL_ReadSPIAutoReceivedData(HAL_SPIPort port, uint32_t* buffer,
int32_t HAL_GetSPIAutoDroppedCount(HAL_SPIPort port, int32_t* status) {
return 0;
}
void HAL_ConfigureSPIAutoStall(HAL_SPIPort port, int32_t csToSclkTicks,
int32_t stallTicks, int32_t pow2BytesPerRead,
int32_t* status) {}
} // extern "C"

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2019 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. */
@@ -14,6 +14,7 @@
#include "CallbackStore.h"
#include "edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI.h"
#include "mockdata/DriverStationData.h"
#include "mockdata/MockHooks.h"
using namespace wpi::java;
@@ -446,6 +447,25 @@ Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_notifyNewData
HALSIM_NotifyDriverStationNewData();
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
* Method: setSendError
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI_setSendError
(JNIEnv*, jclass, jboolean shouldSend)
{
if (shouldSend) {
HALSIM_SetSendError(nullptr);
} else {
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; });
}
}
/*
* Class: edu_wpi_first_hal_sim_mockdata_DriverStationDataJNI
* Method: resetData

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

@@ -0,0 +1,31 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 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. */
/*----------------------------------------------------------------------------*/
package edu.wpi.first.hal.sim;
import org.junit.jupiter.api.Test;
import edu.wpi.first.hal.SimBoolean;
import edu.wpi.first.hal.SimDevice;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SimDeviceSimTest {
@Test
void testBasic() {
SimDevice dev = SimDevice.create("test");
SimBoolean devBool = dev.createBoolean("bool", false, false);
SimDeviceSim sim = new SimDeviceSim("test");
SimBoolean simBool = sim.getBoolean("bool");
assertFalse(simBool.get());
simBool.set(true);
assertTrue(devBool.get());
}
}

View File

@@ -0,0 +1,40 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019 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 <wpi/StringRef.h>
#include "gtest/gtest.h"
#include "hal/SimDevice.h"
#include "simulation/SimDeviceSim.h"
using namespace frc::sim;
namespace hal {
TEST(SimDeviceSimTests, TestBasic) {
SimDevice dev{"test"};
SimBoolean devBool = dev.CreateBoolean("bool", false, false);
SimDeviceSim sim{"test"};
SimBoolean simBool = sim.GetBoolean("bool");
EXPECT_FALSE(simBool.Get());
simBool.Set(true);
EXPECT_TRUE(devBool.Get());
}
TEST(SimDeviceSimTests, TestEnumerateDevices) {
SimDevice dev{"test"};
bool foundit = false;
SimDeviceSim::EnumerateDevices(
"te", [&](const char* name, HAL_SimDeviceHandle handle) {
if (wpi::StringRef(name) == "test") foundit = true;
});
EXPECT_TRUE(foundit);
}
} // namespace hal

View File

@@ -86,18 +86,27 @@ deploy {
}
tasks.register('deployJava') {
dependsOn tasks.named('deployJreRoborio')
dependsOn tasks.named('deployMyRobotJavaRoborio')
dependsOn tasks.named('deployMyRobotCppLibrariesRoborio')
try {
dependsOn tasks.named('deployJreRoborio')
dependsOn tasks.named('deployMyRobotJavaRoborio')
dependsOn tasks.named('deployMyRobotCppLibrariesRoborio')
} catch (ignored) {
}
}
tasks.register('deployShared') {
dependsOn tasks.named('deployMyRobotCppLibrariesRoborio')
dependsOn tasks.named('deployMyRobotCppRoborio')
try {
dependsOn tasks.named('deployMyRobotCppLibrariesRoborio')
dependsOn tasks.named('deployMyRobotCppRoborio')
} catch (ignored) {
}
}
tasks.register('deployStatic') {
dependsOn tasks.named('deployMyRobotCppStaticRoborio')
try {
dependsOn tasks.named('deployMyRobotCppStaticRoborio')
} catch (ignored) {
}
}
mainClassName = 'Main'
@@ -148,7 +157,7 @@ model {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib project: ':cameraserver', library: 'cameraserver', linkage: 'shared'
if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(binary, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(binary, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}
@@ -177,7 +186,7 @@ model {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
lib project: ':cameraserver', library: 'cameraserver', linkage: 'static'
if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(binary, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(binary, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}

View File

@@ -44,6 +44,7 @@ public final class NetworkTableInstance implements AutoCloseable {
public static final int kNetModeClient = 0x02;
public static final int kNetModeStarting = 0x04;
public static final int kNetModeFailure = 0x08;
public static final int kNetModeLocal = 0x10;
/**
* The default port that network tables operates on.
@@ -675,6 +676,23 @@ public final class NetworkTableInstance implements AutoCloseable {
return NetworkTablesJNI.getNetworkMode(m_handle);
}
/**
* Starts local-only operation. Prevents calls to startServer or startClient
* from taking effect. Has no effect if startServer or startClient
* has already been called.
*/
public void startLocal() {
NetworkTablesJNI.startLocal(m_handle);
}
/**
* Stops local-only operation. startServer or startClient can be called after
* this call to start a server or client.
*/
public void stopLocal() {
NetworkTablesJNI.stopLocal(m_handle);
}
/**
* Starts a server using the networktables.ini as the persistent file,
* using the default listening address and port.

View File

@@ -139,6 +139,8 @@ public final class NetworkTablesJNI {
public static native void setNetworkIdentity(int inst, String name);
public static native int getNetworkMode(int inst);
public static native void startLocal(int inst);
public static native void stopLocal(int inst);
public static native void startServer(int inst, String persistFilename, String listenAddress, int port);
public static native void stopServer(int inst);
public static native void startClient(int inst);

View File

@@ -115,6 +115,16 @@ DispatcherBase::~DispatcherBase() { Stop(); }
unsigned int DispatcherBase::GetNetworkMode() const { return m_networkMode; }
void DispatcherBase::StartLocal() {
{
std::scoped_lock lock(m_user_mutex);
if (m_active) return;
m_active = true;
}
m_networkMode = NT_NET_MODE_LOCAL;
m_storage.SetDispatcher(this, false);
}
void DispatcherBase::StartServer(
const Twine& persist_filename,
std::unique_ptr<wpi::NetworkAcceptor> acceptor) {

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2015-2019 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. */
@@ -48,6 +48,7 @@ class DispatcherBase : public IDispatcher {
virtual ~DispatcherBase();
unsigned int GetNetworkMode() const;
void StartLocal();
void StartServer(const Twine& persist_filename,
std::unique_ptr<wpi::NetworkAcceptor> acceptor);
void StartClient();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2018-2019 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. */
@@ -1368,6 +1368,30 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_getNetworkMode
return nt::GetNetworkMode(inst);
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: startLocal
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_startLocal
(JNIEnv*, jclass, jint inst)
{
nt::StartLocal(inst);
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: stopLocal
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_networktables_NetworkTablesJNI_stopLocal
(JNIEnv*, jclass, jint inst)
{
nt::StopLocal(inst);
}
/*
* Class: edu_wpi_first_networktables_NetworkTablesJNI
* Method: startServer

View File

@@ -539,6 +539,10 @@ unsigned int NT_GetNetworkMode(NT_Inst inst) {
return nt::GetNetworkMode(inst);
}
void NT_StartLocal(NT_Inst inst) { nt::StartLocal(inst); }
void NT_StopLocal(NT_Inst inst) { nt::StopLocal(inst); }
void NT_StartServer(NT_Inst inst, const char* persist_filename,
const char* listen_address, unsigned int port) {
nt::StartServer(inst, persist_filename, listen_address, port);

View File

@@ -742,6 +742,20 @@ unsigned int GetNetworkMode(NT_Inst inst) {
return ii->dispatcher.GetNetworkMode();
}
void StartLocal(NT_Inst inst) {
auto ii = InstanceImpl::Get(Handle{inst}.GetTypedInst(Handle::kInstance));
if (!ii) return;
ii->dispatcher.StartLocal();
}
void StopLocal(NT_Inst inst) {
auto ii = InstanceImpl::Get(Handle{inst}.GetTypedInst(Handle::kInstance));
if (!ii) return;
ii->dispatcher.Stop();
}
void StartServer(StringRef persist_filename, const char* listen_address,
unsigned int port) {
auto ii = InstanceImpl::GetDefault();

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2017-2019 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. */
@@ -61,7 +61,8 @@ class NetworkTableInstance final {
kNetModeServer = NT_NET_MODE_SERVER,
kNetModeClient = NT_NET_MODE_CLIENT,
kNetModeStarting = NT_NET_MODE_STARTING,
kNetModeFailure = NT_NET_MODE_FAILURE
kNetModeFailure = NT_NET_MODE_FAILURE,
kNetModeLocal = NT_NET_MODE_LOCAL
};
/**
@@ -298,6 +299,19 @@ class NetworkTableInstance final {
*/
unsigned int GetNetworkMode() const;
/**
* Starts local-only operation. Prevents calls to StartServer or StartClient
* from taking effect. Has no effect if StartServer or StartClient
* has already been called.
*/
void StartLocal();
/**
* Stops local-only operation. StartServer or StartClient can be called after
* this call to start a server or client.
*/
void StopLocal();
/**
* Starts a server using the specified filename, listening address, and port.
*

View File

@@ -81,6 +81,10 @@ inline unsigned int NetworkTableInstance::GetNetworkMode() const {
return ::nt::GetNetworkMode(m_handle);
}
inline void NetworkTableInstance::StartLocal() { ::nt::StartLocal(m_handle); }
inline void NetworkTableInstance::StopLocal() { ::nt::StopLocal(m_handle); }
inline void NetworkTableInstance::StartServer(const Twine& persist_filename,
const char* listen_address,
unsigned int port) {

View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
/* Copyright (c) 2015-2019 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. */
@@ -95,6 +95,7 @@ enum NT_NetworkMode {
NT_NET_MODE_CLIENT = 0x02, /* running in client mode */
NT_NET_MODE_STARTING = 0x04, /* flag for starting (either client or server) */
NT_NET_MODE_FAILURE = 0x08, /* flag for failure (either client or server) */
NT_NET_MODE_LOCAL = 0x10, /* running in local-only mode */
};
/*
@@ -1037,6 +1038,19 @@ void NT_SetNetworkIdentity(NT_Inst inst, const char* name, size_t name_len);
*/
unsigned int NT_GetNetworkMode(NT_Inst inst);
/**
* Starts local-only operation. Prevents calls to NT_StartServer or
* NT_StartClient from taking effect. Has no effect if NT_StartServer or
* NT_StartClient has already been called.
*/
void NT_StartLocal(NT_Inst inst);
/**
* Stops local-only operation. NT_StartServer or NT_StartClient can be called
* after this call to start a server or client.
*/
void NT_StopLocal(NT_Inst inst);
/**
* Starts a server using the specified filename, listening address, and port.
*

View File

@@ -1130,6 +1130,19 @@ unsigned int GetNetworkMode();
*/
unsigned int GetNetworkMode(NT_Inst inst);
/**
* Starts local-only operation. Prevents calls to StartServer or StartClient
* from taking effect. Has no effect if StartServer or StartClient
* has already been called.
*/
void StartLocal(NT_Inst inst);
/**
* Stops local-only operation. StartServer or StartClient can be called after
* this call to start a server or client.
*/
void StopLocal(NT_Inst inst);
/**
* Starts a server using the specified filename, listening address, and port.
*

View File

@@ -8,9 +8,9 @@ nativeUtils {
wpi {
configureDependencies {
wpiVersion = "-1"
niLibVersion = "2020.7.1"
niLibVersion = "2020.10.1"
opencvVersion = "3.4.7-2"
googleTestVersion = "1.9.0-3-437e100"
googleTestVersion = "1.9.0-4-437e100-1"
imguiVersion = "1.72b-2"
}
}

View File

@@ -0,0 +1,21 @@
model {
tasks {
def ts = $.testSuites
project.tasks.register('testDesktopCpp') { testTask->
def systemArch = getCurrentArch()
def found = false
ts.each {
if (it in GoogleTestTestSuiteSpec && it.name == "${nativeName}Test") {
it.binaries.each {
if (found) return
def arch = it.targetPlatform.name
if (arch == systemArch && it.buildType.name == 'debug') {
testTask.dependsOn it.tasks.run
found = true
}
}
}
}
}
}
}

View File

@@ -70,6 +70,7 @@ task checkCommands(type: Task) {
assert it.tags != null
assert it.foldername != null
assert it.replacename != null
assert it.commandversion != null
if (project.isCppCommands) {
assert it.headers != null
assert !it.headers.isEmpty()

View File

@@ -0,0 +1,3 @@
tasks.register('testDesktopJava') {
dependsOn test
}

View File

@@ -141,6 +141,9 @@ model {
}
}
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
tasks.withType(RunTestExecutable) {
args "--gtest_output=xml:test_detail.xml"
outputs.dir outputDir

View File

@@ -200,7 +200,7 @@ model {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
}
if (nativeName == 'hal' && it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}
@@ -235,7 +235,7 @@ model {
if (!project.hasProperty('noWpiutil')) {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
if (nativeName == 'hal' && it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}
@@ -275,6 +275,9 @@ model {
}
}
apply from: "${rootDir}/shared/cppDesktopTestTask.gradle"
apply from: "${rootDir}/shared/javaDesktopTestTask.gradle"
ext.getJniSpecClass = {
return JniNativeLibrarySpec
}

View File

@@ -57,7 +57,7 @@ if (!project.hasProperty('onlylinuxathena')) {
}
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
} else {
it.buildable = false

View File

@@ -49,7 +49,7 @@ model {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib library: pluginName, linkage: 'shared'
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}

View File

@@ -23,8 +23,14 @@
using namespace halsimgui;
static constexpr int kDefaultColumns = 10;
static std::vector<int> numColumns;
namespace {
struct LEDDisplaySettings {
int numColumns = 10;
LEDConfig config;
};
} // namespace
static std::vector<LEDDisplaySettings> displaySettings;
// read/write columns setting to ini file
static void* AddressableLEDReadOpen(ImGuiContext* ctx,
@@ -33,15 +39,15 @@ static void* AddressableLEDReadOpen(ImGuiContext* ctx,
int num;
if (wpi::StringRef{name}.getAsInteger(10, num)) return nullptr;
if (num < 0) return nullptr;
if (num >= static_cast<int>(numColumns.size()))
numColumns.resize(num + 1, kDefaultColumns);
return &numColumns[num];
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) {
int* cols = static_cast<int*>(entry);
auto* settings = static_cast<LEDDisplaySettings*>(entry);
// format: columns=#
wpi::StringRef line{lineStr};
auto [name, value] = line.split('=');
@@ -50,24 +56,41 @@ static void AddressableLEDReadLine(ImGuiContext* ctx,
if (name == "columns") {
int num;
if (value.getAsInteger(10, num)) return;
*cols = num;
settings->numColumns = num;
} else if (name == "serpentine") {
int num;
if (value.getAsInteger(10, num)) return;
settings->config.serpentine = num != 0;
} else if (name == "order") {
int num;
if (value.getAsInteger(10, num)) return;
settings->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);
}
}
static void AddressableLEDWriteAll(ImGuiContext* ctx,
ImGuiSettingsHandler* handler,
ImGuiTextBuffer* out_buf) {
for (size_t i = 0; i < numColumns.size(); ++i) {
out_buf->appendf("[AddressableLED][%d]\ncolumns=%d\n\n",
static_cast<int>(i), numColumns[i]);
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));
}
}
static void DisplayAddressableLEDs() {
bool hasAny = false;
static const int numLED = HAL_GetNumAddressableLEDs();
if (numLED > static_cast<int>(numColumns.size()))
numColumns.resize(numLED, kDefaultColumns);
if (numLED > static_cast<int>(displaySettings.size()))
displaySettings.resize(numLED);
for (int i = 0; i < numLED; ++i) {
if (!HALSIM_GetAddressableLEDInitialized(i)) continue;
@@ -82,8 +105,22 @@ static void DisplayAddressableLEDs() {
ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
ImGui::LabelText("Length", "%d", length);
ImGui::LabelText("Running", "%s", running ? "Yes" : "No");
ImGui::InputInt("Columns", &numColumns[i]);
if (numColumns[i] < 1) numColumns[i] = 1;
ImGui::InputInt("Columns", &displaySettings[i].numColumns);
{
static const char* options[] = {"Row Major", "Column Major"};
int val = displaySettings[i].config.order;
if (ImGui::Combo("Order", &val, options, 2))
displaySettings[i].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;
if (ImGui::Combo("Start", &val, options, 4))
displaySettings[i].config.start = static_cast<LEDConfig::Start>(val);
}
ImGui::Checkbox("Serpentine", &displaySettings[i].config.serpentine);
if (displaySettings[i].numColumns < 1) displaySettings[i].numColumns = 1;
ImGui::PopItemWidth();
// show as LED indicators
@@ -100,7 +137,8 @@ static void DisplayAddressableLEDs() {
}
}
DrawLEDs(values, length, numColumns[i], colors);
DrawLEDs(values, length, displaySettings[i].numColumns, colors, 0, 0,
displaySettings[i].config);
}
if (!hasAny) ImGui::Text("No addressable LEDs");
}

View File

@@ -24,9 +24,18 @@ static void DisplayAnalogInputs() {
bool hasInputs = false;
static int numAnalog = HAL_GetNumAnalogInputs();
static int numAccum = HAL_GetNumAccumulators();
bool first = true;
for (int i = 0; i < numAnalog; ++i) {
if (HALSIM_GetAnalogInInitialized(i)) {
hasInputs = true;
if (!first) {
ImGui::Spacing();
ImGui::Spacing();
} else {
first = false;
}
char name[32];
std::snprintf(name, sizeof(name), "In[%d]", i);
if (i < numAccum && HALSIM_GetAnalogGyroInitialized(i)) {

View File

@@ -10,30 +10,87 @@
namespace halsimgui {
void DrawLEDs(const int* values, int numValues, int cols, const ImU32* colors,
float size, float spacing) {
if (numValues == 0) return;
float size, float spacing, const LEDConfig& config) {
if (numValues == 0 || cols < 1) return;
if (size == 0) size = ImGui::GetFontSize() / 2.0;
if (spacing == 0) spacing = ImGui::GetFontSize() / 3.0;
int rows = (numValues + cols - 1) / cols;
float inc = size + spacing;
ImDrawList* drawList = ImGui::GetWindowDrawList();
const ImVec2 p = ImGui::GetCursorScreenPos();
float x = p.x + size / 2, y = p.y + size / 2;
int rows = 1;
for (int i = 0; i < numValues; ++i) {
if (i >= (rows * cols)) {
++rows;
x = p.x + size / 2;
y += size + spacing;
}
if (values[i] > 0)
drawList->AddRectFilled(ImVec2(x, y), ImVec2(x + size, y + size),
colors[values[i] - 1]);
else if (values[i] < 0)
drawList->AddRect(ImVec2(x, y), ImVec2(x + size, y + size),
colors[-values[i] - 1], 0.0f, 0, 1.0);
x += size + spacing;
float ystart, yinc;
if (config.start & 1) {
// lower
ystart = p.y + size / 2 + inc * (rows - 1);
yinc = -inc;
} else {
// upper
ystart = p.y + size / 2;
yinc = inc;
}
ImGui::Dummy(ImVec2((size + spacing) * cols, (size + spacing) * rows));
float xstart, xinc;
if (config.start & 2) {
// right
xstart = p.x + size / 2 + inc * (cols - 1);
xinc = -inc;
} else {
// left
xstart = p.x + size / 2;
xinc = inc;
}
float x = xstart, y = ystart;
if (config.order == LEDConfig::RowMajor) {
// row major
int row = 1;
for (int i = 0; i < numValues; ++i) {
if (i >= (row * cols)) {
++row;
if (config.serpentine) {
x -= xinc;
xinc = -xinc;
} else {
x = xstart;
}
y += yinc;
}
if (values[i] > 0)
drawList->AddRectFilled(ImVec2(x, y), ImVec2(x + size, y + size),
colors[values[i] - 1]);
else if (values[i] < 0)
drawList->AddRect(ImVec2(x, y), ImVec2(x + size, y + size),
colors[-values[i] - 1], 0.0f, 0, 1.0);
x += xinc;
}
} else {
// column major
int col = 1;
for (int i = 0; i < numValues; ++i) {
if (i >= (col * rows)) {
++col;
if (config.serpentine) {
y -= yinc;
yinc = -yinc;
} else {
y = ystart;
}
x += xinc;
}
if (values[i] > 0)
drawList->AddRectFilled(ImVec2(x, y), ImVec2(x + size, y + size),
colors[values[i] - 1]);
else if (values[i] < 0)
drawList->AddRect(ImVec2(x, y), ImVec2(x + size, y + size),
colors[-values[i] - 1], 0.0f, 0, 1.0);
y += yinc;
}
}
ImGui::Dummy(ImVec2(inc * cols, inc * rows));
}
} // 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. */
@@ -301,6 +301,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);

View File

@@ -11,6 +11,33 @@
namespace halsimgui {
/**
* DrawLEDs() configuration for 2D arrays.
*/
struct LEDConfig {
/**
* Whether the major order is serpentined (e.g. the first row goes left to
* right, the second row right to left, the third row left to right, and so
* on).
*/
bool serpentine = false;
/**
* The input array order (row-major or column-major).
*/
enum Order { RowMajor = 0, ColumnMajor } order = RowMajor;
/**
* The starting location of the array (0 location).
*/
enum Start {
UpperLeft = 0,
LowerLeft,
UpperRight,
LowerRight
} start = UpperLeft;
};
/**
* Draw a 2D array of LEDs.
*
@@ -27,8 +54,10 @@ namespace halsimgui {
* if 0, defaults to 1/2 of font size
* @param spacing spacing between each LED (both horizontal and vertical);
* if 0, defaults to 1/3 of font size
* @param config 2D array configuration
*/
void DrawLEDs(const int* values, int numValues, int cols, const ImU32* colors,
float size = 0.0f, float spacing = 0.0f);
float size = 0.0f, float spacing = 0.0f,
const LEDConfig& config = LEDConfig{});
} // namespace halsimgui

View File

@@ -116,7 +116,7 @@ if (!project.hasProperty('onlylinuxathena')) {
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}
@@ -131,7 +131,7 @@ if (!project.hasProperty('onlylinuxathena')) {
lib project: ':wpilibc', library: 'wpilibc', linkage: 'shared'
lib library: nativeName, linkage: 'shared'
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}

View File

@@ -1,17 +1,19 @@
# WPILIB TEST SCRIPTS
# WPILib Test Scripts
## Overview
These test scripts are designed to allow the user of the WPILib test framework to quickly and easily deploy and run their tests on the WPI roboRIO.
In order for the automated test system to work there is a driverstation onboard the roboRIO that handles a queue of users waiting to use the driver station. All of the interaction with this queue is handled internally by test scripts contained within this folder.
If you deploy code to the test stand using the Eclipse plugins, you _must_ remove the build artifacts in `/home/lvuser`, or you will break tests.
If you deploy code to the test stand using GradleRIO, you _must_ remove the build artifacts in `/home/lvuser`, or you will break the test stand.
## roboRIO Setup
The roboRIO on the test bench must be updated everytime NI releases a new image.
The roboRIO on the test bench must be updated every time NI releases a new image.
1. [Use the roboRIO Imaging Tool to format the roboRIO with the lastest image.](https://wpilib.screenstepslive.com/s/4485/m/13503/l/144984-imaging-your-roborio)
2. [Install Java on the roboRIO.](https://wpilib.screenstepslive.com/s/4485/m/13503/l/599747-installing-java-8-on-the-roborio-using-the-frc-roborio-java-installer-java-only)
3. SFTP the [teststand, netconsole, and libstdc++ ipk files](https://users.wpi.edu/~phplenefisch/ipk/) on to the roboRIO.
4. ssh on to the roboRIO as the admin user (ex: `ssh admin@roboRIO-190-FRC.local`)
5. Use opkg to install the ipk files (ex: `opkg install teststand_1.2-1_armv7a-vfp.ipk`)
6. Reboot the roboRIO
1. [Use the roboRIO Imaging Tool to format the roboRIO with the lastest image.](https://frcdocs.wpi.edu/en/latest/docs/getting-started/getting-started-frc-control-system/imaging-your-roborio.html)
2. Set a static ip on the roboRIO web dashboard to `10.1.90.2`
2. Install Java on the roboRIO
1. [Download the JRE from Maven.](https://frcmaven.wpi.edu/artifactory/list/release/edu/wpi/first/jdk/)
2. Transfer the JRE ipk to the roboRIO with scp: `scp <local path> admin@roboRIO-190-FRC.local:/tmp/frcjre.ipk`
3. Install the JRE: `opkg install /tmp/frcjre.ipk`
4. Remove the ipk file: `rm /tmp/frcjre.ipk`
3. Reboot the roboRIO

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
#*----------------------------------------------------------------------------*#
#* Copyright (c) FIRST 2014. All Rights Reserved. *#
#* Copyright (c) 2014-2019 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. *#
#* the project. *#
#*----------------------------------------------------------------------------*#
# If this is changed, update the .gitignore
@@ -31,7 +31,7 @@ DEFAULT_DESTINATION_CPP_TEST_RESULTS=${DEFAULT_DESTINATION_TEST_RESULTS_DIR}/${C
DEFAULT_JAVA_TEST_NAME=FRCUserProgram.jar
DEFAULT_JAVA_TEST_ARGS=""
DEFAULT_LOCAL_JAVA_TEST_FILE=../build/integrationTestFiles/java/wpilibjIntegrationTests.jar
DEFAULT_LOCAL_JAVA_TEST_FILE=../build/integrationTestFiles/java/wpilibjIntegrationTests-all.jar
JAVA_REPORT=javareport.xml
DEFAULT_LIBRARY_NATIVE_FILES=../build/integrationTestFiles/libs

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
#*----------------------------------------------------------------------------*#
#* Copyright (c) FIRST 2014. All Rights Reserved. *#
#* Copyright (c) 2014-2019 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. *#
#* the project. *#
#*----------------------------------------------------------------------------*#
# Configurable variables
@@ -19,7 +19,7 @@ DEFAULT_DESTINATION_RUN_TEST_SCRIPT=${DEFAULT_DESTINATION_DIR}/${DEFAULT_LOCAL_R
usage="$(basename "$0") [-h] (java|cpp) [-A] [arg] [arg]...
A script designed to run the integration tests.
This script should only be run on the roborio.
This script should only be run on the computer connected to the roboRIO.
Where:
-h Show this help text.
-A Disable language recomended arguments.
@@ -30,20 +30,26 @@ Where:
LANGUAGE=none
LOCAL_TEST_FILE=none
DESTINATION_TEST_FILE=none
LIBRARY_FILES=none
TEST_RUN_ARGS=""
DESTINATION_TEST_RESULTS=none
LOCAL_TEST_RESULTS=none
# Begin searching for options from the third paramater on
# Begin searching for options from the second paramater on
PARAM_ARGS=${@:2}
if [[ "$1" = java ]]; then
LANGUAGE=$1
LOCAL_TEST_FILE=$DEFAULT_LOCAL_JAVA_TEST_FILE
DESTINATION_TEST_FILE=$DEFAULT_DESTINATION_JAVA_TEST_FILE
DESTINATION_TEST_RESULTS=$DEFAULT_DESTINATION_JAVA_TEST_RESULTS
LOCAL_TEST_RESULTS=$DEFAULT_LOCAL_JAVA_TEST_RESULT
elif [[ "$1" = cpp ]]; then
LANGUAGE=$1
LOCAL_TEST_FILE=$DEFAULT_LOCAL_CPP_TEST_FILE
DESTINATION_TEST_FILE=$DEFAULT_DESTINATION_CPP_TEST_FILE
DESTINATION_TEST_RESULTS=$DEFAULT_DESTINATION_CPP_TEST_RESULTS
LOCAL_TEST_RESULTS=$DEFAULT_LOCAL_CPP_TEST_RESULT
elif [[ "$1" = "-h" ]]; then
printf "Usage:\n"
echo "$usage"
@@ -65,25 +71,14 @@ TEST_RUN_ARGS="${@:2}"
shopt -s huponexit
SCP_TEST_SCRIPT="scp config.sh ${DEFAULT_LOCAL_RUN_TEST_SCRIPT} ${ROBOT_ADDRESS}:/${DEFAULT_DESTINATION_DIR}"
SSH_CHMOD_AND_MAKE_TEMP_TEST_DIR="ssh -t ${ROBOT_ADDRESS} \"chmod a+x ${DEFAULT_DESTINATION_RUN_TEST_SCRIPT}; mkdir ${DEFAULT_TEST_SCP_DIR}; touch ${DESTINATION_TEST_FILE}\""
SCP_TEST_PROGRAM="scp ${LOCAL_TEST_FILE} ${ROBOT_ADDRESS}:${DESTINATION_TEST_FILE}"
SSH_RUN_TESTS="ssh -t ${ROBOT_ADDRESS} ${DEFAULT_DESTINATION_RUN_TEST_SCRIPT} ${LANGUAGE} $(whoami) -d ${DEFAULT_TEST_SCP_DIR} ${TEST_RUN_ARGS}"
SCP_NATIVE_LIBRARIES="scp ${DEFAULT_LIBRARY_NATIVE_FILES}/* ${ROBOT_ADDRESS}:${DEFAULT_LIBRARY_NATIVE_DESTINATION}"
CONFIG_NATIVE_LIBRARIES="ssh -t ${ADMIN_ROBOT_ADDRESS} ldconfig"
# Fail if any command fails
set -e
if [ $(which sshpass) ]; then
sshpass -p "" ${SCP_NATIVE_LIBRARIES}
sshpass -p "" ${CONFIG_NATIVE_LIBRARIES}
sshpass -p "" ${SCP_TEST_SCRIPT}
sshpass -p "" ${SSH_CHMOD_AND_MAKE_TEMP_TEST_DIR}
sshpass -p "" ${SCP_TEST_PROGRAM}
sshpass -p "" ${SSH_RUN_TESTS}
else
eval ${SCP_NATIVE_LIBRARIES}
eval ${CONFIG_NATIVE_LIBRARIES}
eval ${SCP_TEST_SCRIPT}
eval ${SSH_CHMOD_AND_MAKE_TEMP_TEST_DIR}
eval ${SCP_TEST_PROGRAM}
eval ${SSH_RUN_TESTS}
fi
ssh ${ROBOT_ADDRESS} "rm -R ${DEFAULT_DESTINATION_TEST_RESULTS_DIR}; mkdir ${DEFAULT_DESTINATION_TEST_RESULTS_DIR}"
scp ${DEFAULT_LIBRARY_NATIVE_FILES}/* ${ROBOT_ADDRESS}:${DEFAULT_LIBRARY_NATIVE_DESTINATION}
ssh ${ADMIN_ROBOT_ADDRESS} ldconfig
scp config.sh ${DEFAULT_LOCAL_RUN_TEST_SCRIPT} ${ROBOT_ADDRESS}:/${DEFAULT_DESTINATION_DIR}
ssh ${ROBOT_ADDRESS} "chmod a+x ${DEFAULT_DESTINATION_RUN_TEST_SCRIPT}; mkdir ${DEFAULT_TEST_SCP_DIR}; touch ${DESTINATION_TEST_FILE}"
scp ${LOCAL_TEST_FILE} ${ROBOT_ADDRESS}:${DESTINATION_TEST_FILE}
ssh ${ROBOT_ADDRESS} ${DEFAULT_DESTINATION_RUN_TEST_SCRIPT} ${LANGUAGE} -d ${DEFAULT_TEST_SCP_DIR} ${TEST_RUN_ARGS}
mkdir ${DEFAULT_LOCAL_TEST_RESULTS_DIR}; scp ${ROBOT_ADDRESS}:${DESTINATION_TEST_RESULTS} ${LOCAL_TEST_RESULTS}

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env bash
#*----------------------------------------------------------------------------*#
#* Copyright (c) FIRST 2014. 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. *#
#*----------------------------------------------------------------------------*#
# Configurable variables
source config.sh
(
# Wait for lock
printf "Getting exclusive lock for RIO execution...\n"
flock -x 200 || exit 1
# Ensure the teststand is dead
SSH_STOP_TESTSTAND="ssh -t ${ROBOT_ADDRESS} sh -c '/etc/init.d/teststand stop; sleep 1'"
if [ $(which sshpass) ]; then
sshpass -p "" ${SSH_STOP_TESTSTAND}
else
eval ${SSH_STOP_TESTSTAND}
fi
# If there are already test results in the repository then remove them
if [[ -e ${DEFAULT_LOCAL_TEST_RESULTS_DIR} ]]; then
rm -R ${DEFAULT_LOCAL_TEST_RESULTS_DIR}
fi
# Make the directory where the tests should live
mkdir ${DEFAULT_LOCAL_TEST_RESULTS_DIR} 2>/dev/null
# Remove the preivous test results from the the robot
SSH_REMOVE_OLD_TEST_RESULTS="ssh -t ${ROBOT_ADDRESS} rm -R ${DEFAULT_DESTINATION_TEST_RESULTS_DIR}; mkdir ${DEFAULT_DESTINATION_TEST_RESULTS_DIR}"
if [ $(which sshpass) ]; then
sshpass -p "" ${SSH_REMOVE_OLD_TEST_RESULTS}
else
eval ${SSH_REMOVE_OLD_TEST_RESULTS}
fi
printf "Running cpp test\n"
# Run the C++ Tests
./deploy-and-run-test-on-robot.sh cpp -A "--gtest_output=xml:${DEFAULT_DESTINATION_CPP_TEST_RESULTS}"
# Retrive the C++ Test Results
SCP_GET_CPP_TEST_RESULT="scp ${ROBOT_ADDRESS}:${DEFAULT_DESTINATION_CPP_TEST_RESULTS} ${DEFAULT_LOCAL_CPP_TEST_RESULT}"
if [ $(which sshpass) ]; then
sshpass -p "" ${SCP_GET_CPP_TEST_RESULT}
else
eval ${SCP_GET_CPP_TEST_RESULT}
fi
sleep 10
# Run the Java Tests
./deploy-and-run-test-on-robot.sh java
# Retrive the Java Test Results
SCP_GET_JAVA_TEST_RESULT="scp ${ROBOT_ADDRESS}:${DEFAULT_DESTINATION_JAVA_TEST_RESULTS} ${DEFAULT_LOCAL_JAVA_TEST_RESULT}"
if [ $(which sshpass) ]; then
sshpass -p "" ${SCP_GET_JAVA_TEST_RESULT}
else
eval ${SCP_GET_JAVA_TEST_RESULT}
fi
# Make sure that we got test results back.
if [ ! -e ${DEFAULT_LOCAL_CPP_TEST_RESULT} ]; then
echo "There are no results from the C++ tests; they must have failed."
exit 100
fi
if [ ! -e ${DEFAULT_LOCAL_JAVA_TEST_RESULT} ]; then
echo "There are no results from the Java tests; they must have failed."
exit 101
fi
# The mutex is released when this program exits
) 200>/var/lock/jenkins.rio.exclusivelock

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env bash
#*----------------------------------------------------------------------------*#
#* Copyright (c) FIRST 2014. All Rights Reserved. *#
#* Copyright (c) 2014-2019 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. *#
#* the project. *#
#*----------------------------------------------------------------------------*#
# This file is intended to be run in the DEFAULT_TEST_DIR on the roboRIO.
@@ -17,12 +17,11 @@ source config.sh
DEFAULT_TEST_DIR=${DEFAULT_DESTINATION_DIR}
DEFAULT_PATH_TO_JRE=/usr/local/frc/JRE/bin/java
usage="$(basename "$0") [-h] (java|cpp) name [-d test_dir] [-A] [arg] [arg]...
usage="$(basename "$0") [-h] (java|cpp) [-d test_dir] [-A] [arg] [arg]...
A script designed to run the integration tests.
This script should only be run on the roborio.
Where:
-h Show this help text
name The name of the user trying to run the tests (used for driver station)
-d The directory where the tests have been placed.
This is done to prevent overwriting an already running program.
This scrip will automatically move the test into the ${DEFAULT_TEST_DIR}
@@ -42,12 +41,11 @@ fi
LANGUAGE=none
TEST_FILE=none
NAME=$2
TEST_DIR="$DEFAULT_TEST_DIR"
# Begin searching for options from the third paramater on
PARAM_ARGS=${@:3}
# Begin searching for options from the second paramater on
PARAM_ARGS=${@:2}
# Where the test arguments start
TEST_RUN_ARGS=${@:3}
TEST_RUN_ARGS=${@:2}
RUN_WITH_DEFAULT_ARGS=true
DEFAULT_ARGS=""
@@ -70,7 +68,7 @@ else
exit 1
fi
PARAM_COUNTER=2
PARAM_COUNTER=1
printf "Param Args ${PARAM_ARGS}\n"
# Check for optional paramaters

View File

@@ -64,7 +64,7 @@ model {
lib project: ':cscore', library: 'cscore', linkage: 'shared'
}
if ((it instanceof NativeExecutableBinarySpec || it instanceof GoogleTestTestSuiteBinarySpec) && it.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'ni_runtime_shared')
nativeUtils.useRequiredLibrary(it, 'netcomm_shared', 'chipobject_shared', 'visa_shared', 'ni_runtime_shared')
}
}
}

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<>();
@@ -89,8 +85,22 @@ public final class CommandScheduler implements Sendable {
CommandScheduler() {
HAL.report(tResourceType.kResourceType_Command, tInstances.kCommand_Scheduler);
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

@@ -19,20 +19,32 @@ public abstract class PIDSubsystem extends SubsystemBase {
protected final PIDController m_controller;
protected boolean m_enabled;
private double m_setpoint;
/**
* Creates a new PIDSubsystem.
*
* @param controller the PIDController to use
* @param initialPosition the initial setpoint of the subsystem
*/
public PIDSubsystem(PIDController controller, double initialPosition) {
setSetpoint(initialPosition);
m_controller = requireNonNullParam(controller, "controller", "PIDSubsystem");
}
/**
* Creates a new PIDSubsystem. Initial setpoint is zero.
*
* @param controller the PIDController to use
*/
public PIDSubsystem(PIDController controller) {
requireNonNullParam(controller, "controller", "PIDSubsystem");
m_controller = controller;
this(controller, 0);
}
@Override
public void periodic() {
if (m_enabled) {
useOutput(m_controller.calculate(getMeasurement(), getSetpoint()));
useOutput(m_controller.calculate(getMeasurement(), m_setpoint), m_setpoint);
}
}
@@ -40,26 +52,29 @@ public abstract class PIDSubsystem extends SubsystemBase {
return m_controller;
}
/**
* Sets the setpoint for the subsystem.
*
* @param setpoint the setpoint for the subsystem
*/
public void setSetpoint(double setpoint) {
m_setpoint = setpoint;
}
/**
* Uses the output from the PIDController.
*
* @param output the output of the PIDController
* @param setpoint the setpoint of the PIDController (for feedforward)
*/
public abstract void useOutput(double output);
/**
* Returns the reference (setpoint) used by the PIDController.
*
* @return the reference (setpoint) to be used by the controller
*/
public abstract double getSetpoint();
protected abstract void useOutput(double output, double setpoint);
/**
* Returns the measurement of the process variable used by the PIDController.
*
* @return the measurement of the process variable
*/
public abstract double getMeasurement();
protected abstract double getMeasurement();
/**
* Enables the PID control. Resets the controller.
@@ -74,6 +89,15 @@ public abstract class PIDSubsystem extends SubsystemBase {
*/
public void disable() {
m_enabled = false;
useOutput(0);
useOutput(0, 0);
}
/**
* Returns whether the controller is enabled.
*
* @return Whether the controller is enabled.
*/
public boolean isEnabled() {
return m_enabled;
}
}

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. */
@@ -113,7 +113,7 @@ public class ProfiledPIDCommand extends CommandBase {
@Override
public void initialize() {
m_controller.reset();
m_controller.reset(m_measurement.getAsDouble());
}
@Override

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. */
@@ -8,6 +8,7 @@
package edu.wpi.first.wpilibj2.command;
import edu.wpi.first.wpilibj.controller.ProfiledPIDController;
import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
import static edu.wpi.first.wpilibj.trajectory.TrapezoidProfile.State;
import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
@@ -20,20 +21,33 @@ public abstract class ProfiledPIDSubsystem extends SubsystemBase {
protected final ProfiledPIDController m_controller;
protected boolean m_enabled;
private TrapezoidProfile.State m_goal;
/**
* Creates a new ProfiledPIDSubsystem.
*
* @param controller the ProfiledPIDController to use
* @param initialPosition the initial goal position of the controller
*/
public ProfiledPIDSubsystem(ProfiledPIDController controller,
double initialPosition) {
m_controller = requireNonNullParam(controller, "controller", "ProfiledPIDSubsystem");
setGoal(initialPosition);
}
/**
* Creates a new ProfiledPIDSubsystem. Initial goal position is zero.
*
* @param controller the ProfiledPIDController to use
*/
public ProfiledPIDSubsystem(ProfiledPIDController controller) {
requireNonNullParam(controller, "controller", "ProfiledPIDSubsystem");
m_controller = controller;
this(controller, 0);
}
@Override
public void periodic() {
if (m_enabled) {
useOutput(m_controller.calculate(getMeasurement(), getGoal()), m_controller.getSetpoint());
useOutput(m_controller.calculate(getMeasurement(), m_goal), m_controller.getSetpoint());
}
}
@@ -41,34 +55,45 @@ public abstract class ProfiledPIDSubsystem extends SubsystemBase {
return m_controller;
}
/**
* Sets the goal state for the subsystem.
*
* @param goal The goal state for the subsystem's motion profile.
*/
public void setGoal(TrapezoidProfile.State goal) {
m_goal = goal;
}
/**
* Sets the goal state for the subsystem. Goal velocity assumed to be zero.
*
* @param goal The goal position for the subsystem's motion profile.
*/
public void setGoal(double goal) {
setGoal(new TrapezoidProfile.State(goal, 0));
}
/**
* Uses the output from the ProfiledPIDController.
*
* @param output the output of the ProfiledPIDController
* @param setpoint the setpoint state of the ProfiledPIDController, for feedforward
*/
public abstract void useOutput(double output, State setpoint);
/**
* Returns the goal used by the ProfiledPIDController.
*
* @return the goal to be used by the controller
*/
public abstract State getGoal();
protected abstract void useOutput(double output, State setpoint);
/**
* Returns the measurement of the process variable used by the ProfiledPIDController.
*
* @return the measurement of the process variable
*/
public abstract double getMeasurement();
protected abstract double getMeasurement();
/**
* Enables the PID control. Resets the controller.
*/
public void enable() {
m_enabled = true;
m_controller.reset();
m_controller.reset(getMeasurement());
}
/**
@@ -78,4 +103,13 @@ public abstract class ProfiledPIDSubsystem extends SubsystemBase {
m_enabled = false;
useOutput(0, new State());
}
/**
* Returns whether the controller is enabled.
*
* @return Whether the controller is enabled.
*/
public boolean isEnabled() {
return m_enabled;
}
}

View File

@@ -53,8 +53,8 @@ public class RamseteCommand extends CommandBase {
/**
* Constructs a new RamseteCommand that, when executed, will follow the provided trajectory.
* PID control and feedforward are handled internally, and outputs are scaled -1 to 1 for easy
* consumption by speed controllers.
* PID control and feedforward are handled internally, and outputs are scaled -12 to 12
* representing units of volts.
*
* <p>Note: The controller will *not* set the outputVolts to zero upon completion of the path -
* this

View File

@@ -76,7 +76,6 @@ public abstract class SubsystemBase implements Subsystem, Sendable {
*/
public void addChild(String name, Sendable child) {
SendableRegistry.addLW(child, getSubsystem(), name);
SendableRegistry.addChild(this, child);
}
@Override

View File

@@ -9,6 +9,8 @@ package edu.wpi.first.wpilibj2.command;
import edu.wpi.first.wpilibj.trajectory.TrapezoidProfile;
import static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam;
/**
* A subsystem that generates and runs trapezoidal motion profiles automatically. The user
* specifies how to use the current state of the motion profile by overriding the `useState` method.
@@ -18,50 +20,88 @@ public abstract class TrapezoidProfileSubsystem extends SubsystemBase {
private final TrapezoidProfile.Constraints m_constraints;
private TrapezoidProfile.State m_state;
private TrapezoidProfile.State m_goal;
private boolean m_enabled = true;
/**
* Creates a new TrapezoidProfileSubsystem.
*
* @param constraints The constraints (maximum velocity and acceleration) for the profiles.
* @param initialPosition The initial position of the controller mechanism when the subsystem
* is constructed.
*/
public TrapezoidProfileSubsystem(TrapezoidProfile.Constraints constraints,
double initialPosition) {
m_constraints = constraints;
m_state = new TrapezoidProfile.State(initialPosition, 0);
m_period = 0.02;
}
/**
* Creates a new TrapezoidProfileSubsystem.
*
* @param constraints The constraints (maximum velocity and acceleration) for the profiles.
* @param initialPosition The initial position of the controller mechanism when the subsystem
* @param initialPosition The initial position of the controlled mechanism when the subsystem
* is constructed.
* @param period The period of the main robot loop, in seconds.
*/
public TrapezoidProfileSubsystem(TrapezoidProfile.Constraints constraints,
double initialPosition,
double period) {
m_constraints = constraints;
m_constraints = requireNonNullParam(constraints, "constraints", "TrapezoidProfileSubsystem");
m_state = new TrapezoidProfile.State(initialPosition, 0);
setGoal(initialPosition);
m_period = period;
}
/**
* Creates a new TrapezoidProfileSubsystem.
*
* @param constraints The constraints (maximum velocity and acceleration) for the profiles.
* @param initialPosition The initial position of the controlled mechanism when the subsystem
* is constructed.
*/
public TrapezoidProfileSubsystem(TrapezoidProfile.Constraints constraints,
double initialPosition) {
this(constraints, initialPosition, 0.02);
}
/**
* Creates a new TrapezoidProfileSubsystem.
*
* @param constraints The constraints (maximum velocity and acceleration) for the profiles.
*/
public TrapezoidProfileSubsystem(TrapezoidProfile.Constraints constraints) {
this(constraints, 0, 0.02);
}
@Override
public void periodic() {
var profile = new TrapezoidProfile(m_constraints, getGoal(), m_state);
var profile = new TrapezoidProfile(m_constraints, m_goal, m_state);
m_state = profile.calculate(m_period);
useState(m_state);
if (m_enabled) {
useState(m_state);
}
}
/**
* Users should override this to return the goal state for the subsystem's motion profile.
* Sets the goal state for the subsystem.
*
* @return The goal state for the subsystem's motion profile.
* @param goal The goal state for the subsystem's motion profile.
*/
public abstract TrapezoidProfile.State getGoal();
public void setGoal(TrapezoidProfile.State goal) {
m_goal = goal;
}
/**
* Sets the goal state for the subsystem. Goal velocity assumed to be zero.
*
* @param goal The goal position for the subsystem's motion profile.
*/
public void setGoal(double goal) {
setGoal(new TrapezoidProfile.State(goal, 0));
}
/**
* Enable the TrapezoidProfileSubsystem's output.
*/
public void enable() {
m_enabled = true;
}
/**
* Disable the TrapezoidProfileSubsystem's output.
*/
public void disable() {
m_enabled = false;
}
/**
* Users should override this to consume the current state of the motion profile.

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

@@ -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. */
@@ -51,6 +51,13 @@ ParallelRaceGroup Command::WithInterrupt(std::function<bool()> condition) && {
SequentialCommandGroup Command::BeforeStarting(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) && {
return std::move(*this).BeforeStarting(
std::move(toRun),
wpi::makeArrayRef(requirements.begin(), requirements.end()));
}
SequentialCommandGroup Command::BeforeStarting(
std::function<void()> toRun, wpi::ArrayRef<Subsystem*> requirements) && {
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(
std::make_unique<InstantCommand>(std::move(toRun), requirements));
@@ -61,6 +68,13 @@ SequentialCommandGroup Command::BeforeStarting(
SequentialCommandGroup Command::AndThen(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) && {
return std::move(*this).AndThen(
std::move(toRun),
wpi::makeArrayRef(requirements.begin(), requirements.end()));
}
SequentialCommandGroup Command::AndThen(
std::function<void()> toRun, wpi::ArrayRef<Subsystem*> requirements) && {
std::vector<std::unique_ptr<Command>> temp;
temp.emplace_back(std::move(*this).TransferOwnership());
temp.emplace_back(

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,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(
@@ -21,6 +21,10 @@ void CommandBase::AddRequirements(
m_requirements.insert(requirements.begin(), requirements.end());
}
void CommandBase::AddRequirements(wpi::ArrayRef<Subsystem*> requirements) {
m_requirements.insert(requirements.begin(), requirements.end());
}
void CommandBase::AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements) {
m_requirements.insert(requirements.begin(), requirements.end());
}

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. */
@@ -9,11 +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"
@@ -41,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;
@@ -67,10 +65,23 @@ static bool ContainsKey(const TMap& map, TKey keyToCheck) {
}
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;
@@ -245,6 +256,12 @@ void CommandScheduler::RegisterSubsystem(
}
}
void CommandScheduler::RegisterSubsystem(wpi::ArrayRef<Subsystem*> subsystems) {
for (auto* subsystem : subsystems) {
RegisterSubsystem(subsystem);
}
}
void CommandScheduler::UnregisterSubsystem(
std::initializer_list<Subsystem*> subsystems) {
for (auto* subsystem : subsystems) {
@@ -252,6 +269,13 @@ void CommandScheduler::UnregisterSubsystem(
}
}
void CommandScheduler::UnregisterSubsystem(
wpi::ArrayRef<Subsystem*> subsystems) {
for (auto* subsystem : subsystems) {
UnregisterSubsystem(subsystem);
}
}
Command* CommandScheduler::GetDefaultCommand(const Subsystem* subsystem) const {
auto&& find = m_impl->subsystems.find(subsystem);
if (find != m_impl->subsystems.end()) {
@@ -294,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 {
@@ -363,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);
@@ -378,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;
@@ -388,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

@@ -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. */
@@ -20,6 +20,18 @@ FunctionalCommand::FunctionalCommand(
AddRequirements(requirements);
}
FunctionalCommand::FunctionalCommand(std::function<void()> onInit,
std::function<void()> onExecute,
std::function<void(bool)> onEnd,
std::function<bool()> isFinished,
wpi::ArrayRef<Subsystem*> requirements)
: m_onInit{std::move(onInit)},
m_onExecute{std::move(onExecute)},
m_onEnd{std::move(onEnd)},
m_isFinished{std::move(isFinished)} {
AddRequirements(requirements);
}
void FunctionalCommand::Initialize() { m_onInit(); }
void FunctionalCommand::Execute() { m_onExecute(); }

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,12 @@ InstantCommand::InstantCommand(std::function<void()> toRun,
AddRequirements(requirements);
}
InstantCommand::InstantCommand(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements)
: m_toRun{std::move(toRun)} {
AddRequirements(requirements);
}
InstantCommand::InstantCommand() : m_toRun{[] {}} {}
void InstantCommand::Initialize() { m_toRun(); }

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. */
@@ -50,6 +50,46 @@ MecanumControllerCommand::MecanumControllerCommand(
AddRequirements(requirements);
}
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::SimpleMotorFeedforward<units::meters> feedforward,
frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
frc2::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<frc::MecanumDriveWheelSpeeds()> currentWheelSpeeds,
frc2::PIDController frontLeftController,
frc2::PIDController rearLeftController,
frc2::PIDController frontRightController,
frc2::PIDController rearRightController,
std::function<void(units::volt_t, units::volt_t, units::volt_t,
units::volt_t)>
output,
wpi::ArrayRef<Subsystem*> requirements)
: m_trajectory(trajectory),
m_pose(pose),
m_feedforward(feedforward),
m_kinematics(kinematics),
m_xController(std::make_unique<frc2::PIDController>(xController)),
m_yController(std::make_unique<frc2::PIDController>(yController)),
m_thetaController(
std::make_unique<frc::ProfiledPIDController<units::radians>>(
thetaController)),
m_maxWheelVelocity(maxWheelVelocity),
m_frontLeftController(
std::make_unique<frc2::PIDController>(frontLeftController)),
m_rearLeftController(
std::make_unique<frc2::PIDController>(rearLeftController)),
m_frontRightController(
std::make_unique<frc2::PIDController>(frontRightController)),
m_rearRightController(
std::make_unique<frc2::PIDController>(rearRightController)),
m_currentWheelSpeeds(currentWheelSpeeds),
m_outputVolts(output),
m_usePID(true) {
AddRequirements(requirements);
}
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
@@ -74,6 +114,30 @@ MecanumControllerCommand::MecanumControllerCommand(
AddRequirements(requirements);
}
MecanumControllerCommand::MecanumControllerCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::MecanumDriveKinematics kinematics, frc2::PIDController xController,
frc2::PIDController yController,
frc::ProfiledPIDController<units::radians> thetaController,
units::meters_per_second_t maxWheelVelocity,
std::function<void(units::meters_per_second_t, units::meters_per_second_t,
units::meters_per_second_t, units::meters_per_second_t)>
output,
wpi::ArrayRef<Subsystem*> requirements)
: m_trajectory(trajectory),
m_pose(pose),
m_kinematics(kinematics),
m_xController(std::make_unique<frc2::PIDController>(xController)),
m_yController(std::make_unique<frc2::PIDController>(yController)),
m_thetaController(
std::make_unique<frc::ProfiledPIDController<units::radians>>(
thetaController)),
m_maxWheelVelocity(maxWheelVelocity),
m_outputVel(output),
m_usePID(false) {
AddRequirements(requirements);
}
void MecanumControllerCommand::Initialize() {
m_prevTime = 0_s;
auto initialState = m_trajectory.Sample(0_s);

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,6 +16,13 @@ NotifierCommand::NotifierCommand(std::function<void()> toRun,
AddRequirements(requirements);
}
NotifierCommand::NotifierCommand(std::function<void()> toRun,
units::second_t period,
wpi::ArrayRef<Subsystem*> requirements)
: m_toRun(toRun), m_notifier{std::move(toRun)}, m_period{period} {
AddRequirements(requirements);
}
NotifierCommand::NotifierCommand(NotifierCommand&& other)
: CommandHelper(std::move(other)),
m_toRun(other.m_toRun),

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,18 @@ PIDCommand::PIDCommand(PIDController controller,
AddRequirements(requirements);
}
PIDCommand::PIDCommand(PIDController controller,
std::function<double()> measurementSource,
std::function<double()> setpointSource,
std::function<void(double)> useOutput,
wpi::ArrayRef<Subsystem*> requirements)
: m_controller{controller},
m_measurement{std::move(measurementSource)},
m_setpoint{std::move(setpointSource)},
m_useOutput{std::move(useOutput)} {
AddRequirements(requirements);
}
PIDCommand::PIDCommand(PIDController controller,
std::function<double()> measurementSource,
double setpoint, std::function<void(double)> useOutput,
@@ -28,6 +40,13 @@ PIDCommand::PIDCommand(PIDController controller,
: PIDCommand(controller, measurementSource, [setpoint] { return setpoint; },
useOutput, requirements) {}
PIDCommand::PIDCommand(PIDController controller,
std::function<double()> measurementSource,
double setpoint, std::function<void(double)> useOutput,
wpi::ArrayRef<Subsystem*> requirements)
: PIDCommand(controller, measurementSource, [setpoint] { return setpoint; },
useOutput, requirements) {}
void PIDCommand::Initialize() { m_controller.Reset(); }
void PIDCommand::Execute() {
@@ -36,4 +55,4 @@ void PIDCommand::Execute() {
void PIDCommand::End(bool interrupted) { m_useOutput(0); }
PIDController& PIDCommand::getController() { return m_controller; }
PIDController& PIDCommand::GetController() { return m_controller; }

View File

@@ -9,23 +9,29 @@
using namespace frc2;
PIDSubsystem::PIDSubsystem(PIDController controller)
: m_controller{controller} {}
PIDSubsystem::PIDSubsystem(PIDController controller, double initialPosition)
: m_controller{controller} {
SetSetpoint(initialPosition);
}
void PIDSubsystem::Periodic() {
if (m_enabled) {
UseOutput(m_controller.Calculate(GetMeasurement(), GetSetpoint()));
UseOutput(m_controller.Calculate(GetMeasurement(), m_setpoint), m_setpoint);
}
}
void PIDSubsystem::SetSetpoint(double setpoint) { m_setpoint = setpoint; }
void PIDSubsystem::Enable() {
m_controller.Reset();
m_enabled = true;
}
void PIDSubsystem::Disable() {
UseOutput(0);
UseOutput(0, 0);
m_enabled = false;
}
bool PIDSubsystem::IsEnabled() { return m_enabled; }
PIDController& PIDSubsystem::GetController() { return m_controller; }

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. */
@@ -32,6 +32,28 @@ RamseteCommand::RamseteCommand(
AddRequirements(requirements);
}
RamseteCommand::RamseteCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::RamseteController controller,
frc::SimpleMotorFeedforward<units::meters> feedforward,
frc::DifferentialDriveKinematics kinematics,
std::function<frc::DifferentialDriveWheelSpeeds()> wheelSpeeds,
frc2::PIDController leftController, frc2::PIDController rightController,
std::function<void(volt_t, volt_t)> output,
wpi::ArrayRef<Subsystem*> requirements)
: m_trajectory(trajectory),
m_pose(pose),
m_controller(controller),
m_feedforward(feedforward),
m_kinematics(kinematics),
m_speeds(wheelSpeeds),
m_leftController(std::make_unique<frc2::PIDController>(leftController)),
m_rightController(std::make_unique<frc2::PIDController>(rightController)),
m_outputVolts(output),
m_usePID(true) {
AddRequirements(requirements);
}
RamseteCommand::RamseteCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::RamseteController controller,
@@ -48,6 +70,22 @@ RamseteCommand::RamseteCommand(
AddRequirements(requirements);
}
RamseteCommand::RamseteCommand(
frc::Trajectory trajectory, std::function<frc::Pose2d()> pose,
frc::RamseteController controller,
frc::DifferentialDriveKinematics kinematics,
std::function<void(units::meters_per_second_t, units::meters_per_second_t)>
output,
wpi::ArrayRef<Subsystem*> requirements)
: m_trajectory(trajectory),
m_pose(pose),
m_controller(controller),
m_kinematics(kinematics),
m_outputVel(output),
m_usePID(false) {
AddRequirements(requirements);
}
void RamseteCommand::Initialize() {
m_prevTime = 0_s;
auto initialState = m_trajectory.Sample(0_s);

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,4 +15,10 @@ RunCommand::RunCommand(std::function<void()> toRun,
AddRequirements(requirements);
}
RunCommand::RunCommand(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements)
: m_toRun{std::move(toRun)} {
AddRequirements(requirements);
}
void RunCommand::Execute() { m_toRun(); }

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,6 +16,13 @@ StartEndCommand::StartEndCommand(std::function<void()> onInit,
AddRequirements(requirements);
}
StartEndCommand::StartEndCommand(std::function<void()> onInit,
std::function<void()> onEnd,
wpi::ArrayRef<Subsystem*> requirements)
: m_onInit{std::move(onInit)}, m_onEnd{std::move(onEnd)} {
AddRequirements(requirements);
}
StartEndCommand::StartEndCommand(const StartEndCommand& other)
: CommandHelper(other) {
m_onInit = other.m_onInit;

View File

@@ -63,5 +63,4 @@ void SubsystemBase::SetSubsystem(const wpi::Twine& name) {
void SubsystemBase::AddChild(std::string name, frc::Sendable* child) {
auto& registry = frc::SendableRegistry::GetInstance();
registry.AddLW(child, GetSubsystem(), name);
registry.AddChild(this, child);
}

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,12 @@ Button Button::WhenPressed(std::function<void()> toRun,
return *this;
}
Button Button::WhenPressed(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
WhenActive(std::move(toRun), requirements);
return *this;
}
Button Button::WhileHeld(Command* command, bool interruptible) {
WhileActiveContinous(command, interruptible);
return *this;
@@ -33,6 +39,12 @@ Button Button::WhileHeld(std::function<void()> toRun,
return *this;
}
Button Button::WhileHeld(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
WhileActiveContinous(std::move(toRun), requirements);
return *this;
}
Button Button::WhenHeld(Command* command, bool interruptible) {
WhileActiveOnce(command, interruptible);
return *this;
@@ -49,6 +61,12 @@ Button Button::WhenReleased(std::function<void()> toRun,
return *this;
}
Button Button::WhenReleased(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
WhenInactive(std::move(toRun), requirements);
return *this;
}
Button Button::ToggleWhenPressed(Command* command, bool interruptible) {
ToggleWhenActive(command, interruptible);
return *this;

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,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);
@@ -30,13 +30,19 @@ Trigger Trigger::WhenActive(Command* command, bool interruptible) {
Trigger Trigger::WhenActive(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
return WhenActive(std::move(toRun), wpi::makeArrayRef(requirements.begin(),
requirements.end()));
}
Trigger Trigger::WhenActive(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
return WhenActive(InstantCommand(std::move(toRun), requirements));
}
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);
@@ -52,13 +58,20 @@ Trigger Trigger::WhileActiveContinous(Command* command, bool interruptible) {
Trigger Trigger::WhileActiveContinous(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
return WhileActiveContinous(
std::move(toRun),
wpi::makeArrayRef(requirements.begin(), requirements.end()));
}
Trigger Trigger::WhileActiveContinous(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
return WhileActiveContinous(InstantCommand(std::move(toRun), requirements));
}
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);
@@ -73,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);
@@ -87,13 +100,19 @@ Trigger Trigger::WhenInactive(Command* command, bool interruptible) {
Trigger Trigger::WhenInactive(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
return WhenInactive(std::move(toRun), wpi::makeArrayRef(requirements.begin(),
requirements.end()));
}
Trigger Trigger::WhenInactive(std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements) {
return WhenInactive(InstantCommand(std::move(toRun), requirements));
}
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()) {
@@ -110,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

@@ -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. */
@@ -8,6 +8,7 @@
#pragma once
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
@@ -132,7 +133,18 @@ class Command : public frc::ErrorBase {
*/
SequentialCommandGroup BeforeStarting(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements = {}) &&;
std::initializer_list<Subsystem*> requirements) &&;
/**
* Decorates this command with a runnable to run before this command starts.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
SequentialCommandGroup BeforeStarting(
std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements = {}) &&;
/**
* Decorates this command with a runnable to run after the command finishes.
@@ -143,7 +155,18 @@ class Command : public frc::ErrorBase {
*/
SequentialCommandGroup AndThen(
std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements = {}) &&;
std::initializer_list<Subsystem*> requirements) &&;
/**
* Decorates this command with a runnable to run after the command finishes.
*
* @param toRun the Runnable to run
* @param requirements the required subsystems
* @return the decorated command
*/
SequentialCommandGroup AndThen(
std::function<void()> toRun,
wpi::ArrayRef<Subsystem*> requirements = {}) &&;
/**
* Decorates this command to run perpetually, ignoring its ordinary end

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. */
@@ -12,6 +12,7 @@
#include <frc/smartdashboard/Sendable.h>
#include <frc/smartdashboard/SendableHelper.h>
#include <wpi/ArrayRef.h>
#include <wpi/SmallSet.h>
#include <wpi/Twine.h>
@@ -32,6 +33,13 @@ class CommandBase : public Command,
*/
void AddRequirements(std::initializer_list<Subsystem*> requirements);
/**
* Adds the specified requirements to the command.
*
* @param requirements the requirements to add
*/
void AddRequirements(wpi::ArrayRef<Subsystem*> requirements);
void AddRequirements(wpi::SmallSet<Subsystem*, 4> requirements);
wpi::SmallSet<Subsystem*, 4> GetRequirements() const override;

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. */
@@ -157,8 +157,10 @@ class CommandScheduler final : public frc::Sendable,
void UnregisterSubsystem(Subsystem* subsystem);
void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
void RegisterSubsystem(wpi::ArrayRef<Subsystem*> subsystems);
void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
void UnregisterSubsystem(wpi::ArrayRef<Subsystem*> subsystems);
/**
* Sets the default command for a subsystem. Registers that subsystem if it

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