Compare commits

...

192 Commits

Author SHA1 Message Date
Prateek Machiraju
45590eea22 [wpigui] Hardcode window scale to 1 on macOS (#3135)
This fixes an issue with scaling on Retina displays where the frame
buffer size was double that of the window size, resulting in a content
scale factor of 2. This scale factor caused elements to appear too
large, even on the smallest zoom setting.

This change does not affect external monitors on macOS because the
reported content scale was 1 anyway.
2021-01-28 21:52:13 -08:00
Prateek Machiraju
834a64920b [build] Publish libglass and libglassnt to Maven (#3127) 2021-01-25 21:42:38 -08:00
Tyler Veness
2c2ccb3618 [wpimath] Fix Rotation2d equality operator (#3128) 2021-01-25 21:41:34 -08:00
Prateek Machiraju
fb5c8c39ae [wpigui] clang-tidy: readability-braces-around-statements 2021-01-25 09:25:39 -08:00
Prateek Machiraju
f7d39193a4 [wpigui] Fix copyright in pfd and wpigui_metal.mm 2021-01-25 09:25:39 -08:00
Tyler Veness
aec796b212 [ntcore] Fix conditional jump on uninitialized value (#3125)
`m_last_flush` should be initialized before it's used at
Dispatcher.cpp:243.
2021-01-25 08:15:08 -08:00
Peter Johnson
fb13bb2393 [sim] GUI: Add right click popup for keyboard joystick settings (#3119) 2021-01-23 09:10:58 -08:00
Prateek Machiraju
c517ec6779 [build] Update thirdparty-imgui to 1.79-2 (#3118) 2021-01-22 19:48:49 -08:00
David Vo
e8cbf2a717 [wpimath] Fix typo in SwerveDrivePoseEstimator doc (NFC) (#3112) 2021-01-21 09:31:37 -08:00
Prateek Machiraju
e9c86df468 [wpimath] Add tests for swerve module optimization (#3100) 2021-01-20 20:44:37 -08:00
Modelmat
6ba8c289c5 [examples] Remove negative of ArcadeDrive(fwd, ..) in the C++ Getting Started Example (#3102) 2021-01-20 20:43:34 -08:00
Peter Johnson
3f1672e89f [hal] Add SimDevice createInt() and createLong() (#3110) 2021-01-20 20:42:39 -08:00
Prateek Machiraju
15be5cbf1f [examples] Fix segfault in GearsBot C++ example (#3111)
This fixes a dangling this pointer in the DriveStraight and
SetDistanceToBox commands by directly capturing the
drivetrain pointer by value instead.
2021-01-20 20:38:45 -08:00
Evan Pratten
4cf0e5e6db Add quick links to API documentation in README (#3082) 2021-01-19 23:00:54 -08:00
Tyler Veness
6b1898f12e Fix RT priority docs (NFC) (#3098)
The ranges and which value was specified as highest were incorrect on
some of them. On Linux, the range is 1 to 99 with 99 being highest.

From `man 7 sched`:
```
Processes scheduled under one of the real-time policies (SCHED_FIFO,
SCHED_RR) have a sched_priority value in the range 1 (low) to 99 (high).
```

Also clean up the relevant javadoc and doxygen comments.
2021-01-19 22:59:18 -08:00
David Vo
b3426e9c0d [wpimath] Fix missing whitespace in pose estimator doc (#3097) 2021-01-19 22:58:08 -08:00
Modelmat
38c1a1f3e0 [examples] Fix feildRelative -> fieldRelative typo in XControllerCommand examples (#3104)
* MecanumControllerCommand
* SwerveControllerCommand
2021-01-19 22:57:41 -08:00
Peter Johnson
4488e25f16 [glass] Shorten SmartDashboard window names (#3096)
Instead of "/SmartDashboard/name" they now default to "name (SmartDashboard)".
This allows for smaller windows while preserving the name without requiring
user customization.
2021-01-17 20:33:42 -08:00
CoolSpy3
cfdb3058ee [wpilibj] Update SimDeviceSimTest (#3095) 2021-01-17 13:48:25 -08:00
Mark Vedder
64adff5fea [examples] Fix typo in ArcadeDrive constructor parameter name (#3092)
Removed extra 'p' in "Supplier" in the parameter name `zaxisRotateSuppplier` of the  ArcadeDrive constructor of the Romi Reference example.
2021-01-16 20:27:29 -08:00
Thad House
6efc58e3db [build] Fix issues with build on windows, deprecations, and native utils (#3090) 2021-01-16 20:26:52 -08:00
Tyler Veness
f393989a5b [wpimath, wpiutil] Add wpi::array for compile time size checking (#3087)
The wpimath APIs use std::array, which doesn't do size checking. Passing
an array with the wrong size can result in uninitialized elements
instead of a compilation error.

This is a breaking change but is worthwhile to avoid hard-to-debug errors.
2021-01-16 20:26:17 -08:00
Prateek Machiraju
d6ed20c1e4 [build] Set macOS deployment target to 10.14 (#3088) 2021-01-14 21:20:38 -08:00
Tyler Veness
7c524014c8 [hal] Add [[nodiscard]] to HAL_WaitForNotifierAlarm() (#3085)
As this is a C-compatible header, add a WPI_NODISCARD macro for
compiler-specific C-compatible nodiscard attributes.
2021-01-14 20:00:55 -08:00
Matt
406d055f07 [wpilib] Fixup wouldHitLowerLimit in elevator and arm simulation classes. (#3076)
Closes #3050.
2021-01-14 00:28:00 -08:00
sciencewhiz
04a90b5dd1 [examples] Don't continually set setpoint in PotentiometerPID Examples (#3084) 2021-01-13 20:09:08 -08:00
Prateek Machiraju
8c5bfa0132 [sim] GUI: Add max value setting for keyboard joysticks (#3083) 2021-01-12 19:57:04 -08:00
Peter Johnson
bc80c55353 [hal] Add SimValue reset() function (#3064)
This enables correct behavior for resetting incremental sensor values like
encoder counts or gyro accumulated angle with WebSockets.
2021-01-12 00:38:58 -08:00
Peter Johnson
9c3b51ca0f [wpilib] Document simulation APIs (#3079)
- Remove sim checkstyle suppression
- Add [[nodiscard]] to C++ register callback functions
- Add a couple of missing sim functions

Co-authored-by: Peter Johnson <johnson.peter@gmail.com>
Co-authored-by: Starlight220 <yotamshlomi@gmail.com>
2021-01-11 21:55:45 -08:00
Prateek Machiraju
26584ff145 [wpimath] Add model description to LinearSystemId Javadocs (#3080) 2021-01-11 20:08:55 -08:00
Prateek Machiraju
42c3d52863 [examples] Sync Java and C++ trajectories in sim example (#3081)
This also shifts the trajectory up and to the right so that the robot is
always visible in the Field GUI during traversal. Some drive constants
and trajectory constraints were also synced between the two languages.
2021-01-11 20:08:22 -08:00
Dustin Spicuzza
64e72f7103 [wpilibc] Add missing function RoboRioSim::ResetData (#3073) 2021-01-10 22:50:25 -08:00
Matt
e955037980 [wpimath] Add optimize() to SwerveModuleState (#3065)
Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2021-01-10 22:49:46 -08:00
Peter Johnson
fb99910c23 [hal] Add SimInt and SimLong wrappers for int/long SimValue (#3066) 2021-01-09 23:26:19 -08:00
CoolSpy3
e620bd4d3f [doc] Add machine-readable websocket specification (#3059)
Co-authored-by: Vasista Vovveti <vasistavovveti@gmail.com>
2021-01-09 23:24:57 -08:00
Peter Johnson
a44e761d9e [glass] Add support for plot Y axis labels 2021-01-08 11:37:35 -08:00
Peter Johnson
ea1974d576 [wpigui] Update imgui and implot to latest 2021-01-08 11:37:35 -08:00
Matt
85a0bd43c2 [wpimath] Add RKF45 integration (#3047)
This is more stable than Runge-Kutta for systems with large elements in their A or B matrices.

Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2021-01-06 21:40:25 -08:00
Prateek Machiraju
278e0f126e [glass] Use .controllable to set widgets' read-only state (#3035)
This modifies the mecanum drive, differential drive, speed controller,
and PID controller widgets to only be writeable when .controllable is
set to true.
2021-01-05 18:33:05 -08:00
Tyler Veness
d8652cfd4f [wpimath] Make Java DCMotor API consistent with C++ and fix motor calcs (#3046)
The stall torque, stall current, and free current are now multiplied by
the number of motors instead of just the stall torque. This produces the
same values for Kt and Kv regardless of the number of motors; the motor
resistance still affects the system response.

For an elevator model, the response should be the same as before since a
factor of "number of motors" shows up in the same place in the
acceleration calculation, but the current calculation will also be
correct now.
2021-01-05 18:28:57 -08:00
Peter Johnson
377b7065aa [build] Add toggleOffOn to Java spotless (#3053)
This allows custom formatting where desired (e.g. of table values).

Also upgrade spotless to 5.5.0.
2021-01-05 17:56:45 -08:00
Prateek Machiraju
1e9c79c587 [sim] Use plant output to retrieve simulated position (#3043)
Using the plant output means that measurement noise can be incorporated.
SingleJointedArmSim (in C++ and Java) and ElevatorSim (in C++) used the
state instead of the measurement.

Closes #3042
2021-01-05 17:55:44 -08:00
Peter Johnson
78147aa342 [sim] GUI: Fix Keyboard Joystick (#3052)
This was broken by #3010.

Also fix a few unknown key cases and a nullptr return that could cause a crash.
2021-01-05 17:55:11 -08:00
Peter Johnson
cd4a2265b9 [ntcore] Fix NetworkTableEntry::GetRaw() (#3051)
It was calling value->GetString() instead of GetRaw(), which would assert.
2021-01-04 22:07:50 -08:00
Austin Shalit
767ac1de10 [build] Use deploy key for doc publish (#3048)
This allows us to limit the scope of personal access tokens
2021-01-04 15:21:47 -08:00
Austin Shalit
d762215d13 [build] Add publish documentation script (#3040) 2021-01-04 13:59:19 -08:00
sciencewhiz
1fd09593cf [examples] Add missing TestInit method to GettingStarted Example (#3039) 2021-01-02 22:00:25 -08:00
Zhiquan Yeo
e45a0f6ce2 [examples] Add RomiGyro to the Romi Reference example (#3037) 2021-01-02 21:59:57 -08:00
sciencewhiz
94f8525721 Update imaging link and fix typo (#3038) 2021-01-02 19:57:39 -08:00
Zhiquan Yeo
d73cf64e54 [examples] Update RomiReference to match motor directions (#3036)
Flip the TeleopArcadeDrive axis directions so that positive
values for x-axis speed result in the Romi driving forward (in the
direction of the Raspberry Pi USB ports).
2021-01-02 17:21:07 -08:00
Peter Johnson
f945462bab Bump copyright year to 2021 (#3033) 2021-01-01 21:54:00 -08:00
Tyler Veness
b05946175b [wpimath] Catch Drake JNI exceptions and rethrow them (#3032)
This gives an informative error in Java instead of crashing the JVM.
2021-01-01 17:09:50 -08:00
Tyler Veness
62f0f8190d [wpimath] Deduplicate angle modulus functions (#2998)
frc::NormalizeAngle(), units::math::NormalizeAngle(), and
frc::GetModulusError() were replaced with frc::InputModulus() and
frc::AngleModulus().

They were placed in wpimath/src/main/native/include/frc/MathUtil.h for
C++ and wpimath/src/main/java/edu/wpi/first/wpiutil/math/MathUtil.java
for Java.
2021-01-01 16:22:00 -08:00
Prateek Machiraju
bf8c0da4be [glass] Add "About" popup with version number (#3031) 2021-01-01 15:59:00 -08:00
Prateek Machiraju
dfdd6b3891 [build] Increase Gradle heap size in Gazebo build (#3028)
Builds have been intermittently failing due to Gradle running out of memory.
2021-01-01 10:29:55 -08:00
Peter Johnson
f5e0fc3e9a Finish clang-tidy cleanups (#3003)
* Add .clang-tidy configuration.
* A separate .clang-tidy is used for hal includes to suppress modernize-use-using
  (as these are C headers).
* Add NOLINT where necessary for a clean run.
* Add clang-tidy job to lint-format workflow.  This workflow is now only run on PRs.
  To reduce runtime, clang-tidy is only run on files changed in the PR.

Two wpilibc changes; both are unlikely to break user code:
* BuiltInAccelerometer: Make SetRange() final
* Counter: Make SetMaxPeriod() final

After these cleanups, the only file that does not run cleanly is
cscore_raw_cv.h due to it not being standalone.
2021-01-01 10:27:49 -08:00
Peter Johnson
d741101fe3 [sim] Revert accidental commit of WSProvider_PDP.h (#3027) 2021-01-01 00:44:31 -08:00
Starlight220
e1620799c7 [examples] Add C++ RomiReference example (#2969)
Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
Co-authored-by: sciencewhiz <sciencewhiz@users.noreply.github.com>
2020-12-31 20:37:20 -08:00
Prateek Machiraju
749c7adb13 [command] Fix use-after-free in CommandScheduler (#3024) 2020-12-31 20:35:17 -08:00
Peter Johnson
921a733911 [sim] Add WS providers for AddressableLED, PCM, and Solenoid (#3026)
Co-authored-by: PJ Reiniger <pj.reiniger@gmail.com>
2020-12-31 20:34:34 -08:00
Austin Shalit
26d0004fe1 [build] Split Actions into different yml files (#3025) 2020-12-31 20:33:39 -08:00
Austin Shalit
948af6d5b5 [wpilib] PWMSpeedController.get(): Apply Inversion (#3016)
This makes get() return the value actually sent to the motor.

This is a breaking change.
2020-12-31 14:35:10 -08:00
Peter Johnson
670a187a3c [wpilibc] SuppliedValueWidget.h: Forward declare ShuffleboardContainer (#3021)
This is needed to break the include loop between SuppliedValueWidget.h and ShuffleboardContainer.h.
2020-12-31 12:35:56 -08:00
Peter Johnson
be9f725023 [ntcore] NetworkTableValue: Use std::forward instead of std::move (#3022)
Because these are forwarding references, they could unexpectedly move a
passed lvalue.  Using std::forward() makes a copy if an lvalue is passed.
2020-12-31 12:35:02 -08:00
Peter Johnson
daf3f4cb1a [cscore] cscore_raw_cv.h: Fix error in PutFrame() (#3019) 2020-12-31 12:34:37 -08:00
Peter Johnson
5acda4cc71 [wpimath] ElevatorFeedforward.h: Add time.h include 2020-12-31 12:18:06 -08:00
Peter Johnson
8452af606b [wpimath] units/radiation.h: Add mass.h include 2020-12-31 12:18:06 -08:00
Peter Johnson
630d449520 [hal] ErrorsInternal.h: Add stdint.h include 2020-12-31 12:18:06 -08:00
Peter Johnson
7372cf7d99 [cscore] Windows NetworkUtil.cpp: Add missing include 2020-12-31 12:18:06 -08:00
Peter Johnson
b7e46c558f Include .h from .inc/.inl files (NFC) (#3017)
This helps both IDEs and linting tools.

Also add some missing braces.
2020-12-31 11:26:53 -08:00
jpokornyiii
bf8f8710ea [examples] Update Romi template and example (#2996)
Updated the RomiReference example to have autonomous example.
Updated RomiReference and both Romi templates to use Encoder.getDistance().
Removed motor inversion.
2020-12-30 22:45:04 -08:00
Austin Shalit
6ffe5b775d [glass] Ensure NetworkTableTree parent context menu has an id (#3015) 2020-12-30 22:43:35 -08:00
Austin Shalit
be0805b85b [build] Update to WPILibVersioningPlugin 4.1.0 (#3014) 2020-12-30 22:40:38 -08:00
Austin Shalit
65b2359b27 [build] Add spotless for other files (#3007)
Adds spotless formatting for Gradle, xml, md, and gitignore files.

yml linting is not performed as it requires a dependency on npm.
2020-12-30 16:17:20 -08:00
Prateek Machiraju
8651aa73e8 [examples] Enable NT Flush in Field2d examples (#3013) 2020-12-30 16:12:15 -08:00
Austin Shalit
78b542737a [build] Add Gazebo build to Actions CI (#3004) 2020-12-30 11:38:49 -08:00
Peter Johnson
fccf86532f [sim] DriverStationGui: Fix two bugs (#3010)
- Slicing of GlfwKeyboardJoystick
- Potential null pointer deref
2020-12-30 11:37:54 -08:00
Peter Johnson
1857417601 [sim] WSProvider_Joystick: Fix off-by-1 in incoming buttons (#3011) 2020-12-30 11:37:20 -08:00
Prateek Machiraju
ee7114a58c [glass] Add drive class widgets (#2975)
This adds widgets for DifferentialDrive and MecanumDrive.
2020-12-30 08:51:55 -08:00
Prateek Machiraju
00fa91d0d6 [glass] Use ImGui style for gyro widget colors (#3009)
This ensures that the colors are properly visible in light mode or any
other custom user styles.
2020-12-30 08:42:26 -08:00
Peter Johnson
b7a25bfc33 ThirdPartyNotices: Add portable file dialogs license (#3005) 2020-12-29 22:46:44 -08:00
Austin Shalit
a2e46b9a1b [glass] modernize-use-nullptr (NFC) (#3006) 2020-12-29 22:46:11 -08:00
Peter Johnson
a751fa22d2 [build] Apply spotless for java formatting (#1768)
Update checkstyle config to be compatible with spotless.

Co-authored-by: Austin Shalit <austinshalit@gmail.com>
2020-12-29 22:45:16 -08:00
Tyler Veness
e563a0b7db [wpimath] Make LinearSystemLoop move-constructible and move-assignable (#2967) 2020-12-29 20:50:26 -08:00
Austin Shalit
49085ca943 [glass] Add context menus to remove and add NetworkTables values (#2979) 2020-12-29 20:49:29 -08:00
Peter Johnson
560a850a2b [glass] Add NetworkTables Log window (#2997)
This moves NetworkTable log messages out of the console (which is hidden on some platforms).
2020-12-29 20:47:58 -08:00
PJ Reiniger
66782e2317 [sim] Create Left/Right drivetrain current accessors (#3001) 2020-12-29 20:46:51 -08:00
Peter Johnson
b60eb1544b clang-tidy: bugprone-virtual-near-miss
A few virtual functions are called by constructors or destructors, which is
dangerous in C++ (as an overridden virtual impl won't be called, only the
one in the current class).  Fix by either marking the function final or
not calling at all (if possible).
2020-12-29 14:26:19 -08:00
Peter Johnson
cbe59fa3bf clang-tidy: google-explicit-constructor 2020-12-29 14:26:19 -08:00
Peter Johnson
c97c6dc065 clang-tidy: google-readability-casting (NFC) 2020-12-29 14:26:19 -08:00
Peter Johnson
32fa97d68d clang-tidy: modernize-use-nullptr (NFC) 2020-12-29 14:26:19 -08:00
Peter Johnson
aee4603269 clang-tidy: modernize-pass-by-value 2020-12-29 14:26:19 -08:00
Peter Johnson
29c7da5f1a clang-tidy: modernize-make-unique 2020-12-29 14:26:19 -08:00
Peter Johnson
6131f4e32b clang-tidy: modernize-concat-nested-namespaces (NFC) 2020-12-29 14:26:19 -08:00
Peter Johnson
67e03e625d clang-tidy: modernize-use-equals-default 2020-12-29 14:26:19 -08:00
Peter Johnson
b124f9101b clang-tidy: modernize-use-default-member-init 2020-12-29 14:26:19 -08:00
Peter Johnson
d11a3a6380 clang-tidy: modernize-use-override (NFC)
Add NOLINT to CommandTestBase due to gmock not adding "override" keyword,
which causes warnings on clang.
2020-12-29 14:26:19 -08:00
Peter Johnson
4cc0706b06 clang-tidy: modernize-use-using (NFC)
Excludes C-compatible headers
2020-12-29 14:26:19 -08:00
Tyler Veness
885f5a9781 [wpilibc] Speed up ScopedTracerTest (#2999)
ScopedTracerTest now uses simulation time instead of wall clock time, so
it doesn't have to actually wait 1.5 seconds.
2020-12-29 10:30:23 -08:00
sciencewhiz
60b5964577 [wpilibj] Fix typos (NFC) (#3000) 2020-12-29 10:29:39 -08:00
Austin Shalit
6e1919414e [build] Bring naming checkstyle rules up to date with Google Style guide (#1781)
Also update Checkstyle to 8.38.

Google changed their style guide from the last time we imported it. This PR brings in those naming changes. The change they made is allowing single letter member, parameter, and local variable names. They also added a lambda naming scheme and I thought it would be good to bring that in too.
2020-12-29 09:27:48 -08:00
Tyler Veness
8c8ec5e63e [wpilibj] Suppress unchecked cast warnings (#2995) 2020-12-28 17:13:34 -08:00
Peter Johnson
b8413ddd5b [wpiutil] Add noexcept to timestamp static functions (#2994)
This silences a clang-tidy warning.
2020-12-28 17:12:51 -08:00
Austin Shalit
5d976b6e18 [glass] Load NetworkTableView settings on first draw (#2993)
Before this change, user settings were not loaded until after the first time they opened the settings context menu.
2020-12-28 15:29:25 -08:00
Tyler Veness
2b4317452b Replace NOLINT(runtime/explicit) comments with NOLINT (NFC) (#2992)
cpplint.py can accept either, but clang-tidy requires NOLINT.
2020-12-28 15:10:31 -08:00
Peter Johnson
1c3011ba4b [glass] Fix handling of "/" NetworkTables key (#2991) 2020-12-28 14:36:30 -08:00
Peter Johnson
574a42f3b4 [hal] Fix UnsafeManipulateDIO status check (#2987) 2020-12-28 13:04:21 -08:00
Matt
9005cd59e5 [wpilib] Clamp input voltage in sim classes (#2955) 2020-12-28 13:03:31 -08:00
Peter Johnson
dd494d4ab7 [glass] NetworkTablesModel::Update(): Avoid use-after-move (#2988) 2020-12-28 13:02:24 -08:00
Peter Johnson
7cca469a12 [wpimath] NormalizeAngle: Make inline, remove unnamed namespace (#2986) 2020-12-28 13:00:26 -08:00
Peter Johnson
2aed432b4b Add braces to C++ single-line loops and conditionals (NFC) (#2973)
This makes code easier to read and more consistent between C++ and Java.
Also update clang-format settings to always add a line break (even if no braces are used).
2020-12-28 12:58:06 -08:00
Peter Johnson
0291a3ff56 [wpiutil] StringRef: Add noexcept to several constructors (#2984) 2020-12-28 11:34:50 -08:00
Peter Johnson
5d7315280a [wpimath] Update UnitsTest.cpp copyright (#2985) 2020-12-28 10:40:20 -08:00
Matt
254931b9a8 [wpimath] Remove LinearSystem from LinearSystemLoop (#2968)
The system wasn't being used internally, and as LinearSystem is stateless, it doesn't need to be held by LinearSystemLoop.
2020-12-28 10:35:51 -08:00
Prateek Machiraju
aa89744c95 Update OtherVersions.md to include wpimath info (#2983)
This also updates occurrences of 2020 to 2021.
2020-12-28 10:34:19 -08:00
Peter Johnson
1cda3f5ad7 [glass] Fix styleguide (#2976) 2020-12-26 14:31:24 -08:00
Peter Johnson
8f1f64ffb6 Remove year from file copyright message (NFC) (#2972)
Also update copyright to include "and other WPILib contributors" and clarify
license referral language to not be restricted to FIRST teams.
2020-12-26 14:12:05 -08:00
Peter Johnson
2bc0a7795c [examples] Fix wpiformat warning about utility include (#2971) 2020-12-26 09:34:21 -08:00
Peter Johnson
4204da6ad4 [glass] Add application icon 2020-12-25 22:08:37 -08:00
Peter Johnson
7ac39b10f7 [wpigui] Add icon support 2020-12-25 22:08:37 -08:00
Matt
6b567e0066 [wpimath] Add support for varying vision standard deviations in pose estimators (#2956)
Exposes the R passed to vision correct to users.
2020-12-24 16:05:07 -08:00
Tyler Veness
df299d6edd [wpimath] Add UnscentedKalmanFilter::Correct() overload (#2966)
This adds an overload of UnscentedKalmanFilter::Correct() that takes a
custom measurement covariance but uses default mean and residual
calculation functions.

Closes #2965.
2020-12-24 16:00:36 -08:00
Prateek Machiraju
4e34f05238 [examples] Use ADXRS450_GyroSim class in simulation example (#2964)
This class did not exist when the original example was written. This
also changes the C++ example to use ADXRS450_Gyro for the sake of
consistency.
2020-12-24 15:42:46 -08:00
Tyler Veness
9962f6fd79 [wpilib] Give Field2d a default Sendable name (#2953) 2020-12-24 12:26:03 -08:00
Peter Johnson
f9d492f4b1 [sim] GUI: Show "Other Devices" window by default (#2961) 2020-12-24 12:24:36 -08:00
Peter Johnson
a8bb2ef1c3 [sim] Fix ADXRS450_GyroSim and DutyCycleEncoderSim (#2963)
These were broken by #2952.

Also fix Java ADXRS450_Gyro angle/rate SimValue names.
2020-12-24 12:23:38 -08:00
Peter Johnson
240c629cda [sim] Try to guess "Map Gamepad" setting (#2960)
Looks to see if the joystick name starts with "Xbox" or contains "pad".
2020-12-23 20:38:28 -08:00
Tyler Veness
952567dd3c [wpilibc] Add missing move constructors and assignment operators (#2959)
- Field2d
- FieldObject2d
- AnalogGyro
2020-12-23 20:36:51 -08:00
Peter Johnson
10b396b4c2 [sim] Various WebSockets fixes and enhancements (#2952)
This is a breaking change to the WebSockets layer to align it with
recent specification documentation work.

To support this, HAL SimValue changed readonly to a direction enum.
This allows specifying bidirectional in addition to input and output.

The SimValue change is specifically designed to avoid API and ABI breakage.
This is completely transparent in C++; in Java a new callback class was added,
and the old readonly functions have been marked deprecated.

A new SimValue creation function for enums allows specifying double values
for each enum value, not just strings.  This allows mapping enum values to
doubles in the WebSockets layer.

A ":" in the SimDevice name now maps it to different WebSocket types (e.g.
"Accel:Name" becomes type "Accel", device "Name").  The type is hidden
in the GUI.

Other WebSockets changes:
* Implemented match_time and game_data
* Added joystick rumble data
* Added builtin accelerometer support
* SimValue enums are mapped to string and double value on WS interface
* Added WebSockets protocol specification
* Added READMEs
2020-12-23 15:54:11 -08:00
sciencewhiz
699bbe21a4 [examples] Fix comments in Gearsbot to match implementation (NFC) (#2957) 2020-12-22 22:26:54 -08:00
Prateek Machiraju
27b67deca6 [glass] Add more widgets (#2947)
This adds the following widgets:
- Speed Controller
- Gyroscope
- Command
- Subsystem
- PIDController
- Scheduler
2020-12-22 21:07:44 -08:00
Peter Johnson
581b7ec553 [wpilib] Add option to flush NetworkTables every iterative loop
This functionality is disabled by default, but can be enabled by the user
program by calling setNetworkTablesFlushEnabled.
2020-12-21 09:53:45 -08:00
Peter Johnson
acfbb1a44a [ntcore] DispatcherBase::Flush: Use wpi::Now()
This is faster on some platforms than steady_clock, and will more
consistently support simulation timing.
2020-12-21 09:53:45 -08:00
Peter Johnson
d85a6d8fe4 [ntcore] Reduce limit on flush and update rate to 5 ms 2020-12-21 09:53:45 -08:00
Tyler Veness
20fbb5c63b [sim] Fix stringop truncation warning from GCC 10 (#2945)
If the strncpy() bound is equal to the destination size and the source
string is longer than 256 bytes, strncpy() won't write a null terminator
for the destination string.
2020-12-17 21:51:57 -08:00
Peter Johnson
1051a06a76 [glass] Show NT timestamps in seconds (#2944) 2020-12-17 07:29:00 -08:00
Peter Johnson
98dfc26208 [glass] Fix plots (#2943) 2020-12-17 07:27:29 -08:00
Peter Johnson
1ba0a2cedd [sim] GUI: Add keyboard virtual joystick support (#2940)
This allows joystick testing without a physical joystick.
Comes with a default set of keyboard mappings, but these are fully customizable by the user.
Up to 4 virtual joysticks are supported.

Default keyboard mappings:

    Joystick 0: axis 0: AD, axis 1: WS, axis 2: ER, buttons ZXCV, POV on numeric keypad
    Joystick 1: axis 0: JL, axis 1: IK, buttons M,./
    Joystick 2: axis 0: left/right arrow, axis 1: up/down arrow, buttons insert/home/pgup/del/end/pgdn

Also adds support for DS-style hotkeys of []\ enable, Enter disable, and spacebar disable.
All of these are disabled by default and must be explicitly enabled by the user.
2020-12-17 00:20:12 -08:00
Tyler Veness
4afb13f98b [examples] Replace M_PI with wpi::math::pi (#2938) 2020-12-17 00:15:02 -08:00
Zhiquan Yeo
b27d33675d [examples] Enhance Romi templates (#2931)
Add motors and encoders so they are more usable out of the box.
2020-12-10 21:38:27 -08:00
Peter Johnson
00b9ae77f9 [sim] Change default WS port number to 3300 (#2932) 2020-12-10 20:39:14 -08:00
Prateek Machiraju
65219f3093 [examples] Update Field2d position in periodic() (#2928)
This ensures that the robot position will be updated in dashboards like Glass when running on real hardware.
2020-12-10 20:36:20 -08:00
Peter Johnson
f78d1d4340 [sim] Process WS Encoder reset internally (#2927)
Currently, Encoder.reset() must make a round trip to the sensor and back
in order for the count to be updated for the user program.  As the sim layer
also resets the internal encoder count, this creates a race condition (a WS
message with a new count can be "in flight" during a reset and update the
count).

This changes the WS layer to not put reset on the wire, but instead keep an
offset count internal to the robot program.  The value on the wire is not
reset, but rather all sends and receives are adjusted as necessary to the
internal robot count.

This approach is straightforward, but does result in the value on the wire
not matching the value in the user program.  A future improvement will fix
this, but this change fixes the immediate race condition problem.
2020-12-10 20:30:12 -08:00
Peter Johnson
941edca597 [hal] Add Java SimDeviceDataJNI.getSimDeviceName (#2924)
This was mistakenly omitted from the Java interface.
2020-12-08 20:42:46 -08:00
Matt
a699435ede [wpilibj] Fix FlywheelSim argument order in constructor (#2922) 2020-12-07 22:34:17 -08:00
Prateek Machiraju
66d6417189 [examples] Add tasks to run Java examples (#2920)
Example: ./gradlew :wpilibjExamples:runstatespacedifferentialdrivesimulation
2020-12-07 22:33:17 -08:00
Prateek Machiraju
558e37c412 [examples] Add simple differential drive simulation example (#2918)
This provides an example of using the differential drive simulator without needing to use the command-based library.
2020-12-07 22:32:42 -08:00
Thad House
4f40d991ea [glass] Switch name of Glass back to glass (#2919)
On Unix systems, most executables are lowercase.
2020-12-07 22:32:15 -08:00
Prateek Machiraju
549af99007 [build] Update native-utils to 2021.0.6 (#2914)
This fixes the Glass publishing classifier
2020-12-05 23:58:42 -08:00
Thad House
b336930093 [glass] Change basename of glass to Glass (#2915)
Was glassApp, which makes building an extraction setup much harder.
2020-12-05 23:56:12 -08:00
Prateek Machiraju
c9a0edfb8b [glass] Package macOS application bundle 2020-12-05 23:23:35 -08:00
Prateek Machiraju
2c5668af46 [wpigui] Add platform-specific preferences save 2020-12-05 23:23:35 -08:00
Peter Johnson
751dea32ae [wpilibc] Try to work around ABI break introduced in #2901 (#2917)
The change to SendableBuilder to add GetTable() added a virtual function
early in the class definition.  This is an ABI break for vendor libraries.
Attempt to workaround this breakage by moving GetTable() to the end of the
class definition.
2020-12-05 23:19:15 -08:00
Thad House
cd8f4bfb1f [build] Package up msvc runtime into maven artifact (#2913)
This will make is so we can get the right artifact to the installer, and we can do it automatically and its guaranteed to match what built the artifacts.
2020-12-05 20:14:03 -08:00
Tyler Veness
a6cfcc6866 [wpilibc] Move SendableChooser Doxygen comments to header (NFC) (#2911) 2020-12-05 20:04:44 -08:00
Tyler Veness
b8c4f603db [wpimath] Upgrade to Eigen 3.3.9 (#2910)
It fixes some compilation errors with C++20.
2020-12-05 20:03:47 -08:00
Prateek Machiraju
0075e4b391 [wpilibj] Fix NPE in Field2d (#2909) 2020-12-05 08:46:54 -08:00
Peter Johnson
125af556ce [simulation] Fix halsim_gui ntcore and wpiutil deps (#2908)
They were being linked out of order, so ntcore wasn't being linked.
2020-12-04 23:30:17 -08:00
Matt
963ad5c255 [wpilib] Add noise to Differential Drive simulator (#2903)
Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
2020-12-04 18:46:50 -08:00
Peter Johnson
387f56cb7b [examples] Add Romi reference Java example and templates (#2905) 2020-12-04 17:34:54 -08:00
Prateek Machiraju
b3deda38c9 [examples] Zero motors on disabledInit() in sim physics examples (#2906)
This ensures that mechanisms will stop moving if the robot is disabled while motors are in motion
2020-12-04 17:34:16 -08:00
Peter Johnson
2a5ca77454 [glass] Add glass: an application for display of robot data
This reuses many pieces of the current simulation GUI.  The common pieces have
been refactored into the libglass library.

The libglass library is designed to be usable for other standalone data
visualization applications (e.g. viewing data logs).

The name "glass" comes from "glass cockpit", as the application features
several multi-function displays that can be adjusted to display robot
information as needed.
2020-12-04 00:36:55 -08:00
Peter Johnson
727940d847 [wpilib] Move Field2d to SmartDashboard 2020-12-04 00:36:55 -08:00
Peter Johnson
8cd42478e1 [wpilib] SendableBuilder: Make GetTable() visible 2020-12-04 00:36:55 -08:00
Prateek Machiraju
c11d34b26c [command] Use addCommands in command group templates (#2900)
This makes the Java templates consistent with the C++ templates as well as the documentation

Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2020-12-01 20:52:45 -08:00
Peter Johnson
339d7445b3 [sim] Add HAL hooks for simulationPeriodic (#2881)
This allows vendor libs to hook into the begin or end of simulationPeriodic().
2020-11-30 23:55:36 -08:00
Peter Johnson
d16f05f2c8 [wpilib] Fix SmartDashboard update order (#2896)
We need to execute listener tasks first, then execute value updates.
Otherwise local changes can fight with dashboard-made changes.
2020-11-30 19:24:12 -08:00
Peter Johnson
5427b32a40 [wpiutil] unique_function: Restrict implicit conversion (#2899)
Only implicitly convert from invocable objects.  This avoids potential
ambiguity in higher-level overloaded functions.
2020-11-30 19:21:10 -08:00
Peter Johnson
f73701239d [ntcore] Add missing SetDefault initializer_list functions (#2898) 2020-11-30 19:20:40 -08:00
Peter Johnson
f5a6fc0703 [sim] Add initialized flag for all solenoids on a PCM (#2897)
This allows much easier/faster checking for whether any solenoid has been
initialized on a particular PCM.
2020-11-30 19:20:16 -08:00
Prateek Machiraju
bdf5ba91a4 [wpilibj] Fix typo in ElevatorSim (#2895)
This caused an illegal argument exception whenever the simulated elevator velocity was retrieved.
2020-11-29 22:28:11 -08:00
Declan Freeman-Gleason
bc8f338771 [wpilib] Add pose estimators (#2867)
Pose and state estimators can filter latency-compensated global measurements and fuse them with state-space drivetrain model information to estimate robot position. They are drop-in replacements for the existing odometry classes.

Co-authored-by: Declan Freeman-Gleason <declanfreemangleason@gmail.com>
Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
Co-authored-by: Claudius Tewari <cttewari@gmail.com>
Co-authored-by: Matt <matthew.morley.ca@gmail.com>
2020-11-28 14:35:35 -08:00
Tyler Veness
3413bfc06a [wpilib] PIDController: Recompute the error in AtSetpoint() (#2822)
This makes AtSetpoint() return false after the setpoint is changed with
SetSetpoint().

Closes #2821.

Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
2020-11-28 14:33:17 -08:00
Prateek Machiraju
2056f0ce09 [wpilib] Fix bugs in Hatchbot examples (#2893)
This fixes an issue with some commands not correctly requiring their
subsytems. Furthermore, an execute() method was added to the
DriveDistance command to continuously update the voltage command.
2020-11-28 14:01:56 -08:00
Peter Johnson
5eb8cfd691 [wpilibc] Fix MatchDataSender (#2892)
The is_convertible test was always treating the input as bool.
Use is_same on T instead.
2020-11-27 22:06:08 -08:00
Thad House
e6a4254488 [build] Delete test folders after tests execute (#2891)
Also deletes object files.

Both of these things are only done on the build server (-PbuildServer flag).

This will remove all test folders, which removes lots of copies of dependencies.

This also fixes an issue where gtest exectubables were installed for cross builds, even though they should not have been.
2020-11-27 21:44:47 -08:00
Prateek Machiraju
d478ad00d0 [imgui] Allow usage of imgui_stdlib (#2889)
This bumps the version number of thirdparty-imgui in Gradle and adds
imgui_stdlib.cpp into the sources in CMake, as well as adding a new
include directory.
2020-11-26 19:28:24 -08:00
Prateek Machiraju
53eda861de [build] Add unit-testing infrastructure to examples (#2863)
This also adds CMake capabilities to the command-based libraries as well
as wpilibExamples.
2020-11-26 11:47:35 -08:00
Prateek Machiraju
cc1d86ba63 [sim] Add title to simulator GUI window (#2888) 2020-11-26 11:46:14 -08:00
Prateek Machiraju
f0528f00e7 [build] CMake: Use project-specific binary and source dirs (#2886)
This ensures that allwpilib will still build correctly when added as a CMake external project.
2020-11-24 20:25:44 -08:00
Tyler Veness
5cd2ad124d [wpilibc] Add Color::operator!= (#2887) 2020-11-24 19:26:00 -08:00
Tyler Veness
6c00e7a902 [build] CI CMake: build with GUI enabled (#2884) 2020-11-24 13:37:39 -08:00
Tyler Veness
53170bbb58 Update roboRIO toolchain installation instructions (#2883)
There were conflicting instructions: install via the archive on
the releases page, and install using a gradlew command.
2020-11-23 19:48:26 -08:00
Dean Brettle
467258e050 [sim] GUI: Add option to not zero disconnected joysticks (#2876)
This allows team sim code to set the joystick values and not have them overwritten by the GUI.
2020-11-23 19:46:27 -08:00
Tyler Veness
129be23c9e Clarify JDK installation instructions in readme (#2882) 2020-11-23 19:45:14 -08:00
Prateek Machiraju
8e9290e86e [build] Add separate CMake setting for wpimath (#2885)
This allows external CMake projects to only depend on wpimath instead of
having to build the entire library.
2020-11-23 19:44:20 -08:00
Starlight220
7cf5bebf8e [wpilibj] Cache NT writes from DriverStation (#2780)
This reduces malloc traffic.
2020-11-21 14:35:43 -08:00
Prateek Machiraju
f7f9087fb5 [command] Fix timing issue in RamseteCommand (#2871)
This issue only existed on the initial iteration. When timing is paused and stepped,
initialize() and execute() get called with the same timestamp the first time, which
would result in a divide by zero. All subsequent steps advance timing and only
call execute() so the time deltas are all set correctly.
2020-11-21 10:03:01 -08:00
CoolSpy3
256e7904fd [wpilibj] SimDeviceSim: Fix sim value changed callback (#2880) 2020-11-20 21:02:23 -08:00
Tyler Veness
c8ea1b6c38 [wpilib] Add function to adjust LQR controller gain for pure time delay (#2878)
There were three options for where to put this function:

1. A free function in LinearQuadraticRegulator.h. Returning a K matrix
   means the user can't use the LinearQuadraticRegulator in a loop
   anymore.
2. A default argument added to ctors in LinearQuadraticRegulator for a
   time delay (default of 0). This has the smallest API footprint from
   the user perspective, but it bloats the already substantial
   constructor overload set of LinearQuadraticRegulator.
3. A member function in LinearQuadraticRegulator that modifies the
   internal K. This would still have to take in a LinearSystem or (A, B)
   pair because the ctor doesn't store it. Storing it internally feels
   like paying for what we don't use most of the time.

I went with option 3.

I verified the tests's expected values in Python with
scipy.linalg.fractional_matrix_power().

Closes #2877.
2020-11-20 15:28:00 -08:00
Peter Johnson
2816b06c05 [sim] HAL_GetControlWord: Fully zero output (#2873)
This ensures the padding is zero'ed.  We already do this on Athena, we just didn't in sim.
2020-11-20 15:11:11 -08:00
Tyler Veness
4c695ea088 Add toolchain installation instructions to README (#2875) 2020-11-19 13:09:09 -08:00
3166 changed files with 70123 additions and 46200 deletions

View File

@@ -14,10 +14,10 @@ AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true

76
.clang-tidy Normal file
View File

@@ -0,0 +1,76 @@
Checks:
'bugprone-assert-side-effect,
bugprone-bool-pointer-implicit-conversion,
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-dynamic-static-initializers,
bugprone-exception-escape,
bugprone-forward-declaration-namespace,
bugprone-forwarding-reference-overload,
bugprone-inaccurate-erase,
bugprone-incorrect-roundings,
bugprone-integer-division,
bugprone-lambda-function-name,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-move-forwarding-reference,
bugprone-multiple-statement-macro,
bugprone-parent-virtual-call,
bugprone-posix-return,
bugprone-sizeof-container,
bugprone-sizeof-expression,
bugprone-spuriously-wake-up-functions,
bugprone-string-constructor,
bugprone-string-integer-assignment,
bugprone-string-literal-with-embedded-nul,
bugprone-suspicious-enum-usage,
bugprone-suspicious-include,
bugprone-suspicious-memset-usage,
bugprone-suspicious-missing-comma,
bugprone-suspicious-semicolon,
bugprone-suspicious-string-compare,
bugprone-throw-keyword-missing,
bugprone-too-small-loop-variable,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-self-assignment,
bugprone-unused-raii,
bugprone-virtual-near-miss,
cert-dcl58-cpp,
cert-err52-cpp,
cert-err60-cpp,
cert-mem57-cpp,
cert-oop57-cpp,
cert-oop58-cpp,
clang-diagnostic-*,
-clang-diagnostic-deprecated-declarations,
-clang-diagnostic-#warnings,
-clang-diagnostic-pedantic,
clang-analyzer-*,
cppcoreguidelines-slicing,
google-build-namespaces,
google-explicit-constructor,
google-global-names-in-headers,
google-readability-avoid-underscore-in-googletest-name,
google-readability-casting,
google-runtime-operator,
llvm-twine-local,
misc-definitions-in-headers,
misc-misplaced-const,
misc-new-delete-overloads,
misc-non-copyable-objects,
modernize-avoid-bind,
modernize-concat-nested-namespaces,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
modernize-use-default-member-init,
modernize-use-noexcept,
modernize-use-nullptr,
modernize-use-override,
modernize-use-using,
readability-braces-around-statements'
FormatStyle: file
CheckOptions:
- key: bugprone-dangling-handle
value: 'wpi::StringRef;wpi::Twine'

4
.gitattributes vendored Normal file
View File

@@ -0,0 +1,4 @@
*.gradle text eol=lf
*.java text eol=lf
*.md text eol=lf
*.xml text eol=lf

59
.github/workflows/cmake.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: CMake
on: [pull_request, push]
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: Linux
container: wpilib/roborio-cross-ubuntu:2020-18.04
flags: ""
- os: macos-latest
name: macOS
container: ""
flags: "-DWITH_JAVA=OFF"
name: "Build - ${{ matrix.name }}"
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
brew install opencv
fi
- name: configure
run: mkdir build && cd build && cmake ${{ matrix.flags }} ..
- name: build
working-directory: build
run: make -j3
- name: test
working-directory: build
run: make test
build-vcpkg:
name: "Build - Windows"
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Prepare vcpkg
uses: lukka/run-vcpkg@v4
with:
vcpkgArguments: opencv
vcpkgDirectory: ${{ runner.workspace }}/vcpkg/
vcpkgGitCommitId: 544f8e4593764f78faa94bac2adb81cca5232943
vcpkgTriplet: x64-windows
- name: Configure & Build
uses: lukka/run-cmake@v3
with:
buildDirectory: ${{ runner.workspace }}/build/
cmakeAppendedArgs: -DWITH_JAVA=OFF
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
useVcpkgToolchainFile: true
- name: Run Tests
run: ctest -C "Debug"
working-directory: ${{ runner.workspace }}/build/

58
.github/workflows/documentation.yml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Documentation
on: [push, workflow_dispatch]
env:
BASE_PATH: allwpilib/docs
jobs:
publish:
name: "Documentation - Publish"
runs-on: ubuntu-latest
if: github.repository_owner == 'wpilibsuite' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-java@v1
with:
java-version: 13
- name: Set environment variables (Development)
run: |
echo "TARGET_FOLDER=$BASE_PATH/development" >> $GITHUB_ENV
if: github.ref == 'refs/heads/master'
- name: Set environment variables (Tag)
run: |
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
echo "TARGET_FOLDER=$BASE_PATH/beta" >> $GITHUB_ENV
if: startsWith(github.ref, 'refs/tags/v')
- name: Set environment variables (Release)
run: |
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
echo "TARGET_FOLDER=$BASE_PATH/release" >> $GITHUB_ENV
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta')
- name: Build with Gradle
run: ./gradlew docs:generateJavaDocs docs:doxygen -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
- name: Install SSH Client 🔑
uses: webfactory/ssh-agent@v0.4.1
with:
ssh-private-key: ${{ secrets.GH_DEPLOY_KEY }}
- name: Deploy Java 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
SSH: true
REPOSITORY_NAME: wpilibsuite/wpilibsuite.github.io
BRANCH: main
CLEAN: true
FOLDER: docs/build/docs/javadoc
TARGET_FOLDER: ${{ env.TARGET_FOLDER }}/java
- name: Deploy C++ 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
SSH: true
REPOSITORY_NAME: wpilibsuite/wpilibsuite.github.io
BRANCH: main
CLEAN: true
FOLDER: docs/build/docs/doxygen/html
TARGET_FOLDER: ${{ env.TARGET_FOLDER }}/cpp

15
.github/workflows/gazebo.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Gazebo
on: [pull_request, push]
jobs:
build:
name: "Build"
runs-on: ubuntu-latest
container: wpilib/gazebo-ubuntu:18.04
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Build with Gradle
run: ./gradlew build -PbuildServer -PmakeSim -Dorg.gradle.jvmargs=-Xmx2g

View File

@@ -1,4 +1,4 @@
name: CI
name: Gradle
on: [pull_request, push]
@@ -38,6 +38,8 @@ jobs:
path: build/allOutputs
build-host:
env:
MACOSX_DEPLOYMENT_TARGET: 10.14
strategy:
fail-fast: false
matrix:
@@ -111,84 +113,6 @@ jobs:
name: Documentation
path: docs/build/outputs
build-cmake:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: Linux
container: wpilib/roborio-cross-ubuntu:2020-18.04
flags: ""
- os: macos-latest
name: macOS
container: ""
flags: "-DWITH_JAVA=OFF"
name: "Build - CMake ${{ matrix.name }}"
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
brew install opencv
fi
- name: configure
run: mkdir build && cd build && cmake -DWITH_GUI=OFF ${{ matrix.flags }} ..
- name: build
working-directory: build
run: make -j3
- name: test
working-directory: build
run: make test
build-cmake-vcpkg:
name: "Build - CMake Windows"
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Prepare vcpkg
uses: lukka/run-vcpkg@v4
with:
vcpkgArguments: opencv
vcpkgDirectory: ${{ runner.workspace }}/vcpkg/
vcpkgGitCommitId: 544f8e4593764f78faa94bac2adb81cca5232943
vcpkgTriplet: x64-windows
- name: Configure & Build
uses: lukka/run-cmake@v3
with:
buildDirectory: ${{ runner.workspace }}/build/
cmakeAppendedArgs: -DWITH_JAVA=OFF
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
useVcpkgToolchainFile: true
- name: Run Tests
run: ctest -C "Debug"
working-directory: ${{ runner.workspace }}/build/
wpiformat:
name: "wpiformat"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Fetch all history and metadata
run: |
git fetch --prune --unshallow
git checkout -b pr
git branch -f master origin/master
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install clang-format
run: sudo apt-get update -q && sudo apt-get install clang-format-10
- name: Install wpiformat
run: pip3 install wpiformat
- name: Run
run: wpiformat -clang 10
- name: Check Output
run: git --no-pager diff --exit-code HEAD
combine:
name: Combine
needs: [build-docker, build-host, build-documentation]
@@ -220,7 +144,7 @@ jobs:
github.ref == 'refs/heads/master'
run: cd combiner && ./gradlew publish -Pallwpilib
env:
RUN_AZURE_ARTIFACTORY_RELEASE: 'TRUE'
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- name: Combine (Release)
@@ -229,7 +153,7 @@ jobs:
startsWith(github.ref, 'refs/tags/v')
run: cd combiner && ./gradlew publish -Pallwpilib -PreleaseRepoPublish
env:
RUN_AZURE_ARTIFACTORY_RELEASE: 'TRUE'
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
- uses: actions/upload-artifact@v2

52
.github/workflows/lint-format.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Lint and Format
on: [pull_request]
jobs:
wpiformat:
name: "wpiformat"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Fetch all history and metadata
run: |
git fetch --prune --unshallow
git checkout -b pr
git branch -f master origin/master
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install clang-format
run: sudo apt-get update -q && sudo apt-get install -y clang-format-10
- name: Install wpiformat
run: pip3 install wpiformat
- name: Run
run: wpiformat -clang 10
- name: Check Output
run: git --no-pager diff --exit-code HEAD
tidy:
name: "clang-tidy"
runs-on: ubuntu-latest
container: wpilib/roborio-cross-ubuntu:2020-18.04
steps:
- uses: actions/checkout@v2
- name: Fetch all history and metadata
run: |
git fetch --prune --unshallow
git checkout -b pr
git branch -f master origin/master
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install clang-format and clang-tidy
run: sudo apt-get update -q && sudo apt-get install -y clang-format-10 clang-tidy-10
- name: Install wpiformat
run: pip3 install wpiformat
- name: Create compile_commands.json
run: mkdir build-cmake && cd build-cmake && cmake -DWITH_OLD_COMMANDS=ON -DWITH_EXAMPLES=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=YES ..
- name: List changed files
run: wpiformat -list-changed-files
- name: Run clang-tidy
run: wpiformat -clang 10 -no-format -tidy-changed -compile-commands=build-cmake

View File

@@ -1,6 +1,3 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) {year} FIRST. All Rights Reserved.{padding}*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

View File

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

View File

@@ -1,5 +1,5 @@
# Disable in-source builds to prevent source tree corruption.
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
if(" ${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL " ${CMAKE_CURRENT_BINARY_DIR}")
message(FATAL_ERROR "
FATAL: In-source builds are not allowed.
You should create a separate directory for build files.
@@ -9,17 +9,19 @@ endif()
project(allwpilib)
cmake_minimum_required(VERSION 3.3.0)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
set(WPILIB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
INCLUDE(CPack)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_BINARY_DIR}/jar)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/bin)
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${WPILIB_BINARY_DIR}/jar)
# use, i.e. don't skip the full RPATH for the build tree
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
@@ -44,7 +46,10 @@ ENDIF("${isSystemDir}" STREQUAL "-1")
option(BUILD_SHARED_LIBS "Build with shared libs (needed for JNI)" ON)
option(WITH_JAVA "Include java and JNI in the build" ON)
option(WITH_CSCORE "Build cscore (needs OpenCV)" ON)
option(WITH_WPILIB "Build hal, wpilibc/j, wpimath, and myRobot (needs OpenCV)" ON)
option(WITH_WPIMATH "Build wpimath" ON)
option(WITH_WPILIB "Build hal, wpilibc/j, and myRobot (needs OpenCV)" ON)
option(WITH_OLD_COMMANDS "Build old commands" OFF)
option(WITH_EXAMPLES "Build examples" OFF)
option(WITH_TESTS "Build unit tests (requires internet connection)" ON)
option(WITH_GUI "Build GUI items" ON)
option(WITH_SIMULATION_MODULES "Build simulation modules" ON)
@@ -106,6 +111,20 @@ FATAL: Cannot build simulation modules with wpilib disabled.
")
endif()
if (NOT WITH_WPIMATH AND WITH_WPILIB)
message(FATAL_ERROR "
FATAL: Cannot build wpilib without wpimath.
Enable wpimath by setting WITH_WPIMATH=ON
")
endif()
if (NOT WITH_OLD_COMMANDS AND WITH_EXAMPLES)
message(FATAL_ERROR "
FATAL: Cannot build examples with old commands disabled.
Enable old commands by setting WITH_OLD_COMMANDS=ON
")
endif()
set( wpilib_dest wpilib)
set( include_dest wpilib/include )
set( main_lib_dest wpilib/lib )
@@ -134,6 +153,8 @@ set(CAMERASERVER_DEP_REPLACE_IMPL "include(\${SELF_DIR}/cameraserver-config.cmak
set(HAL_DEP_REPLACE_IMPL "include(\${SELF_DIR}/hal-config.cmake)")
set(WPIMATH_DEP_REPLACE "include($\{SELF_DIR\}/wpimath-config.cmake)")
set(WPILIBC_DEP_REPLACE_IMPL "include(\${SELF_DIR}/wpilibc-config.cmake)")
set(WPILIBNEWCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibNewcommands-config.cmake)")
set(WPILIBOLDCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibOldcommands-config.cmake)")
else()
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
set(NTCORE_DEP_REPLACE "find_dependency(ntcore)")
@@ -142,6 +163,8 @@ set(CAMERASERVER_DEP_REPLACE_IMPL "find_dependency(cameraserver)")
set(HAL_DEP_REPLACE_IMPL "find_dependency(hal)")
set(WPIMATH_DEP_REPLACE "find_dependency(wpimath)")
set(WPILIBC_DEP_REPLACE_IMPL "find_dependency(wpilibc)")
set(WPILIBNEWCOMMANDS_DEP_REPLACE "find_dependency(wpilibNewCommands)")
set(WPILIBOLDCOMMANDS_DEP_REPLACE "find_dependency(wpilibOldCommands)")
endif()
set(FILENAME_DEP_REPLACE "get_filename_component(SELF_DIR \"$\{CMAKE_CURRENT_LIST_FILE\}\" PATH)")
@@ -156,9 +179,14 @@ endif()
add_subdirectory(wpiutil)
add_subdirectory(ntcore)
if (WITH_WPIMATH)
add_subdirectory(wpimath)
endif()
if (WITH_GUI)
add_subdirectory(imgui)
add_subdirectory(wpigui)
add_subdirectory(glass)
endif()
if (WITH_CSCORE)
@@ -170,9 +198,15 @@ if (WITH_CSCORE)
set(HAL_DEP_REPLACE ${HAL_DEP_REPLACE_IMPL})
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
add_subdirectory(hal)
add_subdirectory(wpimath)
add_subdirectory(wpilibj)
add_subdirectory(wpilibc)
add_subdirectory(wpilibNewCommands)
if (WITH_OLD_COMMANDS)
add_subdirectory(wpilibOldCommands)
endif()
if (WITH_EXAMPLES)
add_subdirectory(wpilibcExamples)
endif()
add_subdirectory(myRobot)
endif()
endif()
@@ -181,5 +215,5 @@ if (WITH_SIMULATION_MODULES AND NOT WITH_EXTERNAL_HAL)
add_subdirectory(simulation)
endif()
configure_file(wpilib-config.cmake.in ${CMAKE_BINARY_DIR}/wpilib-config.cmake )
install(FILES ${CMAKE_BINARY_DIR}/wpilib-config.cmake DESTINATION ${wpilib_config_dir})
configure_file(wpilib-config.cmake.in ${WPILIB_BINARY_DIR}/wpilib-config.cmake )
install(FILES ${WPILIB_BINARY_DIR}/wpilib-config.cmake DESTINATION ${wpilib_config_dir})

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2019 FIRST
Copyright (c) 2009-2021 FIRST and other WPILib contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -8,12 +8,12 @@ modification, are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the FIRST nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
* Neither the name of FIRST, WPILib, nor the names of other WPILib
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY FIRST AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES

View File

@@ -1,27 +1,27 @@
## Publishing Third Party Dependencies
Currently the 3rd party deps are imgui, opencv, and google test
For publishing these dependencies, the version needs to be manually updated in the publish.gradle file of their respective repository.
Then, in the azure build for the dependency you want to build for, manually start a pipeline build (As of current, this is the `Run Pipeline` button).
A variable needs to be added called `RUN_AZURE_ARTIFACTORY_RELEASE`, with a value of `true`. Then when the pipeline gets started, the final build outputs will be updated to artifactory.
To use newer versions of C++ dependencies, in `shared/config.gradle`, update the version related to the specific dependency.
For Java dependencies, there is likely a file related to the specific dependency in the shared folder. Update the version in there.
Note, changing artifact locations (This includes changing the artifact year currently, I have an issue open to change this) requires updating the `native-utils` plugin
## Publishing allwpilib
allwpilib publishes to the development repo on every push to master. To publish a release build, upload a new tag, and a release will automatically be built and published.
## Publishing desktop tools
Desktop tools publish to the development repo on every push to master. To publish a release build, upload a new tag, and a release will automatically be built and published.
## Publishing VS Code
Before publishing, make sure to update the gradlerio version in `vscode-wpilib/resources/gradle/version.txt` Also make sure the gradle wrapper version matches the wrapper required by gradlerio.
Upon pushing a tag, a release will be built, and the files will be uploaded to the releases on GitHub. For publishing to the marketplace, you need a Microsoft account and to be added as a maintainer.
## Publishing GradleRIO
Before publishing, make sure to update the version in build.gradle. Publishing must happen locally, using the command `./gradlew publishPlugin`. This does require your API key for publishing to be set.
## Building the installer
Update the GradleRIO version in gradle.properties, and in the scripts folder in vscode, update the vscode extension. Then push, it will build the installer on azure.
## Publishing Third Party Dependencies
Currently the 3rd party deps are imgui, opencv, and google test
For publishing these dependencies, the version needs to be manually updated in the publish.gradle file of their respective repository.
Then, in the azure build for the dependency you want to build for, manually start a pipeline build (As of current, this is the `Run Pipeline` button).
A variable needs to be added called `RUN_AZURE_ARTIFACTORY_RELEASE`, with a value of `true`. Then when the pipeline gets started, the final build outputs will be updated to artifactory.
To use newer versions of C++ dependencies, in `shared/config.gradle`, update the version related to the specific dependency.
For Java dependencies, there is likely a file related to the specific dependency in the shared folder. Update the version in there.
Note, changing artifact locations (This includes changing the artifact year currently, I have an issue open to change this) requires updating the `native-utils` plugin
## Publishing allwpilib
allwpilib publishes to the development repo on every push to master. To publish a release build, upload a new tag, and a release will automatically be built and published.
## Publishing desktop tools
Desktop tools publish to the development repo on every push to master. To publish a release build, upload a new tag, and a release will automatically be built and published.
## Publishing VS Code
Before publishing, make sure to update the gradlerio version in `vscode-wpilib/resources/gradle/version.txt` Also make sure the gradle wrapper version matches the wrapper required by gradlerio.
Upon pushing a tag, a release will be built, and the files will be uploaded to the releases on GitHub. For publishing to the marketplace, you need a Microsoft account and to be added as a maintainer.
## Publishing GradleRIO
Before publishing, make sure to update the version in build.gradle. Publishing must happen locally, using the command `./gradlew publishPlugin`. This does require your API key for publishing to be set.
## Building the installer
Update the GradleRIO version in gradle.properties, and in the scripts folder in vscode, update the vscode extension. Then push, it will build the installer on azure.

View File

@@ -13,6 +13,7 @@ In order to build a project using a development build, find the build.gradle fil
```groovy
wpi.maven.useDevelopment = true
wpi.wpilibVersion = 'YEAR.+'
wpi.wpimathVersion = 'YEAR.+
```
The top of your ``build.gradle`` file should now look similar to the code below. Ignore any differences in versions.
@@ -25,7 +26,8 @@ plugins {
}
wpi.maven.useDevelopment = true
wpi.wpilibVersion = '2020.+'
wpi.wpilibVersion = '2021.+'
wpi.wpimathVersion = '2021.+'
```
C++
@@ -37,7 +39,8 @@ plugins {
}
wpi.maven.useDevelopment = true
wpi.wpilibVersion = '2020.+'
wpi.wpilibVersion = '2021.+'
wpi.wpimathVersion = '2021.+'
```
## Local Build
@@ -53,6 +56,7 @@ plugins {
wpi.maven.useFrcMavenLocalDevelopment = true
wpi.wpilibVersion = 'YEAR.424242.+'
wpi.wpimathVersion = 'YEAR.424242.+'
```
C++
@@ -65,4 +69,5 @@ plugins {
wpi.maven.useFrcMavenLocalDevelopment = true
wpi.wpilibVersion = 'YEAR.424242.+'
wpi.wpimathVersion = 'YEAR.424242.+'
```

View File

@@ -35,8 +35,10 @@ The following build options are available:
* This option will build C++ unit tests. These can be run via `make test`.
* `WITH_CSCORE` (ON Default)
* This option will cause cscore to be built. Turning this off will implicitly disable cameraserver, the hal and wpilib as well, irrespective of their specific options. If this is off, the OpenCV build requirement is removed.
* `WITH_WPIMATH` (ON Default)
* This option will build the wpimath library. This option must be on to build wpilib.
* `WITH_WPILIB` (ON Default)
* This option will build the hal, wpilibc/j, and wpimath during the build. The HAL is the simulator hal, unless the external hal options are used. The cmake build has no capability to build for the RoboRIO.
* This option will build the hal and wpilibc/j during the build. The HAL is the simulator hal, unless the external hal options are used. The cmake build has no capability to build for the RoboRIO.
* `WITH_SIMULATION_MODULES` (ON Default)
* This option will build simulation modules, including wpigui and the HALSim plugins.
* `WITH_EXTERNAL_HAL` (OFF Default)
@@ -48,7 +50,7 @@ The following build options are available:
## Build Setup
The WPILib CMake build does not allow in source builds. Because the `build` directory is used by Gradle, we recommend a `buildcmake` directory in the root. This folder is included in the gitignore.
The WPILib CMake build does not allow in source builds. Because the `build` directory is used by Gradle, we recommend a `build-cmake` directory in the root. This folder is included in the gitignore.
Once you have a build folder, run CMake configuration in that build directory with the following command.

View File

@@ -1,6 +1,8 @@
# WPILib Project
![CI](https://github.com/wpilibsuite/allwpilib/workflows/CI/badge.svg)
[![C++ Documentation](https://img.shields.io/badge/documentation-c%2B%2B-blue)](https://first.wpi.edu/wpilib/allwpilib/docs/development/cpp/)
[![Java Documentation](https://img.shields.io/badge/documentation-java-orange)](https://first.wpi.edu/wpilib/allwpilib/docs/development/java/)
Welcome to the WPILib project. This repository contains the HAL, WPILibJ, and WPILibC projects. These are the core libraries for creating robot programs for the roboRIO.
@@ -31,16 +33,23 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
## Requirements
- [JDK 11](https://adoptopenjdk.net/)
- Note that the JRE is insufficient; the full JDK is required
- On Ubuntu, run `sudo apt install openjdk-11-jdk`
- On Windows, install the JDK 11 .msi from the link above
- On macOS, install the JDK 11 .pkg from the link above
- C++ compiler
- On Linux, install GCC
- On Linux, install GCC 7 or greater
- On Windows, install [Visual Studio Community 2019](https://visualstudio.microsoft.com/vs/community/) and select the C++ programming language during installation (Gradle can't use the build tools for Visual Studio 2019)
- On macOS, install the Xcode command-line build tools via `xcode-select --install`
- [ARM compiler toolchain](https://github.com/wpilibsuite/roborio-toolchain/releases)
- For 2020 and beyond, use GCC version 7 or greater
- ARM compiler toolchain
- Run `./gradlew installRoboRioToolchain` after cloning this repository
- If the WPILib installer was used, this toolchain is already installed
- Raspberry Pi toolchain (optional)
- Run `./gradlew installRaspbianToolchain` after cloning this repository
## Setup
Clone the WPILib repository. If the toolchains are not installed, install them, and make sure they are available on the system PATH.
Clone the WPILib repository and follow the instructions above for installing any required tooling.
See the [styleguide README](https://github.com/wpilibsuite/styleguide/blob/master/README.md) for wpiformat setup instructions.

View File

@@ -845,3 +845,14 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=====================
Portable File Dialogs
=====================
Copyright © 2018—2020 Sam Hocevar <sam@hocevar.net>
This library is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What the **** You Want
to Public License, Version 2, as published by the WTFPL Task Force.
See http://www.wtfpl.net/ for more details.

View File

@@ -4,88 +4,88 @@ trigger:
batch: true
branches:
include:
- master
- master
stages:
- stage: Build
jobs:
- job: IntegrationTests
displayName: Integration Tests
pool:
vmImage: 'Ubuntu 16.04'
- stage: Build
jobs:
- job: IntegrationTests
displayName: Integration Tests
pool:
vmImage: "Ubuntu 16.04"
container:
image: wpilib/roborio-cross-ubuntu:2021-18.04
container:
image: wpilib/roborio-cross-ubuntu:2021-18.04
timeoutInMinutes: 0
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'
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'
- 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'
- 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: 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'
- 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'
- 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: 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'
- task: PublishTestResults@2
displayName: Publish Java Test Results
inputs:
testResultsFormat: "JUnit"
testResultsFiles: "*.xml"
testRunTitle: "Java Test Report"
searchFolder: "$(System.DefaultWorkingDirectory)/test-reports"

View File

@@ -2,7 +2,7 @@ import edu.wpi.first.toolchain.*
plugins {
id 'base'
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.0.2'
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.1.0'
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'
@@ -11,17 +11,11 @@ plugins {
id 'visual-studio'
id 'net.ltgt.errorprone' version '1.1.1' apply false
id 'com.github.johnrengelman.shadow' version '5.2.0' apply false
id 'com.diffplug.spotless' version '5.5.0'
}
if (project.hasProperty('buildServer')) {
wpilibVersioning.buildServerMode = true
wpilibVersioning.useAllTags = true
}
if (project.hasProperty('releaseMode')) {
wpilibVersioning.releaseMode = true
wpilibVersioning.useAllTags = true
}
wpilibVersioning.buildServerMode = project.hasProperty('buildServer')
wpilibVersioning.releaseMode = project.hasProperty('releaseMode')
allprojects {
repositories {
@@ -117,8 +111,12 @@ subprojects {
String path = task.getLinkedFile().getAsFile().get().getAbsolutePath()
exec {
workingDir rootDir
def args = ["sh", "-c", "codesign --force --strict --timestamp --options=runtime " +
"--verbose -s ${project.findProperty("developerID")} ${path}"]
def args = [
"sh",
"-c",
"codesign --force --strict --timestamp --options=runtime " +
"--verbose -s ${project.findProperty("developerID")} ${path}"
]
commandLine args
}
}
@@ -131,6 +129,49 @@ ext.getCurrentArch = {
return NativePlatforms.desktop
}
spotless {
java {
target fileTree('.') {
include '**/*.java'
exclude '**/build/**', '**/build-*/**'
}
toggleOffOn()
googleJavaFormat()
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
}
groovyGradle {
target fileTree('.') {
include '**/*.gradle'
exclude '**/build/**', '**/build-*/**'
}
greclipse()
indentWithSpaces(4)
trimTrailingWhitespace()
endWithNewline()
}
format 'xml', {
target fileTree('.') {
include '**/*.xml'
exclude '**/build/**', '**/build-*/**'
}
eclipseWtp('xml')
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
format 'misc', {
target fileTree('.') {
include '**/*.md', '**/.gitignore'
exclude '**/build/**', '**/build-*/**'
}
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
}
wrapper {
gradleVersion = '6.0.1'
}

View File

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

View File

@@ -6,6 +6,8 @@ import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.tasks.Delete
import org.gradle.api.GradleException;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
@@ -87,6 +89,14 @@ class SingleNativeBuild implements Plugin<Project> {
subs << component
}
}
Delete deleteObjects = null
if (project.hasProperty('buildServer')) {
deleteObjects = project.tasks.create('deleteObjects', Delete)
project.tasks.named('build').configure { Task t ->
t.dependsOn deleteObjects
return
}
}
subs.each {
((NativeLibrarySpec) it).binaries.each { oBinary ->
if (oBinary.buildable == false) {
@@ -136,6 +146,10 @@ class SingleNativeBuild implements Plugin<Project> {
tree.include '**/*.o'
tree.include '**/*.obj'
link.source tree
if (project.hasProperty('buildServer')) {
deleteObjects.dependsOn link
deleteObjects.delete tree
}
} else if (binary instanceof StaticLibraryBinarySpec) {
def sBinary = (StaticLibraryBinarySpec) binary
ObjectFilesToBinary assemble = (ObjectFilesToBinary) sBinary.tasks.createStaticLib
@@ -145,6 +159,10 @@ class SingleNativeBuild implements Plugin<Project> {
tree.include '**/*.o'
tree.include '**/*.obj'
assemble.source tree
if (project.hasProperty('buildServer')) {
deleteObjects.dependsOn assemble
deleteObjects.delete tree
}
}
}
}

View File

@@ -53,8 +53,8 @@ else()
set (cameraserver_config_dir share/cameraserver)
endif()
configure_file(cameraserver-config.cmake.in ${CMAKE_BINARY_DIR}/cameraserver-config.cmake )
install(FILES ${CMAKE_BINARY_DIR}/cameraserver-config.cmake DESTINATION ${cameraserver_config_dir})
configure_file(cameraserver-config.cmake.in ${WPILIB_BINARY_DIR}/cameraserver-config.cmake )
install(FILES ${WPILIB_BINARY_DIR}/cameraserver-config.cmake DESTINATION ${cameraserver_config_dir})
install(EXPORT cameraserver DESTINATION ${cameraserver_config_dir})
file(GLOB multiCameraServer_src multiCameraServer/src/main/native/cpp/*.cpp)

View File

@@ -20,9 +20,9 @@ dependencies {
ext {
sharedCvConfigs = [cameraserver : [],
cameraserverBase: [],
cameraserverDev : [],
cameraserverTest: []]
cameraserverBase: [],
cameraserverDev : [],
cameraserverTest: []]
staticCvConfigs = [:]
useJava = true
useCpp = true
@@ -32,14 +32,32 @@ apply from: "${rootDir}/shared/opencv.gradle"
nativeUtils.exportsConfigs {
cameraserver {
x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
x86ExcludeSymbols = [
'_CT??_R0?AV_System_error',
'_CT??_R0?AVexception',
'_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error',
'_CT??_R0?AVsystem_error',
'_CTA5?AVfailure',
'_TI5?AVfailure',
'_CT??_R0?AVout_of_range',
'_CTA3?AVout_of_range',
'_TI3?AVout_of_range',
'_CT??_R0?AVbad_cast'
]
x64ExcludeSymbols = [
'_CT??_R0?AV_System_error',
'_CT??_R0?AVexception',
'_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error',
'_CT??_R0?AVsystem_error',
'_CTA5?AVfailure',
'_TI5?AVfailure',
'_CT??_R0?AVout_of_range',
'_CTA3?AVout_of_range',
'_TI3?AVout_of_range',
'_CT??_R0?AVbad_cast'
]
}
}

View File

@@ -52,10 +52,10 @@ model {
}
}
binaries.all { binary ->
lib project: ':cameraserver', library: 'cameraserver', linkage: 'static'
lib project: ':ntcore', library: 'ntcore', linkage: 'static'
lib project: ':cscore', library: 'cscore', linkage: 'static'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
lib project: ':cameraserver', library: 'cameraserver', linkage: 'static'
lib project: ':ntcore', library: 'ntcore', linkage: 'static'
lib project: ':cscore', library: 'cscore', linkage: 'static'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
}
}
}

View File

@@ -1,55 +1,50 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import edu.wpi.cscore.VideoSource;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.networktables.NetworkTableInstance;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
/*
JSON format:
{
"team": <team number>,
"ntmode": <"client" or "server", "client" if unspecified>
"cameras": [
{
"name": <camera name>
"path": <path, e.g. "/dev/video0">
"pixel format": <"MJPEG", "YUYV", etc> // optional
"width": <video mode width> // optional
"height": <video mode height> // optional
"fps": <video mode fps> // optional
"brightness": <percentage brightness> // optional
"white balance": <"auto", "hold", value> // optional
"exposure": <"auto", "hold", value> // optional
"properties": [ // optional
{
"name": <property name>
"value": <property value>
}
]
}
]
}
*/
JSON format:
{
"team": <team number>,
"ntmode": <"client" or "server", "client" if unspecified>
"cameras": [
{
"name": <camera name>
"path": <path, e.g. "/dev/video0">
"pixel format": <"MJPEG", "YUYV", etc> // optional
"width": <video mode width> // optional
"height": <video mode height> // optional
"fps": <video mode fps> // optional
"brightness": <percentage brightness> // optional
"white balance": <"auto", "hold", value> // optional
"exposure": <"auto", "hold", value> // optional
"properties": [ // optional
{
"name": <property name>
"value": <property value>
}
]
}
]
}
*/
public final class Main {
private static String configFile = "/boot/frc.json";
@@ -65,19 +60,14 @@ public final class Main {
public static boolean server;
public static List<CameraConfig> cameras = new ArrayList<>();
private Main() {
}
private Main() {}
/**
* Report parse error.
*/
/** Report parse error. */
public static void parseError(String str) {
System.err.println("config error in '" + configFile + "': " + str);
}
/**
* Read single camera configuration.
*/
/** Read single camera configuration. */
public static boolean readCameraConfig(JsonObject config) {
CameraConfig cam = new CameraConfig();
@@ -103,9 +93,7 @@ public final class Main {
return true;
}
/**
* Read configuration file.
*/
/** Read configuration file. */
@SuppressWarnings("PMD.CyclomaticComplexity")
public static boolean readConfig() {
// parse file
@@ -160,22 +148,17 @@ public final class Main {
return true;
}
/**
* Start running the camera.
*/
/** Start running the camera. */
public static void startCamera(CameraConfig config) {
System.out.println("Starting camera '" + config.name + "' on " + config.path);
VideoSource camera = CameraServer.getInstance().startAutomaticCapture(
config.name, config.path);
VideoSource camera = CameraServer.getInstance().startAutomaticCapture(config.name, config.path);
Gson gson = new GsonBuilder().create();
camera.setConfigJson(gson.toJson(config.config));
}
/**
* Main.
*/
/** Main. */
public static void main(String... args) {
if (args.length > 0) {
configFile = args[0];
@@ -202,7 +185,7 @@ public final class Main {
}
// loop forever
for (;;) {
for (; ; ) {
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <cstdio>
#include <string>
@@ -146,7 +143,9 @@ bool ReadConfig() {
// cameras
try {
for (auto&& camera : j.at("cameras")) {
if (!ReadCameraConfig(camera)) return false;
if (!ReadCameraConfig(camera)) {
return false;
}
}
} catch (const wpi::json::exception& e) {
ParseError() << "could not read cameras: " << e.what() << '\n';
@@ -167,10 +166,14 @@ void StartCamera(const CameraConfig& config) {
} // namespace
int main(int argc, char* argv[]) {
if (argc >= 2) configFile = argv[1];
if (argc >= 2) {
configFile = argv[1];
}
// read configuration
if (!ReadConfig()) return EXIT_FAILURE;
if (!ReadConfig()) {
return EXIT_FAILURE;
}
// start NetworkTables
auto ntinst = nt::NetworkTableInstance::GetDefault();
@@ -183,8 +186,12 @@ int main(int argc, char* argv[]) {
}
// start cameras
for (auto&& camera : cameras) StartCamera(camera);
for (auto&& camera : cameras) {
StartCamera(camera);
}
// loop forever
for (;;) std::this_thread::sleep_for(std::chrono::seconds(10));
for (;;) {
std::this_thread::sleep_for(std::chrono::seconds(10));
}
}

View File

@@ -1,17 +1,11 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.cameraserver;
public final class DevMain {
public static void main(String[] args) {
public static void main(String[] args) {}
}
private DevMain() {
}
private DevMain() {}
}

View File

@@ -1,8 +1,5 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
int main() {}

View File

@@ -1,19 +1,9 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.cameraserver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import edu.wpi.cscore.AxisCamera;
import edu.wpi.cscore.CameraServerJNI;
import edu.wpi.cscore.CvSink;
@@ -32,27 +22,28 @@ import edu.wpi.first.networktables.EntryListenerFlags;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Singleton class for creating and keeping camera servers.
* Also publishes camera information to NetworkTables.
* Singleton class for creating and keeping camera servers. Also publishes camera information to
* NetworkTables.
*/
public final class CameraServer {
public static final int kBasePort = 1181;
@Deprecated
public static final int kSize640x480 = 0;
@Deprecated
public static final int kSize320x240 = 1;
@Deprecated
public static final int kSize160x120 = 2;
@Deprecated public static final int kSize640x480 = 0;
@Deprecated public static final int kSize320x240 = 1;
@Deprecated public static final int kSize160x120 = 2;
private static final String kPublishName = "/CameraPublisher";
private static CameraServer server;
/**
* Get the CameraServer instance.
*/
/** Get the CameraServer instance. */
public static synchronized CameraServer getInstance() {
if (server == null) {
server = new CameraServer();
@@ -64,28 +55,29 @@ public final class CameraServer {
private String m_primarySourceName;
private final Map<String, VideoSource> m_sources;
private final Map<String, VideoSink> m_sinks;
private final Map<Integer, NetworkTable> m_tables; // indexed by source handle
private final Map<Integer, NetworkTable> m_tables; // indexed by source handle
// source handle indexed by sink handle
private final Map<Integer, Integer> m_fixedSources;
private final NetworkTable m_publishTable;
private final VideoListener m_videoListener; //NOPMD
private final int m_tableListener; //NOPMD
private final VideoListener m_videoListener; // NOPMD
private final int m_tableListener; // NOPMD
private int m_nextPort;
private String[] m_addresses;
@SuppressWarnings("JavadocMethod")
@SuppressWarnings("MissingJavadocMethod")
private static String makeSourceValue(int source) {
switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
case kUsb:
return "usb:" + CameraServerJNI.getUsbCameraPath(source);
case kHttp: {
String[] urls = CameraServerJNI.getHttpCameraUrls(source);
if (urls.length > 0) {
return "ip:" + urls[0];
} else {
return "ip:";
case kHttp:
{
String[] urls = CameraServerJNI.getHttpCameraUrls(source);
if (urls.length > 0) {
return "ip:" + urls[0];
} else {
return "ip:";
}
}
}
case kCv:
return "cv:";
default:
@@ -93,12 +85,12 @@ public final class CameraServer {
}
}
@SuppressWarnings("JavadocMethod")
@SuppressWarnings("MissingJavadocMethod")
private static String makeStreamValue(String address, int port) {
return "mjpg:http://" + address + ":" + port + "/?action=stream";
}
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
@SuppressWarnings({"MissingJavadocMethod", "PMD.AvoidUsingHardCodedIP"})
private synchronized String[] getSinkStreamValues(int sink) {
// Ignore all but MjpegServer
if (VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) != VideoSink.Kind.kMjpeg) {
@@ -119,7 +111,7 @@ public final class CameraServer {
values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
for (String addr : m_addresses) {
if ("127.0.0.1".equals(addr)) {
continue; // ignore localhost
continue; // ignore localhost
}
values.add(makeStreamValue(addr, port));
}
@@ -128,11 +120,11 @@ public final class CameraServer {
return values.toArray(new String[0]);
}
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
@SuppressWarnings({"MissingJavadocMethod", "PMD.AvoidUsingHardCodedIP"})
private synchronized String[] getSourceStreamValues(int source) {
// Ignore all but HttpCamera
if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
!= VideoSource.Kind.kHttp) {
!= VideoSource.Kind.kHttp) {
return new String[0];
}
@@ -150,7 +142,7 @@ public final class CameraServer {
int sinkSource = CameraServerJNI.getSinkSource(sink);
if (source == sinkSource
&& VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink))
== VideoSink.Kind.kMjpeg) {
== VideoSink.Kind.kMjpeg) {
// Add USB-only passthrough
String[] finalValues = Arrays.copyOf(values, values.length + 1);
int port = CameraServerJNI.getMjpegServerPort(sink);
@@ -163,15 +155,20 @@ public final class CameraServer {
return values;
}
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP", "PMD.CyclomaticComplexity"})
@SuppressWarnings({
"MissingJavadocMethod",
"PMD.AvoidUsingHardCodedIP",
"PMD.CyclomaticComplexity"
})
private synchronized void updateStreamValues() {
// Over all the sinks...
for (VideoSink i : m_sinks.values()) {
int sink = i.getHandle();
// Get the source's subtable (if none exists, we're done)
int source = Objects.requireNonNullElseGet(m_fixedSources.get(sink),
() -> CameraServerJNI.getSinkSource(sink));
int source =
Objects.requireNonNullElseGet(
m_fixedSources.get(sink), () -> CameraServerJNI.getSinkSource(sink));
if (source == 0) {
continue;
@@ -208,7 +205,7 @@ public final class CameraServer {
}
}
@SuppressWarnings("JavadocMethod")
@SuppressWarnings("MissingJavadocMethod")
private static String pixelFormatToString(PixelFormat pixelFormat) {
switch (pixelFormat) {
case kMJPEG:
@@ -228,13 +225,19 @@ public final class CameraServer {
/// Provide string description of video mode.
/// The returned string is "{width}x{height} {format} {fps} fps".
@SuppressWarnings("JavadocMethod")
@SuppressWarnings("MissingJavadocMethod")
private static String videoModeToString(VideoMode mode) {
return mode.width + "x" + mode.height + " " + pixelFormatToString(mode.pixelFormat)
+ " " + mode.fps + " fps";
return mode.width
+ "x"
+ mode.height
+ " "
+ pixelFormatToString(mode.pixelFormat)
+ " "
+ mode.fps
+ " fps";
}
@SuppressWarnings("JavadocMethod")
@SuppressWarnings("MissingJavadocMethod")
private static String[] getSourceModeValues(int sourceHandle) {
VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
String[] modeStrings = new String[modes.length];
@@ -244,7 +247,7 @@ public final class CameraServer {
return modeStrings;
}
@SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
@SuppressWarnings({"MissingJavadocMethod", "PMD.CyclomaticComplexity"})
private static void putSourcePropertyValue(NetworkTable table, VideoEvent event, boolean isNew) {
String name;
String infoName;
@@ -270,14 +273,18 @@ public final class CameraServer {
case kEnum:
if (isNew) {
entry.setDefaultDouble(event.value);
table.getEntry(infoName + "/min").setDouble(
CameraServerJNI.getPropertyMin(event.propertyHandle));
table.getEntry(infoName + "/max").setDouble(
CameraServerJNI.getPropertyMax(event.propertyHandle));
table.getEntry(infoName + "/step").setDouble(
CameraServerJNI.getPropertyStep(event.propertyHandle));
table.getEntry(infoName + "/default").setDouble(
CameraServerJNI.getPropertyDefault(event.propertyHandle));
table
.getEntry(infoName + "/min")
.setDouble(CameraServerJNI.getPropertyMin(event.propertyHandle));
table
.getEntry(infoName + "/max")
.setDouble(CameraServerJNI.getPropertyMax(event.propertyHandle));
table
.getEntry(infoName + "/step")
.setDouble(CameraServerJNI.getPropertyStep(event.propertyHandle));
table
.getEntry(infoName + "/default")
.setDouble(CameraServerJNI.getPropertyDefault(event.propertyHandle));
} else {
entry.setDouble(event.value);
}
@@ -297,8 +304,12 @@ public final class CameraServer {
}
}
@SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable", "PMD.ExcessiveMethodLength",
"PMD.NPathComplexity"})
@SuppressWarnings({
"MissingJavadocMethod",
"PMD.UnusedLocalVariable",
"PMD.ExcessiveMethodLength",
"PMD.NPathComplexity"
})
private CameraServer() {
m_defaultUsbDevice = new AtomicInteger();
m_sources = new HashMap<>();
@@ -321,176 +332,204 @@ public final class CameraServer {
// - "PropertyInfo/{Property}" - Property supporting information
// Listener for video events
m_videoListener = new VideoListener(event -> {
switch (event.kind) {
case kSourceCreated: {
// Create subtable for the camera
NetworkTable table = m_publishTable.getSubTable(event.name);
m_tables.put(event.sourceHandle, table);
table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
table.getEntry("description").setString(
CameraServerJNI.getSourceDescription(event.sourceHandle));
table.getEntry("connected").setBoolean(
CameraServerJNI.isSourceConnected(event.sourceHandle));
table.getEntry("streams").setStringArray(getSourceStreamValues(event.sourceHandle));
try {
VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
table.getEntry("mode").setDefaultString(videoModeToString(mode));
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
} catch (VideoException ignored) {
// Do nothing. Let the other event handlers update this if there is an error.
}
break;
}
case kSourceDestroyed: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("source").setString("");
table.getEntry("streams").setStringArray(new String[0]);
table.getEntry("modes").setStringArray(new String[0]);
}
break;
}
case kSourceConnected: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
// update the description too (as it may have changed)
table.getEntry("description").setString(
CameraServerJNI.getSourceDescription(event.sourceHandle));
table.getEntry("connected").setBoolean(true);
}
break;
}
case kSourceDisconnected: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("connected").setBoolean(false);
}
break;
}
case kSourceVideoModesUpdated: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
}
break;
}
case kSourceVideoModeChanged: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("mode").setString(videoModeToString(event.mode));
}
break;
}
case kSourcePropertyCreated: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
putSourcePropertyValue(table, event, true);
}
break;
}
case kSourcePropertyValueUpdated: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
putSourcePropertyValue(table, event, false);
}
break;
}
case kSourcePropertyChoicesUpdated: {
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
try {
String[] choices = CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
table.getEntry("PropertyInfo/" + event.name + "/choices").setStringArray(choices);
} catch (VideoException ignored) {
// ignore
}
}
break;
}
case kSinkSourceChanged:
case kSinkCreated:
case kSinkDestroyed:
case kNetworkInterfacesChanged: {
m_addresses = CameraServerJNI.getNetworkInterfaces();
updateStreamValues();
break;
}
default:
break;
}
}, 0x4fff, true);
m_videoListener =
new VideoListener(
event -> {
switch (event.kind) {
case kSourceCreated:
{
// Create subtable for the camera
NetworkTable table = m_publishTable.getSubTable(event.name);
m_tables.put(event.sourceHandle, table);
table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
table
.getEntry("description")
.setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
table
.getEntry("connected")
.setBoolean(CameraServerJNI.isSourceConnected(event.sourceHandle));
table
.getEntry("streams")
.setStringArray(getSourceStreamValues(event.sourceHandle));
try {
VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
table.getEntry("mode").setDefaultString(videoModeToString(mode));
table
.getEntry("modes")
.setStringArray(getSourceModeValues(event.sourceHandle));
} catch (VideoException ignored) {
// Do nothing. Let the other event handlers update this if there is an error.
}
break;
}
case kSourceDestroyed:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("source").setString("");
table.getEntry("streams").setStringArray(new String[0]);
table.getEntry("modes").setStringArray(new String[0]);
}
break;
}
case kSourceConnected:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
// update the description too (as it may have changed)
table
.getEntry("description")
.setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
table.getEntry("connected").setBoolean(true);
}
break;
}
case kSourceDisconnected:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("connected").setBoolean(false);
}
break;
}
case kSourceVideoModesUpdated:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table
.getEntry("modes")
.setStringArray(getSourceModeValues(event.sourceHandle));
}
break;
}
case kSourceVideoModeChanged:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
table.getEntry("mode").setString(videoModeToString(event.mode));
}
break;
}
case kSourcePropertyCreated:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
putSourcePropertyValue(table, event, true);
}
break;
}
case kSourcePropertyValueUpdated:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
putSourcePropertyValue(table, event, false);
}
break;
}
case kSourcePropertyChoicesUpdated:
{
NetworkTable table = m_tables.get(event.sourceHandle);
if (table != null) {
try {
String[] choices =
CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
table
.getEntry("PropertyInfo/" + event.name + "/choices")
.setStringArray(choices);
} catch (VideoException ignored) {
// ignore
}
}
break;
}
case kSinkSourceChanged:
case kSinkCreated:
case kSinkDestroyed:
case kNetworkInterfacesChanged:
{
m_addresses = CameraServerJNI.getNetworkInterfaces();
updateStreamValues();
break;
}
default:
break;
}
},
0x4fff,
true);
// Listener for NetworkTable events
// We don't currently support changing settings via NT due to
// synchronization issues, so just update to current setting if someone
// else tries to change it.
m_tableListener = NetworkTableInstance.getDefault().addEntryListener(kPublishName + "/",
event -> {
String relativeKey = event.name.substring(kPublishName.length() + 1);
m_tableListener =
NetworkTableInstance.getDefault()
.addEntryListener(
kPublishName + "/",
event -> {
String relativeKey = event.name.substring(kPublishName.length() + 1);
// get source (sourceName/...)
int subKeyIndex = relativeKey.indexOf('/');
if (subKeyIndex == -1) {
return;
}
String sourceName = relativeKey.substring(0, subKeyIndex);
VideoSource source = m_sources.get(sourceName);
if (source == null) {
return;
}
// get source (sourceName/...)
int subKeyIndex = relativeKey.indexOf('/');
if (subKeyIndex == -1) {
return;
}
String sourceName = relativeKey.substring(0, subKeyIndex);
VideoSource source = m_sources.get(sourceName);
if (source == null) {
return;
}
// get subkey
relativeKey = relativeKey.substring(subKeyIndex + 1);
// get subkey
relativeKey = relativeKey.substring(subKeyIndex + 1);
// handle standard names
String propName;
if ("mode".equals(relativeKey)) {
// reset to current mode
event.getEntry().setString(videoModeToString(source.getVideoMode()));
return;
} else if (relativeKey.startsWith("Property/")) {
propName = relativeKey.substring(9);
} else if (relativeKey.startsWith("RawProperty/")) {
propName = relativeKey.substring(12);
} else {
return; // ignore
}
// handle standard names
String propName;
if ("mode".equals(relativeKey)) {
// reset to current mode
event.getEntry().setString(videoModeToString(source.getVideoMode()));
return;
} else if (relativeKey.startsWith("Property/")) {
propName = relativeKey.substring(9);
} else if (relativeKey.startsWith("RawProperty/")) {
propName = relativeKey.substring(12);
} else {
return; // ignore
}
// everything else is a property
VideoProperty property = source.getProperty(propName);
switch (property.getKind()) {
case kNone:
return;
case kBoolean:
// reset to current setting
event.getEntry().setBoolean(property.get() != 0);
return;
case kInteger:
case kEnum:
// reset to current setting
event.getEntry().setDouble(property.get());
return;
case kString:
// reset to current setting
event.getEntry().setString(property.getString());
return;
default:
return;
}
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
// everything else is a property
VideoProperty property = source.getProperty(propName);
switch (property.getKind()) {
case kNone:
return;
case kBoolean:
// reset to current setting
event.getEntry().setBoolean(property.get() != 0);
return;
case kInteger:
case kEnum:
// reset to current setting
event.getEntry().setDouble(property.get());
return;
case kString:
// reset to current setting
event.getEntry().setString(property.getString());
return;
default:
return;
}
},
EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
}
/**
* Start automatically capturing images to send to the dashboard.
*
* <p>You should call this method to see a camera feed on the dashboard.
* If you also want to perform vision processing on the roboRIO, use
* getVideo() to get access to the camera images.
* <p>You should call this method to see a camera feed on the dashboard. If you also want to
* perform vision processing on the roboRIO, use getVideo() to get access to the camera images.
*
* <p>The first time this overload is called, it calls
* {@link #startAutomaticCapture(int)} with device 0, creating a camera
* named "USB Camera 0". Subsequent calls increment the device number
* <p>The first time this overload is called, it calls {@link #startAutomaticCapture(int)} with
* device 0, creating a camera named "USB Camera 0". Subsequent calls increment the device number
* (e.g. 1, 2, etc).
*/
public UsbCamera startAutomaticCapture() {
@@ -502,8 +541,8 @@ public final class CameraServer {
/**
* Start automatically capturing images to send to the dashboard.
*
* <p>This overload calls {@link #startAutomaticCapture(String, int)} with
* a name of "USB Camera {dev}".
* <p>This overload calls {@link #startAutomaticCapture(String, int)} with a name of "USB Camera
* {dev}".
*
* @param dev The device number of the camera interface
*/
@@ -541,8 +580,7 @@ public final class CameraServer {
}
/**
* Start automatically capturing images to send to the dashboard from
* an existing camera.
* Start automatically capturing images to send to the dashboard from an existing camera.
*
* @param camera Camera
*/
@@ -556,8 +594,7 @@ public final class CameraServer {
/**
* Adds an Axis IP camera.
*
* <p>This overload calls {@link #addAxisCamera(String, String)} with
* name "Axis Camera".
* <p>This overload calls {@link #addAxisCamera(String, String)} with name "Axis Camera".
*
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
*/
@@ -568,8 +605,7 @@ public final class CameraServer {
/**
* Adds an Axis IP camera.
*
* <p>This overload calls {@link #addAxisCamera(String, String[])} with
* name "Axis Camera".
* <p>This overload calls {@link #addAxisCamera(String, String[])} with name "Axis Camera".
*
* @param hosts Array of Camera host IPs/DNS names
*/
@@ -606,10 +642,9 @@ public final class CameraServer {
}
/**
* Adds a virtual camera for switching between two streams. Unlike the
* other addCamera methods, this returns a VideoSink rather than a
* VideoSource. Calling setSource() on the returned object can be used
* to switch the actual source of the stream.
* Adds a virtual camera for switching between two streams. Unlike the other addCamera methods,
* this returns a VideoSink rather than a VideoSource. Calling setSource() on the returned object
* can be used to switch the actual source of the stream.
*/
public MjpegServer addSwitchedCamera(String name) {
// create a dummy CvSource
@@ -623,11 +658,11 @@ public final class CameraServer {
}
/**
* Get OpenCV access to the primary camera feed. This allows you to
* get images from the camera for image processing on the roboRIO.
* Get OpenCV access to the primary camera feed. This allows you to get images from the camera for
* image processing on the roboRIO.
*
* <p>This is only valid to call after a camera feed has been added
* with startAutomaticCapture() or addServer().
* <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
* or addServer().
*/
public CvSink getVideo() {
VideoSource source;
@@ -644,8 +679,8 @@ public final class CameraServer {
}
/**
* Get OpenCV access to the specified camera. This allows you to get
* images from the camera for image processing on the roboRIO.
* Get OpenCV access to the specified camera. This allows you to get images from the camera for
* image processing on the roboRIO.
*
* @param camera Camera (e.g. as returned by startAutomaticCapture).
*/
@@ -670,8 +705,8 @@ public final class CameraServer {
}
/**
* Get OpenCV access to the specified camera. This allows you to get
* images from the camera for image processing on the roboRIO.
* Get OpenCV access to the specified camera. This allows you to get images from the camera for
* image processing on the roboRIO.
*
* @param name Camera name
*/
@@ -687,8 +722,8 @@ public final class CameraServer {
}
/**
* Create a MJPEG stream with OpenCV input. This can be called to pass custom
* annotated images to the dashboard.
* Create a MJPEG stream with OpenCV input. This can be called to pass custom annotated images to
* the dashboard.
*
* @param name Name to give the stream
* @param width Width of the image being sent
@@ -750,8 +785,8 @@ public final class CameraServer {
/**
* Get server for the primary camera feed.
*
* <p>This is only valid to call after a camera feed has been added
* with startAutomaticCapture() or addServer().
* <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
* or addServer().
*/
public VideoSink getServer() {
synchronized (this) {

View File

@@ -1,13 +1,9 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.cameraserver;
public interface CameraServerShared {
/**
* get the main thread id func.

View File

@@ -1,57 +1,42 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.cameraserver;
public final class CameraServerSharedStore {
private static CameraServerShared cameraServerShared;
private CameraServerSharedStore() {
}
private CameraServerSharedStore() {}
/**
* get the CameraServerShared object.
*/
/** get the CameraServerShared object. */
public static synchronized CameraServerShared getCameraServerShared() {
if (cameraServerShared == null) {
cameraServerShared = new CameraServerShared() {
cameraServerShared =
new CameraServerShared() {
@Override
public void reportVideoServer(int id) {
@Override
public void reportVideoServer(int id) {}
}
@Override
public void reportUsbCamera(int id) {}
@Override
public void reportUsbCamera(int id) {
@Override
public void reportDriverStationError(String error) {}
}
@Override
public void reportAxisCamera(int id) {}
@Override
public void reportDriverStationError(String error) {
}
@Override
public void reportAxisCamera(int id) {
}
@Override
public Long getRobotMainThreadId() {
return null;
}
};
@Override
public Long getRobotMainThreadId() {
return null;
}
};
}
return cameraServerShared;
}
/**
* set the CameraServerShared object.
*/
/** set the CameraServerShared object. */
public static synchronized void setCameraServerShared(CameraServerShared shared) {
cameraServerShared = shared;
}

View File

@@ -1,26 +1,22 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.vision;
import org.opencv.core.Mat;
/**
* A vision pipeline is responsible for running a group of
* OpenCV algorithms to extract data from an image.
* A vision pipeline is responsible for running a group of OpenCV algorithms to extract data from an
* image.
*
* @see VisionRunner
* @see VisionThread
*/
public interface VisionPipeline {
/**
* Processes the image input and sets the result objects.
* Implementations should make these objects accessible.
* Processes the image input and sets the result objects. Implementations should make these
* objects accessible.
*/
void process(Mat image);
}

View File

@@ -1,22 +1,18 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.vision;
import org.opencv.core.Mat;
import edu.wpi.cscore.CvSink;
import edu.wpi.cscore.VideoSource;
import edu.wpi.first.cameraserver.CameraServerSharedStore;
import org.opencv.core.Mat;
/**
* A vision runner is a convenient wrapper object to make it easy to run vision pipelines
* from robot code. The easiest way to use this is to run it in a {@link VisionThread}
* and use the listener to take snapshots of the pipeline's outputs.
* A vision runner is a convenient wrapper object to make it easy to run vision pipelines from robot
* code. The easiest way to use this is to run it in a {@link VisionThread} and use the listener to
* take snapshots of the pipeline's outputs.
*
* @see VisionPipeline
* @see VisionThread
@@ -45,17 +41,16 @@ public class VisionRunner<P extends VisionPipeline> {
* @param pipeline the vision pipeline that ran
*/
void copyPipelineOutputs(P pipeline);
}
/**
* Creates a new vision runner. It will take images from the {@code videoSource}, send them to
* the {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert
* user code when it is safe to access the pipeline's outputs.
* Creates a new vision runner. It will take images from the {@code videoSource}, send them to the
* {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert user
* code when it is safe to access the pipeline's outputs.
*
* @param videoSource the video source to use to supply images for the pipeline
* @param pipeline the vision pipeline to run
* @param listener a function to call after the pipeline has finished running
* @param pipeline the vision pipeline to run
* @param listener a function to call after the pipeline has finished running
*/
public VisionRunner(VideoSource videoSource, P pipeline, Listener<? super P> listener) {
this.m_pipeline = pipeline;
@@ -64,15 +59,15 @@ public class VisionRunner<P extends VisionPipeline> {
}
/**
* Runs the pipeline one time, giving it the next image from the video source specified
* in the constructor. This will block until the source either has an image or throws an error.
* If the source successfully supplied a frame, the pipeline's image input will be set,
* the pipeline will run, and the listener specified in the constructor will be called to notify
* it that the pipeline ran.
* Runs the pipeline one time, giving it the next image from the video source specified in the
* constructor. This will block until the source either has an image or throws an error. If the
* source successfully supplied a frame, the pipeline's image input will be set, the pipeline will
* run, and the listener specified in the constructor will be called to notify it that the
* pipeline ran.
*
* <p>This method is exposed to allow teams to add additional functionality or have their own
* ways to run the pipeline. Most teams, however, should just use {@link #runForever} in its own
* thread using a {@link VisionThread}.</p>
* <p>This method is exposed to allow teams to add additional functionality or have their own ways
* to run the pipeline. Most teams, however, should just use {@link #runForever} in its own thread
* using a {@link VisionThread}.
*/
public void runOnce() {
Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
@@ -98,11 +93,11 @@ public class VisionRunner<P extends VisionPipeline> {
}
/**
* A convenience method that calls {@link #runOnce()} in an infinite loop. This must
* be run in a dedicated thread, and cannot be used in the main robot thread because
* it will freeze the robot program.
* A convenience method that calls {@link #runOnce()} in an infinite loop. This must be run in a
* dedicated thread, and cannot be used in the main robot thread because it will freeze the robot
* program.
*
* <p><strong>Do not call this method directly from the main thread.</strong></p>
* <p><strong>Do not call this method directly from the main thread.</strong>
*
* @throws IllegalStateException if this is called from the main robot thread
* @see VisionThread
@@ -119,9 +114,7 @@ public class VisionRunner<P extends VisionPipeline> {
}
}
/**
* Stop a RunForever() loop.
*/
/** Stop a RunForever() loop. */
public void stop() {
m_enabled = false;
}

View File

@@ -1,18 +1,15 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.vision;
import edu.wpi.cscore.VideoSource;
/**
* A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread;
* it does not prevent the program from exiting when all other non-daemon threads
* have finished running.
* A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread; it
* does not prevent the program from exiting when all other non-daemon threads have finished
* running.
*
* @see VisionPipeline
* @see VisionRunner
@@ -34,14 +31,12 @@ public class VisionThread extends Thread {
* equivalent to {@code new VisionThread(new VisionRunner<>(videoSource, pipeline, listener))}.
*
* @param videoSource the source for images the pipeline should process
* @param pipeline the pipeline to run
* @param listener the listener to copy outputs from the pipeline after it runs
* @param <P> the type of the pipeline
* @param pipeline the pipeline to run
* @param listener the listener to copy outputs from the pipeline after it runs
* @param <P> the type of the pipeline
*/
public <P extends VisionPipeline> VisionThread(VideoSource videoSource,
P pipeline,
VisionRunner.Listener<? super P> listener) {
public <P extends VisionPipeline> VisionThread(
VideoSource videoSource, P pipeline, VisionRunner.Listener<? super P> listener) {
this(new VisionRunner<>(videoSource, pipeline, listener));
}
}

View File

@@ -1,16 +1,13 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
/**
* Classes in the {@code edu.wpi.first.vision} package are designed to
* simplify using OpenCV vision processing code from a robot program.
* Classes in the {@code edu.wpi.first.vision} package are designed to simplify using OpenCV vision
* processing code from a robot program.
*
* <p>An example use case for grabbing a yellow tote from 2015 in autonomous: <br>
*
* <p>An example use case for grabbing a yellow tote from 2015 in autonomous:
* <br>
* <pre><code>
* public class Robot extends IterativeRobot
* implements VisionRunner.Listener&lt;MyFindTotePipeline&gt; {

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "cameraserver/CameraServer.h"
@@ -40,7 +37,8 @@ struct CameraServer::Impl {
wpi::StringMap<cs::VideoSink> m_sinks;
wpi::DenseMap<CS_Sink, CS_Source> m_fixedSources;
wpi::DenseMap<CS_Source, std::shared_ptr<nt::NetworkTable>> m_tables;
std::shared_ptr<nt::NetworkTable> m_publishTable;
std::shared_ptr<nt::NetworkTable> m_publishTable{
nt::NetworkTableInstance::GetDefault().GetTable(kPublishName)};
cs::VideoListener m_videoListener;
int m_tableListener;
int m_nextPort;
@@ -74,7 +72,9 @@ static wpi::StringRef MakeSourceValue(CS_Source source,
wpi::StringRef prefix{"ip:"};
buf.append(prefix.begin(), prefix.end());
auto urls = cs::GetHttpCameraUrls(source, &status);
if (!urls.empty()) buf.append(urls[0].begin(), urls[0].end());
if (!urls.empty()) {
buf.append(urls[0].begin(), urls[0].end());
}
break;
}
case CS_SOURCE_CV:
@@ -102,8 +102,9 @@ std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
CS_Status status = 0;
// Ignore all but MjpegServer
if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG)
return std::vector<std::string>{};
if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG) {
return {};
}
// Get port
int port = cs::GetMjpegServerPort(sink, &status);
@@ -119,7 +120,9 @@ std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
values.emplace_back(MakeStreamValue(cs::GetHostname() + ".local", port));
for (const auto& addr : m_addresses) {
if (addr == "127.0.0.1") continue; // ignore localhost
if (addr == "127.0.0.1") {
continue; // ignore localhost
}
values.emplace_back(MakeStreamValue(addr, port));
}
}
@@ -132,12 +135,15 @@ std::vector<std::string> CameraServer::Impl::GetSourceStreamValues(
CS_Status status = 0;
// Ignore all but HttpCamera
if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP)
return std::vector<std::string>{};
if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP) {
return {};
}
// Generate values
auto values = cs::GetHttpCameraUrls(source, &status);
for (auto& value : values) value = "mjpg:" + value;
for (auto& value : values) {
value = "mjpg:" + value;
}
#ifdef __FRC_ROBORIO__
// Look to see if we have a passthrough server for this source
@@ -168,16 +174,24 @@ void CameraServer::Impl::UpdateStreamValues() {
// Get the source's subtable (if none exists, we're done)
CS_Source source = m_fixedSources.lookup(sink);
if (source == 0) source = cs::GetSinkSource(sink, &status);
if (source == 0) continue;
if (source == 0) {
source = cs::GetSinkSource(sink, &status);
}
if (source == 0) {
continue;
}
auto table = m_tables.lookup(source);
if (table) {
// Don't set stream values if this is a HttpCamera passthrough
if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) continue;
if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) {
continue;
}
// Set table value
auto values = GetSinkStreamValues(sink);
if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
if (!values.empty()) {
table->GetEntry("streams").SetStringArray(values);
}
}
}
@@ -190,7 +204,9 @@ void CameraServer::Impl::UpdateStreamValues() {
if (table) {
// Set table value
auto values = GetSourceStreamValues(source);
if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
if (!values.empty()) {
table->GetEntry("streams").SetStringArray(values);
}
}
}
}
@@ -224,8 +240,9 @@ static std::string VideoModeToString(const cs::VideoMode& mode) {
static std::vector<std::string> GetSourceModeValues(int source) {
std::vector<std::string> rv;
CS_Status status = 0;
for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status))
for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status)) {
rv.emplace_back(VideoModeToString(mode));
}
return rv;
}
@@ -250,10 +267,11 @@ static void PutSourcePropertyValue(nt::NetworkTable* table,
nt::NetworkTableEntry entry = table->GetEntry(name);
switch (event.propertyKind) {
case CS_PROP_BOOLEAN:
if (isNew)
if (isNew) {
entry.SetDefaultBoolean(event.value != 0);
else
} else {
entry.SetBoolean(event.value != 0);
}
break;
case CS_PROP_INTEGER:
case CS_PROP_ENUM:
@@ -272,20 +290,18 @@ static void PutSourcePropertyValue(nt::NetworkTable* table,
}
break;
case CS_PROP_STRING:
if (isNew)
if (isNew) {
entry.SetDefaultString(event.valueStr);
else
} else {
entry.SetString(event.valueStr);
}
break;
default:
break;
}
}
CameraServer::Impl::Impl()
: m_publishTable{nt::NetworkTableInstance::GetDefault().GetTable(
kPublishName)},
m_nextPort(kBasePort) {
CameraServer::Impl::Impl() : m_nextPort(kBasePort) {
// We publish sources to NetworkTables using the following structure:
// "/CameraPublisher/{Source.Name}/" - root
// - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
@@ -351,30 +367,38 @@ CameraServer::Impl::Impl()
}
case cs::VideoEvent::kSourceDisconnected: {
auto table = GetSourceTable(event.sourceHandle);
if (table) table->GetEntry("connected").SetBoolean(false);
if (table) {
table->GetEntry("connected").SetBoolean(false);
}
break;
}
case cs::VideoEvent::kSourceVideoModesUpdated: {
auto table = GetSourceTable(event.sourceHandle);
if (table)
if (table) {
table->GetEntry("modes").SetStringArray(
GetSourceModeValues(event.sourceHandle));
}
break;
}
case cs::VideoEvent::kSourceVideoModeChanged: {
auto table = GetSourceTable(event.sourceHandle);
if (table)
if (table) {
table->GetEntry("mode").SetString(VideoModeToString(event.mode));
}
break;
}
case cs::VideoEvent::kSourcePropertyCreated: {
auto table = GetSourceTable(event.sourceHandle);
if (table) PutSourcePropertyValue(table.get(), event, true);
if (table) {
PutSourcePropertyValue(table.get(), event, true);
}
break;
}
case cs::VideoEvent::kSourcePropertyValueUpdated: {
auto table = GetSourceTable(event.sourceHandle);
if (table) PutSourcePropertyValue(table.get(), event, false);
if (table) {
PutSourcePropertyValue(table.get(), event, false);
}
break;
}
case cs::VideoEvent::kSourcePropertyChoicesUpdated: {
@@ -416,10 +440,14 @@ CameraServer::Impl::Impl()
// get source (sourceName/...)
auto subKeyIndex = relativeKey.find('/');
if (subKeyIndex == wpi::StringRef::npos) return;
if (subKeyIndex == wpi::StringRef::npos) {
return;
}
wpi::StringRef sourceName = relativeKey.slice(0, subKeyIndex);
auto sourceIt = m_sources.find(sourceName);
if (sourceIt == m_sources.end()) return;
if (sourceIt == m_sources.end()) {
return;
}
// get subkey
relativeKey = relativeKey.substr(subKeyIndex + 1);
@@ -463,7 +491,7 @@ CameraServer::Impl::Impl()
CameraServer::CameraServer() : m_impl(new Impl) {}
CameraServer::~CameraServer() {}
CameraServer::~CameraServer() = default;
cs::UsbCamera CameraServer::StartAutomaticCapture() {
cs::UsbCamera camera = StartAutomaticCapture(m_impl->m_defaultUsbDevice++);
@@ -692,7 +720,9 @@ cs::VideoSink CameraServer::GetServer(const wpi::Twine& name) {
void CameraServer::AddCamera(const cs::VideoSource& camera) {
std::string name = camera.GetName();
std::scoped_lock lock(m_impl->m_mutex);
if (m_impl->m_primarySourceName.empty()) m_impl->m_primarySourceName = name;
if (m_impl->m_primarySourceName.empty()) {
m_impl->m_primarySourceName = name;
}
m_impl->m_sources.try_emplace(name, camera);
}
@@ -704,13 +734,18 @@ void CameraServer::RemoveCamera(const wpi::Twine& name) {
void CameraServer::SetSize(int size) {
std::scoped_lock lock(m_impl->m_mutex);
if (m_impl->m_primarySourceName.empty()) return;
if (m_impl->m_primarySourceName.empty()) {
return;
}
auto it = m_impl->m_sources.find(m_impl->m_primarySourceName);
if (it == m_impl->m_sources.end()) return;
if (size == kSize160x120)
if (it == m_impl->m_sources.end()) {
return;
}
if (size == kSize160x120) {
it->second.SetResolution(160, 120);
else if (size == kSize320x240)
} else if (size == kSize320x240) {
it->second.SetResolution(320, 240);
else if (size == kSize640x480)
} else if (size == kSize640x480) {
it->second.SetResolution(640, 480);
}
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "cameraserver/CameraServerShared.h"

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "vision/VisionRunner.h"
@@ -23,7 +20,7 @@ VisionRunnerBase::VisionRunnerBase(cs::VideoSource videoSource)
}
// Located here and not in header due to cv::Mat forward declaration.
VisionRunnerBase::~VisionRunnerBase() {}
VisionRunnerBase::~VisionRunnerBase() = default;
void VisionRunnerBase::RunOnce() {
auto csShared = frc::GetCameraServerShared();
@@ -56,4 +53,6 @@ void VisionRunnerBase::RunForever() {
}
}
void VisionRunnerBase::Stop() { m_enabled = false; }
void VisionRunnerBase::Stop() {
m_enabled = false;
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once

View File

@@ -1,15 +1,14 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include <string>
#include <vector>
#include "cameraserver/CameraServer.h"
namespace frc {
template <typename T>
@@ -23,7 +22,9 @@ inline cs::AxisCamera CameraServer::AddAxisCamera(
const wpi::Twine& name, std::initializer_list<T> hosts) {
std::vector<std::string> vec;
vec.reserve(hosts.size());
for (const auto& host : hosts) vec.emplace_back(host);
for (const auto& host : hosts) {
vec.emplace_back(host);
}
return AddAxisCamera(name, vec);
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once

View File

@@ -1,12 +1,11 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#pragma once
#include "vision/VisionRunner.h"
namespace frc {
/**

View File

@@ -1,8 +1,7 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
int main() { return 0; }
int main() {
return 0;
}

View File

@@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 2.8)
# load settings in case of "try compile"
set(TOOLCHAIN_CONFIG_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
set(TOOLCHAIN_CONFIG_FILE "${WPILIB_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
get_property(__IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
if(__IN_TRY_COMPILE)
include("${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake" OPTIONAL) # CMAKE_BINARY_DIR is different
include("${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake" OPTIONAL) # WPILIB_BINARY_DIR is different
macro(toolchain_save_config)
# nothing
endmacro()

View File

@@ -46,8 +46,8 @@ else()
set (cscore_config_dir share/cscore)
endif()
configure_file(cscore-config.cmake.in ${CMAKE_BINARY_DIR}/cscore-config.cmake )
install(FILES ${CMAKE_BINARY_DIR}/cscore-config.cmake DESTINATION ${cscore_config_dir})
configure_file(cscore-config.cmake.in ${WPILIB_BINARY_DIR}/cscore-config.cmake )
install(FILES ${WPILIB_BINARY_DIR}/cscore-config.cmake DESTINATION ${cscore_config_dir})
install(EXPORT cscore DESTINATION ${cscore_config_dir})
SUBDIR_LIST(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")

View File

@@ -60,12 +60,12 @@ model {
ext {
sharedCvConfigs = [cscore : [],
cscoreBase: [],
cscoreDev : [],
cscoreTest: [],
cscoreJNIShared: []]
cscoreBase: [],
cscoreDev : [],
cscoreTest: [],
cscoreJNIShared: []]
staticCvConfigs = [cscoreJNI: [],
cscoreJNICvStatic: []]
cscoreJNICvStatic: []]
useJava = true
useCpp = true
cvStaticBuild = true
@@ -127,27 +127,45 @@ def examplesMap = [:];
File examplesTree = file("$projectDir/examples")
examplesTree.list(new FilenameFilter() {
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
}).each {
sharedCvConfigs.put(it, [])
examplesMap.put(it, [])
}
@Override
public boolean accept(File current, String name) {
return new File(current, name).isDirectory();
}
}).each {
sharedCvConfigs.put(it, [])
examplesMap.put(it, [])
}
apply from: "${rootDir}/shared/opencv.gradle"
nativeUtils.exportsConfigs {
cscore {
x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
x86ExcludeSymbols = [
'_CT??_R0?AV_System_error',
'_CT??_R0?AVexception',
'_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error',
'_CT??_R0?AVsystem_error',
'_CTA5?AVfailure',
'_TI5?AVfailure',
'_CT??_R0?AVout_of_range',
'_CTA3?AVout_of_range',
'_TI3?AVout_of_range',
'_CT??_R0?AVbad_cast'
]
x64ExcludeSymbols = [
'_CT??_R0?AV_System_error',
'_CT??_R0?AVexception',
'_CT??_R0?AVfailure',
'_CT??_R0?AVruntime_error',
'_CT??_R0?AVsystem_error',
'_CTA5?AVfailure',
'_TI5?AVfailure',
'_CT??_R0?AVout_of_range',
'_CTA3?AVout_of_range',
'_TI3?AVout_of_range',
'_CT??_R0?AVbad_cast'
]
}
cscoreJNI {
x86SymbolFilter = { symbols ->

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <wpi/SmallString.h>
#include <wpi/raw_ostream.h>
@@ -19,8 +16,9 @@ int main() {
<< ")\n";
if (!caminfo.otherPaths.empty()) {
wpi::outs() << "Other device paths:\n";
for (auto&& path : caminfo.otherPaths)
for (auto&& path : caminfo.otherPaths) {
wpi::outs() << " " << path << '\n';
}
}
cs::UsbCamera camera{"usbcam", caminfo.dev};
@@ -48,7 +46,9 @@ int main() {
<< "value=" << prop.Get();
auto choices = prop.GetChoices();
for (size_t i = 0; i < choices.size(); ++i) {
if (choices[i].empty()) continue;
if (choices[i].empty()) {
continue;
}
wpi::outs() << "\n " << i << ": " << choices[i];
}
break;

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <cstdio>
#include <iostream>

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <chrono>
#include <thread>
@@ -37,18 +34,22 @@ int main(int argc, char** argv) {
} else {
wpi::StringRef propVal{argv[arg]};
int intVal;
if (propVal.getAsInteger(10, intVal))
if (propVal.getAsInteger(10, intVal)) {
camera.GetProperty(propName).SetString(propVal);
else
} else {
camera.GetProperty(propName).Set(intVal);
}
propName = wpi::StringRef{};
}
}
if (arg < argc && wpi::StringRef{argv[arg]} == "--") ++arg;
if (arg < argc && wpi::StringRef{argv[arg]} == "--") {
++arg;
}
// Wait to connect
while (!camera.IsConnected())
while (!camera.IsConnected()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// Set rest
propName = wpi::StringRef{};
@@ -58,10 +59,11 @@ int main(int argc, char** argv) {
} else {
wpi::StringRef propVal{argv[arg]};
int intVal;
if (propVal.getAsInteger(10, intVal))
if (propVal.getAsInteger(10, intVal)) {
camera.GetProperty(propName).SetString(propVal);
else
} else {
camera.GetProperty(propName).Set(intVal);
}
propName = wpi::StringRef{};
}
}
@@ -91,7 +93,9 @@ int main(int argc, char** argv) {
<< "value=" << prop.Get();
auto choices = prop.GetChoices();
for (size_t i = 0; i < choices.size(); ++i) {
if (choices[i].empty()) continue;
if (choices[i].empty()) {
continue;
}
wpi::outs() << "\n " << i << ": " << choices[i];
}
break;

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <cstdio>
#include <iostream>

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2017-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <cstdio>
@@ -14,8 +11,9 @@
int main() {
wpi::outs() << "hostname: " << cs::GetHostname() << '\n';
wpi::outs() << "IPv4 network addresses:\n";
for (const auto& addr : cs::GetNetworkInterfaces())
for (const auto& addr : cs::GetNetworkInterfaces()) {
wpi::outs() << " " << addr << '\n';
}
cs::UsbCamera camera{"usbcam", 0};
camera.SetVideoMode(cs::VideoMode::kMJPEG, 320, 240, 30);
cs::MjpegServer mjpegServer{"httpserver", 8081};

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <atomic>
#include <thread>
@@ -53,7 +50,9 @@ int main() {
} else {
{
std::scoped_lock lock(sharedFreeListMutex);
for (auto mat : sharedFreeList) sourceFreeList.emplace_back(mat);
for (auto mat : sharedFreeList) {
sourceFreeList.emplace_back(mat);
}
sharedFreeList.clear();
}
if (!sourceFreeList.empty()) {
@@ -71,7 +70,9 @@ int main() {
auto prev = latestFrame.exchange(out);
// put prev on free list
if (prev) sourceFreeList.emplace_back(prev);
if (prev) {
sourceFreeList.emplace_back(prev);
}
}
});

View File

@@ -1,19 +1,14 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import java.nio.ByteBuffer;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import edu.wpi.cscore.VideoMode.PixelFormat;
import edu.wpi.cscore.raw.RawFrame;
import java.nio.ByteBuffer;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
public class RawCVMatSink extends ImageSink {
RawFrame frame = new RawFrame();
@@ -27,26 +22,25 @@ public class RawCVMatSink extends ImageSink {
private int getCVFormat(PixelFormat pixelFormat) {
int type = 0;
switch (pixelFormat) {
case kYUYV:
case kRGB565:
type = CvType.CV_8UC2;
break;
case kBGR:
type = CvType.CV_8UC3;
break;
case kGray:
case kMJPEG:
default:
type = CvType.CV_8UC1;
break;
case kYUYV:
case kRGB565:
type = CvType.CV_8UC2;
break;
case kBGR:
type = CvType.CV_8UC3;
break;
case kGray:
case kMJPEG:
default:
type = CvType.CV_8UC1;
break;
}
return type;
}
/**
* Create a sink for accepting OpenCV images.
* WaitForFrame() must be called on the created sink to get each new
* image.
* Create a sink for accepting OpenCV images. WaitForFrame() must be called on the created sink to
* get each new image.
*
* @param name Source name (arbitrary unique identifier)
*/
@@ -55,24 +49,21 @@ public class RawCVMatSink extends ImageSink {
}
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after 0.225 seconds.
* The provided image will have three 3-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after 0.225 seconds. The
* provided image will have three 3-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message)
* @return Frame time, or 0 on error (call GetError() to obtain the error message)
*/
public long grabFrame(Mat image) {
return grabFrame(image, 0.225);
}
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 3-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after timeout seconds. The
* provided image will have three 3-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in 1 us increments.
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
* is in 1 us increments.
*/
public long grabFrame(Mat image, double timeout) {
frame.setWidth(0);
@@ -83,12 +74,20 @@ public class RawCVMatSink extends ImageSink {
return rv;
}
if (frame.getDataByteBuffer() != origByteBuffer || width != frame.getWidth() || height != frame.getHeight() || pixelFormat != frame.getPixelFormat()) {
if (frame.getDataByteBuffer() != origByteBuffer
|| width != frame.getWidth()
|| height != frame.getHeight()
|| pixelFormat != frame.getPixelFormat()) {
origByteBuffer = frame.getDataByteBuffer();
height = frame.getHeight();
width = frame.getWidth();
pixelFormat = frame.getPixelFormat();
tmpMat = new Mat(frame.getHeight(), frame.getWidth(), getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)), origByteBuffer);
tmpMat =
new Mat(
frame.getHeight(),
frame.getWidth(),
getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)),
origByteBuffer);
}
tmpMat.copyTo(image);
return rv;

View File

@@ -1,15 +1,11 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import org.opencv.core.Mat;
import edu.wpi.cscore.VideoMode.PixelFormat;
import org.opencv.core.Mat;
public class RawCVMatSource extends ImageSource {
/**
@@ -19,11 +15,9 @@ public class RawCVMatSource extends ImageSource {
* @param mode Video mode being generated
*/
public RawCVMatSource(String name, VideoMode mode) {
super(CameraServerJNI.createRawSource(name,
mode.pixelFormat.getValue(),
mode.width,
mode.height,
mode.fps));
super(
CameraServerJNI.createRawSource(
name, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
}
/**
@@ -35,16 +29,17 @@ public class RawCVMatSource extends ImageSource {
* @param height height
* @param fps fps
*/
public RawCVMatSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
public RawCVMatSource(
String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
super(CameraServerJNI.createRawSource(name, pixelFormat.getValue(), width, height, fps));
}
/**
* Put an OpenCV image and notify sinks.
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* Mat.convertTo() and/or cvtColor() to convert it first.
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images are supported. If the
* format, depth or channel order is different, use Mat.convertTo() and/or cvtColor() to convert
* it first.
*
* @param image OpenCV image
*/
@@ -54,6 +49,12 @@ public class RawCVMatSource extends ImageSource {
throw new VideoException("Unsupported Image Type");
}
int imgType = channels == 1 ? PixelFormat.kGray.getValue() : PixelFormat.kBGR.getValue();
CameraServerJNI.putRawSourceFrame(m_handle, image.dataAddr(), image.width(), image.height(), imgType, (int)image.total() * channels);
CameraServerJNI.putRawSourceFrame(
m_handle,
image.dataAddr(),
image.width(),
image.height(),
imgType,
(int) image.total() * channels);
}
}

View File

@@ -1,24 +1,18 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import edu.wpi.first.wpiutil.RuntimeDetector;
public final class DevMain {
/**
* Main method.
*/
/** Main method. */
public static void main(String[] args) {
System.out.println("Hello World!");
System.out.println(RuntimeDetector.getPlatformPath());
System.out.println(CameraServerJNI.getHostname());
}
private DevMain() {
}
private DevMain() {}
}

View File

@@ -1,12 +1,11 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <iostream>
#include "cscore.h"
int main() { std::cout << cs::GetHostname() << std::endl; }
int main() {
std::cout << cs::GetHostname() << std::endl;
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source that represents an Axis IP camera.
*/
/** A source that represents an Axis IP camera. */
public class AxisCamera extends HttpCamera {
private static String hostToUrl(String host) {
return "http://" + host + "/mjpg/video.mjpg";

View File

@@ -1,19 +1,14 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import edu.wpi.first.wpiutil.RuntimeLoader;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.opencv.core.Core;
import edu.wpi.first.wpiutil.RuntimeLoader;
public class CameraServerCvJNI {
static boolean libraryLoaded = false;
@@ -36,7 +31,8 @@ public class CameraServerCvJNI {
if (Helper.getExtractOnStaticLoad()) {
try {
CameraServerJNI.forceLoad();
loader = new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
loader =
new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
loader.loadLibraryHashed();
} catch (IOException ex) {
ex.printStackTrace();
@@ -46,27 +42,29 @@ public class CameraServerCvJNI {
}
}
/**
* Force load the library.
*/
/** Force load the library. */
public static synchronized void forceLoad() throws IOException {
if (libraryLoaded) {
return;
}
CameraServerJNI.forceLoad();
loader = new RuntimeLoader<>(Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
loader =
new RuntimeLoader<>(
Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
loader.loadLibrary();
libraryLoaded = true;
}
public static native int createCvSource(String name, int pixelFormat, int width, int height, int fps);
public static native int createCvSource(
String name, int pixelFormat, int width, int height, int fps);
public static native void putSourceFrame(int source, long imageNativeObj);
public static native int createCvSink(String name);
//public static native int createCvSinkCallback(String name,
// public static native int createCvSinkCallback(String name,
// void (*processFrame)(long time));
public static native long grabSinkFrame(int sink, long imageNativeObj);
public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
}

View File

@@ -1,20 +1,16 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import edu.wpi.cscore.raw.RawFrame;
import edu.wpi.first.wpiutil.RuntimeLoader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import edu.wpi.cscore.raw.RawFrame;
import edu.wpi.first.wpiutil.RuntimeLoader;
public class CameraServerJNI {
static boolean libraryLoaded = false;
@@ -35,7 +31,9 @@ public class CameraServerJNI {
static {
if (Helper.getExtractOnStaticLoad()) {
try {
loader = new RuntimeLoader<>("cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
loader =
new RuntimeLoader<>(
"cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
loader.loadLibrary();
} catch (IOException ex) {
ex.printStackTrace();
@@ -45,14 +43,14 @@ public class CameraServerJNI {
}
}
/**
* Force load the library.
*/
/** Force load the library. */
public static synchronized void forceLoad() throws IOException {
if (libraryLoaded) {
return;
}
loader = new RuntimeLoader<>("cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
loader =
new RuntimeLoader<>(
"cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
loader.loadLibrary();
libraryLoaded = true;
}
@@ -61,89 +59,159 @@ public class CameraServerJNI {
// Property Functions
//
public static native int getPropertyKind(int property);
public static native String getPropertyName(int property);
public static native int getProperty(int property);
public static native void setProperty(int property, int value);
public static native int getPropertyMin(int property);
public static native int getPropertyMax(int property);
public static native int getPropertyStep(int property);
public static native int getPropertyDefault(int property);
public static native String getStringProperty(int property);
public static native void setStringProperty(int property, String value);
public static native String[] getEnumPropertyChoices(int property);
//
// Source Creation Functions
//
public static native int createUsbCameraDev(String name, int dev);
public static native int createUsbCameraPath(String name, String path);
public static native int createHttpCamera(String name, String url, int kind);
public static native int createHttpCameraMulti(String name, String[] urls, int kind);
public static native int createRawSource(String name, int pixelFormat, int width, int height, int fps);
public static native int createRawSource(
String name, int pixelFormat, int width, int height, int fps);
//
// Source Functions
//
public static native int getSourceKind(int source);
public static native String getSourceName(int source);
public static native String getSourceDescription(int source);
public static native long getSourceLastFrameTime(int source);
public static native void setSourceConnectionStrategy(int source, int strategy);
public static native boolean isSourceConnected(int source);
public static native boolean isSourceEnabled(int source);
public static native int getSourceProperty(int source, String name);
public static native int[] enumerateSourceProperties(int source);
public static native VideoMode getSourceVideoMode(int source);
public static native boolean setSourceVideoMode(int source, int pixelFormat, int width, int height, int fps);
public static native boolean setSourceVideoMode(
int source, int pixelFormat, int width, int height, int fps);
public static native boolean setSourcePixelFormat(int source, int pixelFormat);
public static native boolean setSourceResolution(int source, int width, int height);
public static native boolean setSourceFPS(int source, int fps);
public static native boolean setSourceConfigJson(int source, String config);
public static native String getSourceConfigJson(int source);
public static native VideoMode[] enumerateSourceVideoModes(int source);
public static native int[] enumerateSourceSinks(int source);
public static native int copySource(int source);
public static native void releaseSource(int source);
//
// Camera Source Common Property Fuctions
//
public static native void setCameraBrightness(int source, int brightness);
public static native int getCameraBrightness(int source);
public static native void setCameraWhiteBalanceAuto(int source);
public static native void setCameraWhiteBalanceHoldCurrent(int source);
public static native void setCameraWhiteBalanceManual(int source, int value);
public static native void setCameraExposureAuto(int source);
public static native void setCameraExposureHoldCurrent(int source);
public static native void setCameraExposureManual(int source, int value);
//
// UsbCamera Source Functions
//
public static native void setUsbCameraPath(int source, String path);
public static native String getUsbCameraPath(int source);
public static native UsbCameraInfo getUsbCameraInfo(int source);
//
// HttpCamera Source Functions
//
public static native int getHttpCameraKind(int source);
public static native void setHttpCameraUrls(int source, String[] urls);
public static native String[] getHttpCameraUrls(int source);
//
// Image Source Functions
//
public static native void putRawSourceFrameBB(int source, ByteBuffer data, int width, int height, int pixelFormat, int totalData);
public static native void putRawSourceFrame(int source, long data, int width, int height, int pixelFormat, int totalData);
public static native void putRawSourceFrameBB(
int source, ByteBuffer data, int width, int height, int pixelFormat, int totalData);
public static native void putRawSourceFrame(
int source, long data, int width, int height, int pixelFormat, int totalData);
public static void putRawSourceFrame(int source, RawFrame raw) {
putRawSourceFrame(source, raw.getDataPtr(), raw.getWidth(), raw.getHeight(), raw.getPixelFormat(), raw.getTotalData());
putRawSourceFrame(
source,
raw.getDataPtr(),
raw.getWidth(),
raw.getHeight(),
raw.getPixelFormat(),
raw.getTotalData());
}
public static native void notifySourceError(int source, String msg);
public static native void setSourceConnected(int source, boolean connected);
public static native void setSourceDescription(int source, String description);
public static native int createSourceProperty(int source, String name, int kind, int minimum, int maximum, int step, int defaultValue, int value);
public static native void setSourceEnumPropertyChoices(int source, int property, String[] choices);
public static native int createSourceProperty(
int source,
String name,
int kind,
int minimum,
int maximum,
int step,
int defaultValue,
int value);
public static native void setSourceEnumPropertyChoices(
int source, int property, String[] choices);
//
// Sink Creation Functions
@@ -156,22 +224,34 @@ public class CameraServerJNI {
// Sink Functions
//
public static native int getSinkKind(int sink);
public static native String getSinkName(int sink);
public static native String getSinkDescription(int sink);
public static native int getSinkProperty(int sink, String name);
public static native int[] enumerateSinkProperties(int sink);
public static native boolean setSinkConfigJson(int sink, String config);
public static native String getSinkConfigJson(int sink);
public static native void setSinkSource(int sink, int source);
public static native int getSinkSourceProperty(int sink, String name);
public static native int getSinkSource(int sink);
public static native int copySink(int sink);
public static native void releaseSink(int sink);
//
// MjpegServer Sink Functions
//
public static native String getMjpegServerListenAddress(int sink);
public static native int getMjpegServerPort(int sink);
//
@@ -179,23 +259,57 @@ public class CameraServerJNI {
//
public static native void setSinkDescription(int sink, String description);
private static native long grabRawSinkFrameImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat);
private static native long grabRawSinkFrameTimeoutImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat, double timeout);
private static native long grabRawSinkFrameImpl(
int sink,
RawFrame rawFrame,
long rawFramePtr,
ByteBuffer byteBuffer,
int width,
int height,
int pixelFormat);
private static native long grabRawSinkFrameTimeoutImpl(
int sink,
RawFrame rawFrame,
long rawFramePtr,
ByteBuffer byteBuffer,
int width,
int height,
int pixelFormat,
double timeout);
public static long grabSinkFrame(int sink, RawFrame rawFrame) {
return grabRawSinkFrameImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat());
return grabRawSinkFrameImpl(
sink,
rawFrame,
rawFrame.getFramePtr(),
rawFrame.getDataByteBuffer(),
rawFrame.getWidth(),
rawFrame.getHeight(),
rawFrame.getPixelFormat());
}
public static long grabSinkFrameTimeout(int sink, RawFrame rawFrame, double timeout) {
return grabRawSinkFrameTimeoutImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat(), timeout);
return grabRawSinkFrameTimeoutImpl(
sink,
rawFrame,
rawFrame.getFramePtr(),
rawFrame.getDataByteBuffer(),
rawFrame.getWidth(),
rawFrame.getHeight(),
rawFrame.getPixelFormat(),
timeout);
}
public static native String getSinkError(int sink);
public static native void setSinkEnabled(int sink, boolean enabled);
//
// Listener Functions
//
public static native int addListener(Consumer<VideoEvent> listener,
int eventMask, boolean immediateNotify);
public static native int addListener(
Consumer<VideoEvent> listener, int eventMask, boolean immediateNotify);
public static native void removeListener(int handle);
@@ -206,7 +320,6 @@ public class CameraServerJNI {
kSourceBytesReceived(1),
kSourceFramesReceived(2);
@SuppressWarnings("MemberName")
private final int value;
TelemetryKind(int value) {
@@ -217,13 +330,19 @@ public class CameraServerJNI {
return value;
}
}
public static native void setTelemetryPeriod(double seconds);
public static native double getTelemetryElapsedTime();
public static native long getTelemetryValue(int handle, int kind);
public static long getTelemetryValue(int handle, TelemetryKind kind) {
return getTelemetryValue(handle, kind.getValue());
}
public static native double getTelemetryAverageValue(int handle, int kind);
public static double getTelemetryAverageValue(int handle, TelemetryKind kind) {
return getTelemetryAverageValue(handle, kind.getValue());
}
@@ -235,6 +354,7 @@ public class CameraServerJNI {
public interface LoggerFunction {
void apply(int level, String file, int line, String msg);
}
public static native void setLogger(LoggerFunction func, int minLevel);
//

View File

@@ -1,25 +1,19 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import org.opencv.core.Mat;
/**
* A sink for user code to accept video frames as OpenCV images.
* These sinks require the WPILib OpenCV builds.
* For an alternate OpenCV, see the documentation how to build your own
* with RawSink.
* A sink for user code to accept video frames as OpenCV images. These sinks require the WPILib
* OpenCV builds. For an alternate OpenCV, see the documentation how to build your own with RawSink.
*/
public class CvSink extends ImageSink {
/**
* Create a sink for accepting OpenCV images.
* WaitForFrame() must be called on the created sink to get each new
* image.
* Create a sink for accepting OpenCV images. WaitForFrame() must be called on the created sink to
* get each new image.
*
* @param name Source name (arbitrary unique identifier)
*/
@@ -35,41 +29,38 @@ public class CvSink extends ImageSink {
/// time=0 if an error occurred. processFrame should call GetImage()
/// or GetError() as needed, but should not call (except in very
/// unusual circumstances) WaitForImage().
//public CvSink(wpi::StringRef name,
// public CvSink(wpi::StringRef name,
// std::function<void(uint64_t time)> processFrame) {
// super(CameraServerJNI.createCvSinkCallback(name, processFrame));
//}
// }
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after 0.225 seconds.
* The provided image will have three 3-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after 0.225 seconds. The
* provided image will have three 3-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message)
* @return Frame time, or 0 on error (call GetError() to obtain the error message)
*/
public long grabFrame(Mat image) {
return grabFrame(image, 0.225);
}
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 3-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after timeout seconds. The
* provided image will have three 3-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in 1 us increments.
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
* is in 1 us increments.
*/
public long grabFrame(Mat image, double timeout) {
return CameraServerCvJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
}
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 3-bit channels stored in BGR order.
* Wait for the next frame and get the image. May block forever. The provided image will have
* three 3-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call GetError() to obtain the error
* message); the frame time is in 1 us increments.
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
* is in 1 us increments.
*/
public long grabFrameNoTimeout(Mat image) {
return CameraServerCvJNI.grabSinkFrame(m_handle, image.nativeObj);

View File

@@ -1,19 +1,14 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import org.opencv.core.Mat;
/**
* A source that represents a video camera.
* These sources require the WPILib OpenCV builds.
* For an alternate OpenCV, see the documentation how to build your own
* with RawSource.
* A source that represents a video camera. These sources require the WPILib OpenCV builds. For an
* alternate OpenCV, see the documentation how to build your own with RawSource.
*/
public class CvSource extends ImageSource {
/**
@@ -23,11 +18,9 @@ public class CvSource extends ImageSource {
* @param mode Video mode being generated
*/
public CvSource(String name, VideoMode mode) {
super(CameraServerCvJNI.createCvSource(name,
mode.pixelFormat.getValue(),
mode.width,
mode.height,
mode.fps));
super(
CameraServerCvJNI.createCvSource(
name, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
}
/**
@@ -46,14 +39,13 @@ public class CvSource extends ImageSource {
/**
* Put an OpenCV image and notify sinks.
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* Mat.convertTo() and/or cvtColor() to convert it first.
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images are supported. If the
* format, depth or channel order is different, use Mat.convertTo() and/or cvtColor() to convert
* it first.
*
* @param image OpenCV image
*/
public void putFrame(Mat image) {
CameraServerCvJNI.putSourceFrame(m_handle, image.nativeObj);
}
}

View File

@@ -1,20 +1,17 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source that represents a MJPEG-over-HTTP (IP) camera.
*/
/** A source that represents a MJPEG-over-HTTP (IP) camera. */
public class HttpCamera extends VideoCamera {
public enum HttpCameraKind {
kUnknown(0), kMJPGStreamer(1), kCSCore(2), kAxis(3);
kUnknown(0),
kMJPGStreamer(1),
kCSCore(2),
kAxis(3);
@SuppressWarnings("MemberName")
private final int value;
HttpCameraKind(int value) {
@@ -34,10 +31,14 @@ public class HttpCamera extends VideoCamera {
*/
public static HttpCameraKind getHttpCameraKindFromInt(int kind) {
switch (kind) {
case 1: return HttpCameraKind.kMJPGStreamer;
case 2: return HttpCameraKind.kCSCore;
case 3: return HttpCameraKind.kAxis;
default: return HttpCameraKind.kUnknown;
case 1:
return HttpCameraKind.kMJPGStreamer;
case 2:
return HttpCameraKind.kCSCore;
case 3:
return HttpCameraKind.kAxis;
default:
return HttpCameraKind.kUnknown;
}
}
@@ -86,23 +87,18 @@ public class HttpCamera extends VideoCamera {
/**
* Get the kind of HTTP camera.
*
* <p>Autodetection can result in returning a different value than the camera
* was created with.
* <p>Autodetection can result in returning a different value than the camera was created with.
*/
public HttpCameraKind getHttpCameraKind() {
return getHttpCameraKindFromInt(CameraServerJNI.getHttpCameraKind(m_handle));
}
/**
* Change the URLs used to connect to the camera.
*/
/** Change the URLs used to connect to the camera. */
public void setUrls(String[] urls) {
CameraServerJNI.setHttpCameraUrls(m_handle, urls);
}
/**
* Get the URLs used to connect to the camera.
*/
/** Get the URLs used to connect to the camera. */
public String[] getUrls() {
return CameraServerJNI.getHttpCameraUrls(m_handle);
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
@@ -21,19 +18,15 @@ public abstract class ImageSink extends VideoSink {
CameraServerJNI.setSinkDescription(m_handle, description);
}
/**
* Get error string. Call this if WaitForFrame() returns 0 to determine
* what the error is.
*/
/** Get error string. Call this if WaitForFrame() returns 0 to determine what the error is. */
public String getError() {
return CameraServerJNI.getSinkError(m_handle);
}
/**
* Enable or disable getting new frames.
* Disabling will cause processFrame (for callback-based CvSinks) to not
* be called and WaitForFrame() to not return. This can be used to save
* processor resources when frames are not needed.
* Enable or disable getting new frames. Disabling will cause processFrame (for callback-based
* CvSinks) to not be called and WaitForFrame() to not return. This can be used to save processor
* resources when frames are not needed.
*/
public void setEnabled(boolean enabled) {
CameraServerJNI.setSinkEnabled(m_handle, enabled);

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
@@ -13,15 +10,15 @@ public abstract class ImageSource extends VideoSource {
}
/**
* Signal sinks that an error has occurred. This should be called instead
* of NotifyFrame when an error occurs.
* Signal sinks that an error has occurred. This should be called instead of NotifyFrame when an
* error occurs.
*/
public void notifyError(String msg) {
CameraServerJNI.notifySourceError(m_handle, msg);
}
/**
* Set source connection status. Defaults to true.
* Set source connection status. Defaults to true.
*
* @param connected True for connected, false for disconnected
*/
@@ -50,22 +47,17 @@ public abstract class ImageSource extends VideoSource {
* @param value Current value
* @return Property
*/
public VideoProperty createProperty(String name,
VideoProperty.Kind kind,
int minimum,
int maximum,
int step,
int defaultValue,
int value) {
public VideoProperty createProperty(
String name,
VideoProperty.Kind kind,
int minimum,
int maximum,
int step,
int defaultValue,
int value) {
return new VideoProperty(
CameraServerJNI.createSourceProperty(m_handle,
name,
kind.getValue(),
minimum,
maximum,
step,
defaultValue,
value));
CameraServerJNI.createSourceProperty(
m_handle, name, kind.getValue(), minimum, maximum, step, defaultValue, value));
}
/**
@@ -79,14 +71,11 @@ public abstract class ImageSource extends VideoSource {
* @param value Current value
* @return Property
*/
public VideoProperty createIntegerProperty(String name,
int minimum,
int maximum,
int step,
int defaultValue,
int value) {
public VideoProperty createIntegerProperty(
String name, int minimum, int maximum, int step, int defaultValue, int value) {
return new VideoProperty(
CameraServerJNI.createSourceProperty(m_handle,
CameraServerJNI.createSourceProperty(
m_handle,
name,
VideoProperty.Kind.kInteger.getValue(),
minimum,
@@ -106,7 +95,8 @@ public abstract class ImageSource extends VideoSource {
*/
public VideoProperty createBooleanProperty(String name, boolean defaultValue, boolean value) {
return new VideoProperty(
CameraServerJNI.createSourceProperty(m_handle,
CameraServerJNI.createSourceProperty(
m_handle,
name,
VideoProperty.Kind.kBoolean.getValue(),
0,
@@ -124,15 +114,10 @@ public abstract class ImageSource extends VideoSource {
* @return Property
*/
public VideoProperty createStringProperty(String name, String value) {
VideoProperty prop = new VideoProperty(
CameraServerJNI.createSourceProperty(m_handle,
name,
VideoProperty.Kind.kString.getValue(),
0,
0,
0,
0,
0));
VideoProperty prop =
new VideoProperty(
CameraServerJNI.createSourceProperty(
m_handle, name, VideoProperty.Kind.kString.getValue(), 0, 0, 0, 0, 0));
prop.setString(value);
return prop;
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A sink that acts as a MJPEG-over-HTTP network server.
*/
/** A sink that acts as a MJPEG-over-HTTP network server. */
public class MjpegServer extends VideoSink {
/**
* Create a MJPEG-over-HTTP server sink.
@@ -32,16 +27,12 @@ public class MjpegServer extends VideoSink {
this(name, "", port);
}
/**
* Get the listen address of the server.
*/
/** Get the listen address of the server. */
public String getListenAddress() {
return CameraServerJNI.getMjpegServerListenAddress(m_handle);
}
/**
* Get the port number of the server.
*/
/** Get the port number of the server. */
public int getPort() {
return CameraServerJNI.getMjpegServerPort(m_handle);
}
@@ -49,13 +40,11 @@ public class MjpegServer extends VideoSink {
/**
* Set the stream resolution for clients that don't specify it.
*
* <p>It is not necessary to set this if it is the same as the source
* resolution.
* <p>It is not necessary to set this if it is the same as the source resolution.
*
* <p>Setting this different than the source resolution will result in
* increased CPU usage, particularly for MJPEG source cameras, as it will
* decompress, resize, and recompress the image, instead of using the
* camera's MJPEG image directly.
* <p>Setting this different than the source resolution will result in increased CPU usage,
* particularly for MJPEG source cameras, as it will decompress, resize, and recompress the image,
* instead of using the camera's MJPEG image directly.
*
* @param width width, 0 for unspecified
* @param height height, 0 for unspecified
@@ -79,26 +68,24 @@ public class MjpegServer extends VideoSink {
/**
* Set the compression for clients that don't specify it.
*
* <p>Setting this will result in increased CPU usage for MJPEG source cameras
* as it will decompress and recompress the image instead of using the
* camera's MJPEG image directly.
* <p>Setting this will result in increased CPU usage for MJPEG source cameras as it will
* decompress and recompress the image instead of using the camera's MJPEG image directly.
*
* @param quality JPEG compression quality (0-100), -1 for unspecified
*/
public void setCompression(int quality) {
CameraServerJNI.setProperty(CameraServerJNI.getSinkProperty(m_handle, "compression"),
quality);
CameraServerJNI.setProperty(CameraServerJNI.getSinkProperty(m_handle, "compression"), quality);
}
/**
* Set the default compression used for non-MJPEG sources. If not set,
* 80 is used. This function has no effect on MJPEG source cameras; use
* SetCompression() instead to force recompression of MJPEG source images.
* Set the default compression used for non-MJPEG sources. If not set, 80 is used. This function
* has no effect on MJPEG source cameras; use SetCompression() instead to force recompression of
* MJPEG source images.
*
* @param quality JPEG compression quality (0-100)
*/
public void setDefaultCompression(int quality) {
CameraServerJNI.setProperty(CameraServerJNI.getSinkProperty(m_handle, "default_compression"),
quality);
CameraServerJNI.setProperty(
CameraServerJNI.getSinkProperty(m_handle, "default_compression"), quality);
}
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source that represents a USB camera.
*/
/** A source that represents a USB camera. */
public class UsbCamera extends VideoCamera {
/**
* Create a source for a USB camera based on device number.
@@ -40,23 +35,17 @@ public class UsbCamera extends VideoCamera {
return CameraServerJNI.enumerateUsbCameras();
}
/**
* Change the path to the device.
*/
/** Change the path to the device. */
void setPath(String path) {
CameraServerJNI.setUsbCameraPath(m_handle, path);
}
/**
* Get the path to the device.
*/
/** Get the path to the device. */
public String getPath() {
return CameraServerJNI.getUsbCameraPath(m_handle);
}
/**
* Get the full camera information for the device.
*/
/** Get the full camera information for the device. */
public UsbCameraInfo getInfo() {
return CameraServerJNI.getUsbCameraInfo(m_handle);
}
@@ -67,7 +56,7 @@ public class UsbCamera extends VideoCamera {
* @param level 0=don't display Connecting message, 1=do display message
*/
public void setConnectVerbose(int level) {
CameraServerJNI.setProperty(CameraServerJNI.getSourceProperty(m_handle, "connect_verbose"),
level);
CameraServerJNI.setProperty(
CameraServerJNI.getSourceProperty(m_handle, "connect_verbose"), level);
}
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* USB camera information.
*/
/** USB camera information. */
public class UsbCameraInfo {
/**
* Create a new set of UsbCameraInfo.
@@ -22,8 +17,8 @@ public class UsbCameraInfo {
* @param productId USB product id
*/
@SuppressWarnings("PMD.ArrayIsStoredDirectly")
public UsbCameraInfo(int dev, String path, String name, String[] otherPaths, int vendorId,
int productId) {
public UsbCameraInfo(
int dev, String path, String name, String[] otherPaths, int vendorId, int productId) {
this.dev = dev;
this.path = path;
this.name = name;
@@ -32,39 +27,27 @@ public class UsbCameraInfo {
this.productId = productId;
}
/**
* Device number (e.g. N in '/dev/videoN' on Linux).
*/
/** Device number (e.g. N in '/dev/videoN' on Linux). */
@SuppressWarnings("MemberName")
public int dev;
/**
* Path to device if available (e.g. '/dev/video0' on Linux).
*/
/** Path to device if available (e.g. '/dev/video0' on Linux). */
@SuppressWarnings("MemberName")
public String path;
/**
* Vendor/model name of the camera as provided by the USB driver.
*/
/** Vendor/model name of the camera as provided by the USB driver. */
@SuppressWarnings("MemberName")
public String name;
/**
* Other path aliases to device (e.g. '/dev/v4l/by-id/...' etc on Linux).
*/
/** Other path aliases to device (e.g. '/dev/v4l/by-id/...' etc on Linux). */
@SuppressWarnings("MemberName")
public String[] otherPaths;
/**
* USB vendor id.
*/
/** USB vendor id. */
@SuppressWarnings("MemberName")
public int vendorId;
/**
* USB product id.
*/
/** USB product id. */
@SuppressWarnings("MemberName")
public int productId;
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source that represents a video camera.
*/
/** A source that represents a video camera. */
public class VideoCamera extends VideoSource {
public static class WhiteBalance {
public static final int kFixedIndoor = 3000;
@@ -23,58 +18,42 @@ public class VideoCamera extends VideoSource {
super(handle);
}
/**
* Set the brightness, as a percentage (0-100).
*/
/** Set the brightness, as a percentage (0-100). */
public synchronized void setBrightness(int brightness) {
CameraServerJNI.setCameraBrightness(m_handle, brightness);
}
/**
* Get the brightness, as a percentage (0-100).
*/
/** Get the brightness, as a percentage (0-100). */
public synchronized int getBrightness() {
return CameraServerJNI.getCameraBrightness(m_handle);
}
/**
* Set the white balance to auto.
*/
/** Set the white balance to auto. */
public synchronized void setWhiteBalanceAuto() {
CameraServerJNI.setCameraWhiteBalanceAuto(m_handle);
}
/**
* Set the white balance to hold current.
*/
/** Set the white balance to hold current. */
public synchronized void setWhiteBalanceHoldCurrent() {
CameraServerJNI.setCameraWhiteBalanceHoldCurrent(m_handle);
}
/**
* Set the white balance to manual, with specified color temperature.
*/
/** Set the white balance to manual, with specified color temperature. */
public synchronized void setWhiteBalanceManual(int value) {
CameraServerJNI.setCameraWhiteBalanceManual(m_handle, value);
}
/**
* Set the exposure to auto aperture.
*/
/** Set the exposure to auto aperture. */
public synchronized void setExposureAuto() {
CameraServerJNI.setCameraExposureAuto(m_handle);
}
/**
* Set the exposure to hold current.
*/
/** Set the exposure to hold current. */
public synchronized void setExposureHoldCurrent() {
CameraServerJNI.setCameraExposureHoldCurrent(m_handle);
}
/**
* Set the exposure to manual, as a percentage (0-100).
*/
/** Set the exposure to manual, as a percentage (0-100). */
public synchronized void setExposureManual(int value) {
CameraServerJNI.setCameraExposureManual(m_handle, value);
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* Video event.
*/
/** Video event. */
public class VideoEvent {
public enum Kind {
kUnknown(0x0000),
@@ -33,7 +28,6 @@ public class VideoEvent {
kSinkPropertyValueUpdated(0x20000),
kSinkPropertyChoicesUpdated(0x40000);
@SuppressWarnings("MemberName")
private final int value;
Kind(int value) {
@@ -54,32 +48,61 @@ public class VideoEvent {
@SuppressWarnings("PMD.CyclomaticComplexity")
public static Kind getKindFromInt(int kind) {
switch (kind) {
case 0x0001: return Kind.kSourceCreated;
case 0x0002: return Kind.kSourceDestroyed;
case 0x0004: return Kind.kSourceConnected;
case 0x0008: return Kind.kSourceDisconnected;
case 0x0010: return Kind.kSourceVideoModesUpdated;
case 0x0020: return Kind.kSourceVideoModeChanged;
case 0x0040: return Kind.kSourcePropertyCreated;
case 0x0080: return Kind.kSourcePropertyValueUpdated;
case 0x0100: return Kind.kSourcePropertyChoicesUpdated;
case 0x0200: return Kind.kSinkSourceChanged;
case 0x0400: return Kind.kSinkCreated;
case 0x0800: return Kind.kSinkDestroyed;
case 0x1000: return Kind.kSinkEnabled;
case 0x2000: return Kind.kSinkDisabled;
case 0x4000: return Kind.kNetworkInterfacesChanged;
case 0x10000: return Kind.kSinkPropertyCreated;
case 0x20000: return Kind.kSinkPropertyValueUpdated;
case 0x40000: return Kind.kSinkPropertyChoicesUpdated;
default: return Kind.kUnknown;
case 0x0001:
return Kind.kSourceCreated;
case 0x0002:
return Kind.kSourceDestroyed;
case 0x0004:
return Kind.kSourceConnected;
case 0x0008:
return Kind.kSourceDisconnected;
case 0x0010:
return Kind.kSourceVideoModesUpdated;
case 0x0020:
return Kind.kSourceVideoModeChanged;
case 0x0040:
return Kind.kSourcePropertyCreated;
case 0x0080:
return Kind.kSourcePropertyValueUpdated;
case 0x0100:
return Kind.kSourcePropertyChoicesUpdated;
case 0x0200:
return Kind.kSinkSourceChanged;
case 0x0400:
return Kind.kSinkCreated;
case 0x0800:
return Kind.kSinkDestroyed;
case 0x1000:
return Kind.kSinkEnabled;
case 0x2000:
return Kind.kSinkDisabled;
case 0x4000:
return Kind.kNetworkInterfacesChanged;
case 0x10000:
return Kind.kSinkPropertyCreated;
case 0x20000:
return Kind.kSinkPropertyValueUpdated;
case 0x40000:
return Kind.kSinkPropertyChoicesUpdated;
default:
return Kind.kUnknown;
}
}
@SuppressWarnings("PMD.ExcessiveParameterList")
VideoEvent(int kind, int source, int sink, String name, int pixelFormat,
int width, int height, int fps, int property, int propertyKind,
int value, String valueStr) {
VideoEvent(
int kind,
int source,
int sink,
String name,
int pixelFormat,
int width,
int height,
int fps,
int property,
int propertyKind,
int value,
String valueStr) {
this.kind = getKindFromInt(kind);
this.sourceHandle = source;
this.sinkHandle = sink;
@@ -97,6 +120,7 @@ public class VideoEvent {
// Valid for kSource* and kSink* respectively
@SuppressWarnings("MemberName")
public int sourceHandle;
@SuppressWarnings("MemberName")
public int sinkHandle;
@@ -111,10 +135,13 @@ public class VideoEvent {
// Fields for kSourceProperty* events
@SuppressWarnings("MemberName")
public int propertyHandle;
@SuppressWarnings("MemberName")
public VideoProperty.Kind propertyKind;
@SuppressWarnings("MemberName")
public int value;
@SuppressWarnings("MemberName")
public String valueStr;
@@ -129,5 +156,4 @@ public class VideoEvent {
public VideoProperty getProperty() {
return new VideoProperty(propertyHandle, propertyKind);
}
}

View File

@@ -1,15 +1,10 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* An exception raised by the camera server.
*/
/** An exception raised by the camera server. */
public class VideoException extends RuntimeException {
private static final long serialVersionUID = -9155939328084105145L;

View File

@@ -1,17 +1,14 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
import java.util.function.Consumer;
/**
* An event listener. This calls back to a desigated callback function when
* an event matching the specified mask is generated by the library.
* An event listener. This calls back to a desigated callback function when an event matching the
* specified mask is generated by the library.
*/
public class VideoListener implements AutoCloseable {
/**
@@ -19,11 +16,10 @@ public class VideoListener implements AutoCloseable {
*
* @param listener Listener function
* @param eventMask Bitmask of VideoEvent.Type values
* @param immediateNotify Whether callback should be immediately called with
* a representative set of events for the current library state.
* @param immediateNotify Whether callback should be immediately called with a representative set
* of events for the current library state.
*/
public VideoListener(Consumer<VideoEvent> listener, int eventMask,
boolean immediateNotify) {
public VideoListener(Consumer<VideoEvent> listener, int eventMask, boolean immediateNotify) {
m_handle = CameraServerJNI.addListener(listener, eventMask, immediateNotify);
}

View File

@@ -1,20 +1,19 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* Video mode.
*/
/** Video mode. */
public class VideoMode {
public enum PixelFormat {
kUnknown(0), kMJPEG(1), kYUYV(2), kRGB565(3), kBGR(4), kGray(5);
kUnknown(0),
kMJPEG(1),
kYUYV(2),
kRGB565(3),
kBGR(4),
kGray(5);
@SuppressWarnings("MemberName")
private final int value;
PixelFormat(int value) {
@@ -32,9 +31,7 @@ public class VideoMode {
return m_pixelFormatValues[pixelFormat];
}
/**
* Create a new video mode.
*/
/** Create a new video mode. */
public VideoMode(int pixelFormat, int width, int height, int fps) {
this.pixelFormat = getPixelFormatFromInt(pixelFormat);
this.width = width;
@@ -42,9 +39,7 @@ public class VideoMode {
this.fps = fps;
}
/**
* Create a new video mode.
*/
/** Create a new video mode. */
public VideoMode(PixelFormat pixelFormat, int width, int height, int fps) {
this.pixelFormat = pixelFormat;
this.width = width;
@@ -52,27 +47,19 @@ public class VideoMode {
this.fps = fps;
}
/**
* Pixel format.
*/
/** Pixel format. */
@SuppressWarnings("MemberName")
public PixelFormat pixelFormat;
/**
* Width in pixels.
*/
/** Width in pixels. */
@SuppressWarnings("MemberName")
public int width;
/**
* Height in pixels.
*/
/** Height in pixels. */
@SuppressWarnings("MemberName")
public int height;
/**
* Frames per second.
*/
/** Frames per second. */
@SuppressWarnings("MemberName")
public int fps;
}

View File

@@ -1,20 +1,18 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source or sink property.
*/
/** A source or sink property. */
public class VideoProperty {
public enum Kind {
kNone(0), kBoolean(1), kInteger(2), kString(4), kEnum(8);
kNone(0),
kBoolean(1),
kInteger(2),
kString(4),
kEnum(8);
@SuppressWarnings("MemberName")
private final int value;
Kind(int value) {
@@ -34,11 +32,16 @@ public class VideoProperty {
*/
public static Kind getKindFromInt(int kind) {
switch (kind) {
case 1: return Kind.kBoolean;
case 2: return Kind.kInteger;
case 4: return Kind.kString;
case 8: return Kind.kEnum;
default: return Kind.kNone;
case 1:
return Kind.kBoolean;
case 2:
return Kind.kInteger;
case 4:
return Kind.kString;
case 8:
return Kind.kEnum;
default:
return Kind.kNone;
}
}

View File

@@ -1,22 +1,20 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source for video that provides a sequence of frames. Each frame may
* consist of multiple images (e.g. from a stereo or depth camera); these
* are called channels.
* A source for video that provides a sequence of frames. Each frame may consist of multiple images
* (e.g. from a stereo or depth camera); these are called channels.
*/
public class VideoSink implements AutoCloseable {
public enum Kind {
kUnknown(0), kMjpeg(2), kCv(4), kRaw(8);
kUnknown(0),
kMjpeg(2),
kCv(4),
kRaw(8);
@SuppressWarnings("MemberName")
private final int value;
Kind(int value) {
@@ -36,9 +34,12 @@ public class VideoSink implements AutoCloseable {
*/
public static Kind getKindFromInt(int kind) {
switch (kind) {
case 2: return Kind.kMjpeg;
case 4: return Kind.kCv;
default: return Kind.kUnknown;
case 2:
return Kind.kMjpeg;
case 4:
return Kind.kCv;
default:
return Kind.kUnknown;
}
}
@@ -82,24 +83,20 @@ public class VideoSink implements AutoCloseable {
return m_handle;
}
/**
* Get the kind of the sink.
*/
/** Get the kind of the sink. */
public Kind getKind() {
return getKindFromInt(CameraServerJNI.getSinkKind(m_handle));
}
/**
* Get the name of the sink. The name is an arbitrary identifier
* provided when the sink is created, and should be unique.
* Get the name of the sink. The name is an arbitrary identifier provided when the sink is
* created, and should be unique.
*/
public String getName() {
return CameraServerJNI.getSinkName(m_handle);
}
/**
* Get the sink description. This is sink-kind specific.
*/
/** Get the sink description. This is sink-kind specific. */
public String getDescription() {
return CameraServerJNI.getSinkDescription(m_handle);
}
@@ -108,16 +105,13 @@ public class VideoSink implements AutoCloseable {
* Get a property of the sink.
*
* @param name Property name
* @return Property (kind Property::kNone if no property with
* the given name exists)
* @return Property (kind Property::kNone if no property with the given name exists)
*/
public VideoProperty getProperty(String name) {
return new VideoProperty(CameraServerJNI.getSinkProperty(m_handle, name));
}
/**
* Enumerate all properties of this sink.
*/
/** Enumerate all properties of this sink. */
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
public VideoProperty[] enumerateProperties() {
int[] handles = CameraServerJNI.enumerateSinkProperties(m_handle);
@@ -161,9 +155,8 @@ public class VideoSink implements AutoCloseable {
}
/**
* Configure which source should provide frames to this sink. Each sink
* can accept frames from only a single source, but a single source can
* provide frames to multiple clients.
* Configure which source should provide frames to this sink. Each sink can accept frames from
* only a single source, but a single source can provide frames to multiple clients.
*
* @param source Source
*/
@@ -190,12 +183,11 @@ public class VideoSink implements AutoCloseable {
* Get a property of the associated source.
*
* @param name Property name
* @return Property (kind Property::kNone if no property with
* the given name exists or no source connected)
* @return Property (kind Property::kNone if no property with the given name exists or no source
* connected)
*/
public VideoProperty getSourceProperty(String name) {
return new VideoProperty(
CameraServerJNI.getSinkSourceProperty(m_handle, name));
return new VideoProperty(CameraServerJNI.getSinkSourceProperty(m_handle, name));
}
/**

View File

@@ -1,22 +1,21 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore;
/**
* A source for video that provides a sequence of frames. Each frame may
* consist of multiple images (e.g. from a stereo or depth camera); these
* are called channels.
* A source for video that provides a sequence of frames. Each frame may consist of multiple images
* (e.g. from a stereo or depth camera); these are called channels.
*/
public class VideoSource implements AutoCloseable {
public enum Kind {
kUnknown(0), kUsb(1), kHttp(2), kCv(4), kRaw(8);
kUnknown(0),
kUsb(1),
kHttp(2),
kCv(4),
kRaw(8);
@SuppressWarnings("MemberName")
private final int value;
Kind(int value) {
@@ -28,29 +27,22 @@ public class VideoSource implements AutoCloseable {
}
}
/**
* Connection strategy.
*/
/** Connection strategy. */
public enum ConnectionStrategy {
/**
* Automatically connect or disconnect based on whether any sinks are
* connected to this source. This is the default behavior.
* Automatically connect or disconnect based on whether any sinks are connected to this source.
* This is the default behavior.
*/
kAutoManage(0),
/**
* Try to keep the connection open regardless of whether any sinks are
* connected.
*/
/** Try to keep the connection open regardless of whether any sinks are connected. */
kKeepOpen(1),
/**
* Never open the connection. If this is set when the connection is open,
* close the connection.
* Never open the connection. If this is set when the connection is open, close the connection.
*/
kForceClose(2);
@SuppressWarnings("MemberName")
private final int value;
ConnectionStrategy(int value) {
@@ -70,10 +62,14 @@ public class VideoSource implements AutoCloseable {
*/
public static Kind getKindFromInt(int kind) {
switch (kind) {
case 1: return Kind.kUsb;
case 2: return Kind.kHttp;
case 4: return Kind.kCv;
default: return Kind.kUnknown;
case 1:
return Kind.kUsb;
case 2:
return Kind.kHttp;
case 4:
return Kind.kCv;
default:
return Kind.kUnknown;
}
}
@@ -117,30 +113,27 @@ public class VideoSource implements AutoCloseable {
return m_handle;
}
/**
* Get the kind of the source.
*/
/** Get the kind of the source. */
public Kind getKind() {
return getKindFromInt(CameraServerJNI.getSourceKind(m_handle));
}
/**
* Get the name of the source. The name is an arbitrary identifier
* provided when the source is created, and should be unique.
* Get the name of the source. The name is an arbitrary identifier provided when the source is
* created, and should be unique.
*/
public String getName() {
return CameraServerJNI.getSourceName(m_handle);
}
/**
* Get the source description. This is source-kind specific.
*/
/** Get the source description. This is source-kind specific. */
public String getDescription() {
return CameraServerJNI.getSourceDescription(m_handle);
}
/**
* Get the last time a frame was captured.
*
* @return Time in 1 us increments.
*/
public long getLastFrameTime() {
@@ -148,12 +141,11 @@ public class VideoSource implements AutoCloseable {
}
/**
* Sets the connection strategy. By default, the source will automatically
* connect or disconnect based on whether any sinks are connected.
* Sets the connection strategy. By default, the source will automatically connect or disconnect
* based on whether any sinks are connected.
*
* <p>This function is non-blocking; look for either a connection open or
* close event or call {@link #isConnected()} to determine the connection
* state.
* <p>This function is non-blocking; look for either a connection open or close event or call
* {@link #isConnected()} to determine the connection state.
*
* @param strategy connection strategy (auto, keep open, or force close)
*/
@@ -161,16 +153,14 @@ public class VideoSource implements AutoCloseable {
CameraServerJNI.setSourceConnectionStrategy(m_handle, strategy.getValue());
}
/**
* Returns if the source currently connected to whatever is providing the images.
*/
/** Returns if the source currently connected to whatever is providing the images. */
public boolean isConnected() {
return CameraServerJNI.isSourceConnected(m_handle);
}
/**
* Gets source enable status. This is determined with a combination of
* connection strategy and the number of sinks connected.
* Gets source enable status. This is determined with a combination of connection strategy and the
* number of sinks connected.
*
* @return True if enabled, false otherwise.
*/
@@ -182,16 +172,13 @@ public class VideoSource implements AutoCloseable {
* Get a property.
*
* @param name Property name
* @return Property contents (of kind Property::kNone if no property with
* the given name exists)
* @return Property contents (of kind Property::kNone if no property with the given name exists)
*/
public VideoProperty getProperty(String name) {
return new VideoProperty(CameraServerJNI.getSourceProperty(m_handle, name));
}
/**
* Enumerate all properties of this source.
*/
/** Enumerate all properties of this source. */
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
public VideoProperty[] enumerateProperties() {
int[] handles = CameraServerJNI.enumerateSourceProperties(m_handle);
@@ -202,23 +189,19 @@ public class VideoSource implements AutoCloseable {
return rv;
}
/**
* Get the current video mode.
*/
/** Get the current video mode. */
public VideoMode getVideoMode() {
return CameraServerJNI.getSourceVideoMode(m_handle);
}
/**
* Set the video mode.
*
* @param mode Video mode
*/
public boolean setVideoMode(VideoMode mode) {
return CameraServerJNI.setSourceVideoMode(m_handle,
mode.pixelFormat.getValue(),
mode.width,
mode.height,
mode.fps);
return CameraServerJNI.setSourceVideoMode(
m_handle, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps);
}
/**
@@ -307,32 +290,30 @@ public class VideoSource implements AutoCloseable {
/**
* Get the actual FPS.
*
* <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid
* (throws VisionException if telemetry is not enabled).
* <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid (throws
* VisionException if telemetry is not enabled).
*
* @return Actual FPS averaged over the telemetry period.
*/
public double getActualFPS() {
return CameraServerJNI.getTelemetryAverageValue(m_handle,
CameraServerJNI.TelemetryKind.kSourceFramesReceived);
return CameraServerJNI.getTelemetryAverageValue(
m_handle, CameraServerJNI.TelemetryKind.kSourceFramesReceived);
}
/**
* Get the data rate (in bytes per second).
*
* <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid
* (throws VisionException if telemetry is not enabled).
* <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid (throws
* VisionException if telemetry is not enabled).
*
* @return Data rate averaged over the telemetry period.
*/
public double getActualDataRate() {
return CameraServerJNI.getTelemetryAverageValue(m_handle,
CameraServerJNI.TelemetryKind.kSourceBytesReceived);
return CameraServerJNI.getTelemetryAverageValue(
m_handle, CameraServerJNI.TelemetryKind.kSourceBytesReceived);
}
/**
* Enumerate all known video modes for this source.
*/
/** Enumerate all known video modes for this source. */
public VideoMode[] enumerateVideoModes() {
return CameraServerJNI.enumerateSourceVideoModes(m_handle);
}

View File

@@ -1,15 +1,11 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore.raw;
import java.nio.ByteBuffer;
import edu.wpi.cscore.CameraServerJNI;
import java.nio.ByteBuffer;
/**
* Class for storing raw frame data between image read call.
@@ -25,27 +21,28 @@ public class RawFrame implements AutoCloseable {
private int m_height;
private int m_pixelFormat;
/**
* Construct a new RawFrame.
*/
/** Construct a new RawFrame. */
public RawFrame() {
m_framePtr = CameraServerJNI.allocateRawFrame();
}
/**
* Close the RawFrame, releasing native resources.
* Any images currently using the data will be invalidated.
* Close the RawFrame, releasing native resources. Any images currently using the data will be
* invalidated.
*/
@Override
public void close() {
CameraServerJNI.freeRawFrame(m_framePtr);
}
/**
* Called from JNI to set data in class.
*/
public void setData(ByteBuffer dataByteBuffer, long dataPtr, int totalData,
int width, int height, int pixelFormat) {
/** Called from JNI to set data in class. */
public void setData(
ByteBuffer dataByteBuffer,
long dataPtr,
int totalData,
int width,
int height,
int pixelFormat) {
m_dataByteBuffer = dataByteBuffer;
m_dataPtr = dataPtr;
m_totalData = totalData;
@@ -54,76 +51,60 @@ public class RawFrame implements AutoCloseable {
m_pixelFormat = pixelFormat;
}
/**
* Get the pointer to native representation of this frame.
*/
/** Get the pointer to native representation of this frame. */
public long getFramePtr() {
return m_framePtr;
}
/**
* Get a ByteBuffer pointing to the frame data.
* This ByteBuffer is backed by the frame directly. Its lifetime is controlled by
* the frame. If a new frame gets read, it will overwrite the current one.
* Get a ByteBuffer pointing to the frame data. This ByteBuffer is backed by the frame directly.
* Its lifetime is controlled by the frame. If a new frame gets read, it will overwrite the
* current one.
*/
public ByteBuffer getDataByteBuffer() {
return m_dataByteBuffer;
}
/**
* Get a long (is a char* in native code) pointing to the frame data.
* This pointer is backed by the frame directly. Its lifetime is controlled by
* the frame. If a new frame gets read, it will overwrite the current one.
* Get a long (is a char* in native code) pointing to the frame data. This pointer is backed by
* the frame directly. Its lifetime is controlled by the frame. If a new frame gets read, it will
* overwrite the current one.
*/
public long getDataPtr() {
return m_dataPtr;
}
/**
* Get the total length of the data stored in the frame.
*/
/** Get the total length of the data stored in the frame. */
public int getTotalData() {
return m_totalData;
}
/**
* Get the width of the frame.
*/
/** Get the width of the frame. */
public int getWidth() {
return m_width;
}
/**
* Set the width of the frame.
*/
/** Set the width of the frame. */
public void setWidth(int width) {
this.m_width = width;
}
/**
* Get the height of the frame.
*/
/** Get the height of the frame. */
public int getHeight() {
return m_height;
}
/**
* Set the height of the frame.
*/
/** Set the height of the frame. */
public void setHeight(int height) {
this.m_height = height;
}
/**
* Get the PixelFormat of the frame.
*/
/** Get the PixelFormat of the frame. */
public int getPixelFormat() {
return m_pixelFormat;
}
/**
* Set the PixelFormat of the frame.
*/
/** Set the PixelFormat of the frame. */
public void setPixelFormat(int pixelFormat) {
this.m_pixelFormat = pixelFormat;
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore.raw;
@@ -19,8 +16,7 @@ public class RawSink extends ImageSink {
/**
* Create a sink for accepting raw images.
*
* <p>grabFrame() must be called on the created sink to get each new
* image.
* <p>grabFrame() must be called on the created sink to get each new image.
*
* @param name Source name (arbitrary unique identifier)
*/
@@ -29,38 +25,33 @@ public class RawSink extends ImageSink {
}
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after 0.225 seconds.
* The provided image will have three 8-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after 0.225 seconds. The
* provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call getError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrame(RawFrame frame) {
return grabFrame(frame, 0.225);
}
/**
* Wait for the next frame and get the image.
* Times out (returning 0) after timeout seconds.
* The provided image will have three 8-bit channels stored in BGR order.
* Wait for the next frame and get the image. Times out (returning 0) after timeout seconds. The
* provided image will have three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call getError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrame(RawFrame frame, double timeout) {
return CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
}
/**
* Wait for the next frame and get the image. May block forever.
* The provided image will have three 8-bit channels stored in BGR order.
* Wait for the next frame and get the image. May block forever. The provided image will have
* three 8-bit channels stored in BGR order.
*
* @return Frame time, or 0 on error (call getError() to obtain the error
* message); the frame time is in the same time base as wpi::Now(),
* and is in 1 us increments.
* @return Frame time, or 0 on error (call getError() to obtain the error message); the frame time
* is in the same time base as wpi::Now(), and is in 1 us increments.
*/
protected long grabFrameNoTimeout(RawFrame frame) {
return CameraServerJNI.grabSinkFrame(m_handle, frame);

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.cscore.raw;
@@ -24,10 +21,9 @@ public class RawSource extends ImageSource {
* @param mode Video mode being generated
*/
public RawSource(String name, VideoMode mode) {
super(CameraServerJNI.createRawSource(name,
mode.pixelFormat.getValue(),
mode.width, mode.height,
mode.fps));
super(
CameraServerJNI.createRawSource(
name, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
}
/**
@@ -40,10 +36,7 @@ public class RawSource extends ImageSource {
* @param fps fps
*/
public RawSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
super(CameraServerJNI.createRawSource(name,
pixelFormat.getValue(),
width, height,
fps));
super(CameraServerJNI.createRawSource(name, pixelFormat.getValue(), width, height, fps));
}
/**
@@ -77,9 +70,9 @@ public class RawSource extends ImageSource {
* @param pixelFormat pixel format
* @param totalData length of data in total
*/
protected void putFrame(long data, int width, int height, VideoMode.PixelFormat pixelFormat,
int totalData) {
CameraServerJNI.putRawSourceFrame(m_handle, data, width, height, pixelFormat.getValue(),
totalData);
protected void putFrame(
long data, int width, int height, VideoMode.PixelFormat pixelFormat, int totalData) {
CameraServerJNI.putRawSourceFrame(
m_handle, data, width, height, pixelFormat.getValue(), totalData);
}
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "ConfigurableSourceImpl.h"
@@ -26,7 +23,7 @@ ConfigurableSourceImpl::ConfigurableSourceImpl(const wpi::Twine& name,
m_videoModes.push_back(m_mode);
}
ConfigurableSourceImpl::~ConfigurableSourceImpl() {}
ConfigurableSourceImpl::~ConfigurableSourceImpl() = default;
void ConfigurableSourceImpl::Start() {
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_CONFIGURABLESOURCEIMPL_H_
#define CSCORE_CONFIGURABLESOURCEIMPL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "CvSinkImpl.h"
@@ -33,16 +30,22 @@ CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
std::function<void(uint64_t time)> processFrame)
: SinkImpl{name, logger, notifier, telemetry} {}
CvSinkImpl::~CvSinkImpl() { Stop(); }
CvSinkImpl::~CvSinkImpl() {
Stop();
}
void CvSinkImpl::Stop() {
m_active = false;
// wake up any waiters by forcing an empty frame to be sent
if (auto source = GetSource()) source->Wakeup();
if (auto source = GetSource()) {
source->Wakeup();
}
// join thread
if (m_thread.joinable()) m_thread.join();
if (m_thread.joinable()) {
m_thread.join();
}
}
uint64_t CvSinkImpl::GrabFrame(cv::Mat& image) {
@@ -109,7 +112,9 @@ void CvSinkImpl::ThreadMain() {
}
SDEBUG4("waiting for frame");
Frame frame = source->GetNextFrame(); // blocks
if (!m_active) break;
if (!m_active) {
break;
}
if (!frame) {
// Bad frame; sleep for 10 ms so we don't consume all processor time.
std::this_thread::sleep_for(std::chrono::milliseconds(10));
@@ -243,7 +248,9 @@ uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
char* CS_GetSinkError(CS_Sink sink, CS_Status* status) {
wpi::SmallString<128> buf;
auto str = cs::GetSinkError(sink, buf, status);
if (*status != 0) return nullptr;
if (*status != 0) {
return nullptr;
}
return cs::ConvertToC(str);
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_CVSINKIMPL_H_
#define CSCORE_CVSINKIMPL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "CvSourceImpl.h"
@@ -27,15 +24,16 @@ CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
const VideoMode& mode)
: ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
CvSourceImpl::~CvSourceImpl() {}
CvSourceImpl::~CvSourceImpl() = default;
void CvSourceImpl::PutFrame(cv::Mat& image) {
// We only support 8-bit images; convert if necessary.
cv::Mat finalImage;
if (image.depth() == CV_8U)
if (image.depth() == CV_8U) {
finalImage = image;
else
} else {
image.convertTo(finalImage, CV_8U);
}
std::unique_ptr<Image> dest;
switch (image.channels()) {
@@ -227,7 +225,9 @@ void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
CS_Status* status) {
wpi::SmallVector<std::string, 8> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) vec.push_back(choices[i]);
for (int i = 0; i < count; ++i) {
vec.push_back(choices[i]);
}
return cs::SetSourceEnumPropertyChoices(source, property, vec, status);
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_CVSOURCEIMPL_H_
#define CSCORE_CVSOURCEIMPL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "Frame.h"
@@ -35,22 +32,31 @@ Frame::Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time)
}
Image* Frame::GetNearestImage(int width, int height) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
Image* found = nullptr;
// Ideally we want the smallest image at least width/height in size
for (auto i : m_impl->images) {
if (i->IsLarger(width, height) && (!found || (i->IsSmaller(*found))))
if (i->IsLarger(width, height) && (!found || (i->IsSmaller(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// Find the largest image (will be less than width/height)
for (auto i : m_impl->images) {
if (!found || (i->IsLarger(*found))) found = i;
if (!found || (i->IsLarger(*found))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// Shouldn't reach this, but just in case...
return m_impl->images.empty() ? nullptr : m_impl->images[0];
@@ -59,7 +65,9 @@ Image* Frame::GetNearestImage(int width, int height) const {
Image* Frame::GetNearestImage(int width, int height,
VideoMode::PixelFormat pixelFormat,
int jpegQuality) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
Image* found = nullptr;
@@ -74,19 +82,25 @@ Image* Frame::GetNearestImage(int width, int height,
// 1) Same width, height, pixelFormat, and (possibly) JPEG quality
// (e.g. exactly what we want)
for (auto i : m_impl->images) {
if (i->Is(width, height, pixelFormat, jpegQuality)) return i;
if (i->Is(width, height, pixelFormat, jpegQuality)) {
return i;
}
}
// 2) Same width, height, different (but non-JPEG) pixelFormat (color conv)
// 2a) If we want JPEG output, prefer BGR over other pixel formats
if (pixelFormat == VideoMode::kMJPEG) {
for (auto i : m_impl->images) {
if (i->Is(width, height, VideoMode::kBGR)) return i;
if (i->Is(width, height, VideoMode::kBGR)) {
return i;
}
}
}
for (auto i : m_impl->images) {
if (i->Is(width, height) && i->pixelFormat != VideoMode::kMJPEG) return i;
if (i->Is(width, height) && i->pixelFormat != VideoMode::kMJPEG) {
return i;
}
}
// 3) Different width, height, same pixelFormat (only if non-JPEG) (resample)
@@ -94,17 +108,23 @@ Image* Frame::GetNearestImage(int width, int height,
// 3a) Smallest image at least width/height in size
for (auto i : m_impl->images) {
if (i->IsLarger(width, height) && i->pixelFormat == pixelFormat &&
(!found || (i->IsSmaller(*found))))
(!found || (i->IsSmaller(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// 3b) Largest image (less than width/height)
for (auto i : m_impl->images) {
if (i->pixelFormat == pixelFormat && (!found || (i->IsLarger(*found))))
if (i->pixelFormat == pixelFormat && (!found || (i->IsLarger(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
}
// 4) Different width, height, different (but non-JPEG) pixelFormat
@@ -112,18 +132,24 @@ Image* Frame::GetNearestImage(int width, int height,
// 4a) Smallest image at least width/height in size
for (auto i : m_impl->images) {
if (i->IsLarger(width, height) && i->pixelFormat != VideoMode::kMJPEG &&
(!found || (i->IsSmaller(*found))))
(!found || (i->IsSmaller(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// 4b) Largest image (less than width/height)
for (auto i : m_impl->images) {
if (i->pixelFormat != VideoMode::kMJPEG &&
(!found || (i->IsLarger(*found))))
(!found || (i->IsLarger(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// 5) Same width, height, JPEG pixelFormat (decompression). As there may be
// multiple JPEG images, find the highest quality one.
@@ -133,27 +159,37 @@ Image* Frame::GetNearestImage(int width, int height,
found = i;
// consider one without a quality setting to be the highest quality
// (e.g. directly from the camera)
if (i->jpegQuality == -1) break;
if (i->jpegQuality == -1) {
break;
}
}
}
if (found) return found;
if (found) {
return found;
}
// 6) Different width, height, JPEG pixelFormat (decompression)
// 6a) Smallest image at least width/height in size
for (auto i : m_impl->images) {
if (i->IsLarger(width, height) && i->pixelFormat == VideoMode::kMJPEG &&
(!found || (i->IsSmaller(*found))))
(!found || (i->IsSmaller(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// 6b) Largest image (less than width/height)
for (auto i : m_impl->images) {
if (i->pixelFormat != VideoMode::kMJPEG &&
(!found || (i->IsLarger(*found))))
(!found || (i->IsLarger(*found)))) {
found = i;
}
}
if (found) {
return found;
}
if (found) return found;
// Shouldn't reach this, but just in case...
return m_impl->images.empty() ? nullptr : m_impl->images[0];
@@ -161,9 +197,10 @@ Image* Frame::GetNearestImage(int width, int height,
Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality) {
if (!image ||
image->Is(image->width, image->height, pixelFormat, requiredJpegQuality))
if (!image || image->Is(image->width, image->height, pixelFormat,
requiredJpegQuality)) {
return image;
}
Image* cur = image;
// If the source image is a JPEG, we need to decode it before we can do
@@ -172,7 +209,9 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
// would have returned above).
if (cur->pixelFormat == VideoMode::kMJPEG) {
cur = ConvertMJPEGToBGR(cur);
if (pixelFormat == VideoMode::kBGR) return cur;
if (pixelFormat == VideoMode::kBGR) {
return cur;
}
}
// Color convert
@@ -182,17 +221,19 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
if (cur->pixelFormat == VideoMode::kYUYV) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
else
} else {
cur = ConvertYUYVToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kGray) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
else
} else {
cur = ConvertGrayToBGR(cur);
}
}
return ConvertBGRToRGB565(cur);
case VideoMode::kGray:
@@ -200,17 +241,19 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
if (cur->pixelFormat == VideoMode::kYUYV) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
else
} else {
cur = ConvertYUYVToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kRGB565) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
else
} else {
cur = ConvertRGB565ToBGR(cur);
}
}
return ConvertBGRToGray(cur);
case VideoMode::kBGR:
@@ -220,10 +263,11 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
} else if (cur->pixelFormat == VideoMode::kRGB565) {
cur = ConvertRGB565ToBGR(cur);
} else if (cur->pixelFormat == VideoMode::kGray) {
if (pixelFormat == VideoMode::kBGR)
if (pixelFormat == VideoMode::kBGR) {
return ConvertGrayToBGR(cur);
else
} else {
return ConvertGrayToMJPEG(cur, defaultJpegQuality);
}
}
break;
case VideoMode::kYUYV:
@@ -232,14 +276,17 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
}
// Compress if destination is JPEG
if (pixelFormat == VideoMode::kMJPEG)
if (pixelFormat == VideoMode::kMJPEG) {
cur = ConvertBGRToMJPEG(cur, defaultJpegQuality);
}
return cur;
}
Image* Frame::ConvertMJPEGToBGR(Image* image) {
if (!image || image->pixelFormat != VideoMode::kMJPEG) return nullptr;
if (!image || image->pixelFormat != VideoMode::kMJPEG) {
return nullptr;
}
// Allocate an BGR image
auto newImage =
@@ -260,7 +307,9 @@ Image* Frame::ConvertMJPEGToBGR(Image* image) {
}
Image* Frame::ConvertMJPEGToGray(Image* image) {
if (!image || image->pixelFormat != VideoMode::kMJPEG) return nullptr;
if (!image || image->pixelFormat != VideoMode::kMJPEG) {
return nullptr;
}
// Allocate an grayscale image
auto newImage =
@@ -281,7 +330,9 @@ Image* Frame::ConvertMJPEGToGray(Image* image) {
}
Image* Frame::ConvertYUYVToBGR(Image* image) {
if (!image || image->pixelFormat != VideoMode::kYUYV) return nullptr;
if (!image || image->pixelFormat != VideoMode::kYUYV) {
return nullptr;
}
// Allocate a BGR image
auto newImage =
@@ -301,7 +352,9 @@ Image* Frame::ConvertYUYVToBGR(Image* image) {
}
Image* Frame::ConvertBGRToRGB565(Image* image) {
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
if (!image || image->pixelFormat != VideoMode::kBGR) {
return nullptr;
}
// Allocate a RGB565 image
auto newImage =
@@ -321,7 +374,9 @@ Image* Frame::ConvertBGRToRGB565(Image* image) {
}
Image* Frame::ConvertRGB565ToBGR(Image* image) {
if (!image || image->pixelFormat != VideoMode::kRGB565) return nullptr;
if (!image || image->pixelFormat != VideoMode::kRGB565) {
return nullptr;
}
// Allocate a BGR image
auto newImage =
@@ -341,7 +396,9 @@ Image* Frame::ConvertRGB565ToBGR(Image* image) {
}
Image* Frame::ConvertBGRToGray(Image* image) {
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
if (!image || image->pixelFormat != VideoMode::kBGR) {
return nullptr;
}
// Allocate a Grayscale image
auto newImage =
@@ -361,7 +418,9 @@ Image* Frame::ConvertBGRToGray(Image* image) {
}
Image* Frame::ConvertGrayToBGR(Image* image) {
if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
if (!image || image->pixelFormat != VideoMode::kGray) {
return nullptr;
}
// Allocate a BGR image
auto newImage =
@@ -381,8 +440,12 @@ Image* Frame::ConvertGrayToBGR(Image* image) {
}
Image* Frame::ConvertBGRToMJPEG(Image* image, int quality) {
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
if (!m_impl) return nullptr;
if (!image || image->pixelFormat != VideoMode::kBGR) {
return nullptr;
}
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
// Allocate a JPEG image. We don't actually know what the resulting size
@@ -412,8 +475,12 @@ Image* Frame::ConvertBGRToMJPEG(Image* image, int quality) {
}
Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
if (!m_impl) return nullptr;
if (!image || image->pixelFormat != VideoMode::kGray) {
return nullptr;
}
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
// Allocate a JPEG image. We don't actually know what the resulting size
@@ -445,11 +512,14 @@ Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
Image* Frame::GetImageImpl(int width, int height,
VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality) {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
Image* cur = GetNearestImage(width, height, pixelFormat, requiredJpegQuality);
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality))
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality)) {
return cur;
}
WPI_DEBUG4(Instance::GetInstance().logger,
"converting image from " << cur->width << "x" << cur->height
@@ -461,7 +531,9 @@ Image* Frame::GetImageImpl(int width, int height,
// anything else with it. Note that if the destination format is JPEG, we
// still need to do this (unless the width/height/compression were the same,
// in which case we already returned the existing JPEG above).
if (cur->pixelFormat == VideoMode::kMJPEG) cur = ConvertMJPEGToBGR(cur);
if (cur->pixelFormat == VideoMode::kMJPEG) {
cur = ConvertMJPEGToBGR(cur);
}
// Resize
if (!cur->Is(width, height)) {
@@ -485,14 +557,17 @@ Image* Frame::GetImageImpl(int width, int height,
bool Frame::GetCv(cv::Mat& image, int width, int height) {
Image* rawImage = GetImage(width, height, VideoMode::kBGR);
if (!rawImage) return false;
if (!rawImage) {
return false;
}
rawImage->AsMat().copyTo(image);
return true;
}
void Frame::ReleaseFrame() {
for (auto image : m_impl->images)
for (auto image : m_impl->images) {
m_impl->source.ReleaseImage(std::unique_ptr<Image>(image));
}
m_impl->images.clear();
m_impl->source.ReleaseFrameImpl(std::unique_ptr<Impl>(m_impl));
m_impl = nullptr;

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_FRAME_H_
#define CSCORE_FRAME_H_
@@ -45,14 +42,16 @@ class Frame {
};
public:
Frame() noexcept : m_impl{nullptr} {}
Frame() noexcept = default;
Frame(SourceImpl& source, const wpi::Twine& error, Time time);
Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time);
Frame(const Frame& frame) noexcept : m_impl{frame.m_impl} {
if (m_impl) ++m_impl->refcount;
if (m_impl) {
++m_impl->refcount;
}
}
Frame(Frame&& other) noexcept : Frame() { swap(*this, other); }
@@ -74,60 +73,90 @@ class Frame {
Time GetTime() const { return m_impl ? m_impl->time : 0; }
wpi::StringRef GetError() const {
if (!m_impl) return wpi::StringRef{};
if (!m_impl) {
return {};
}
return m_impl->error;
}
int GetOriginalWidth() const {
if (!m_impl) return 0;
if (!m_impl) {
return 0;
}
std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
if (m_impl->images.empty()) {
return 0;
}
return m_impl->images[0]->width;
}
int GetOriginalHeight() const {
if (!m_impl) return 0;
if (!m_impl) {
return 0;
}
std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
if (m_impl->images.empty()) {
return 0;
}
return m_impl->images[0]->height;
}
int GetOriginalPixelFormat() const {
if (!m_impl) return 0;
if (!m_impl) {
return 0;
}
std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
if (m_impl->images.empty()) {
return 0;
}
return m_impl->images[0]->pixelFormat;
}
int GetOriginalJpegQuality() const {
if (!m_impl) return 0;
if (!m_impl) {
return 0;
}
std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
if (m_impl->images.empty()) {
return 0;
}
return m_impl->images[0]->jpegQuality;
}
Image* GetExistingImage(size_t i = 0) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
if (i >= m_impl->images.size()) return nullptr;
if (i >= m_impl->images.size()) {
return nullptr;
}
return m_impl->images[i];
}
Image* GetExistingImage(int width, int height) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height)) return i;
if (i->Is(width, height)) {
return i;
}
}
return nullptr;
}
Image* GetExistingImage(int width, int height,
VideoMode::PixelFormat pixelFormat) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height, pixelFormat)) return i;
if (i->Is(width, height, pixelFormat)) {
return i;
}
}
return nullptr;
}
@@ -135,10 +164,14 @@ class Frame {
Image* GetExistingImage(int width, int height,
VideoMode::PixelFormat pixelFormat,
int jpegQuality) const {
if (!m_impl) return nullptr;
if (!m_impl) {
return nullptr;
}
std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height, pixelFormat, jpegQuality)) return i;
if (i->Is(width, height, pixelFormat, jpegQuality)) {
return i;
}
}
return nullptr;
}
@@ -149,7 +182,9 @@ class Frame {
int jpegQuality = -1) const;
Image* Convert(Image* image, VideoMode::PixelFormat pixelFormat) {
if (pixelFormat == VideoMode::kMJPEG) return nullptr;
if (pixelFormat == VideoMode::kMJPEG) {
return nullptr;
}
return ConvertImpl(image, pixelFormat, -1, 80);
}
Image* ConvertToMJPEG(Image* image, int requiredQuality,
@@ -168,7 +203,9 @@ class Frame {
Image* ConvertGrayToMJPEG(Image* image, int quality);
Image* GetImage(int width, int height, VideoMode::PixelFormat pixelFormat) {
if (pixelFormat == VideoMode::kMJPEG) return nullptr;
if (pixelFormat == VideoMode::kMJPEG) {
return nullptr;
}
return GetImageImpl(width, height, pixelFormat, -1, 80);
}
Image* GetImageMJPEG(int width, int height, int requiredQuality,
@@ -188,11 +225,13 @@ class Frame {
Image* GetImageImpl(int width, int height, VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality);
void DecRef() {
if (m_impl && --(m_impl->refcount) == 0) ReleaseFrame();
if (m_impl && --(m_impl->refcount) == 0) {
ReleaseFrame();
}
}
void ReleaseFrame();
Impl* m_impl;
Impl* m_impl{nullptr};
};
} // namespace cs

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_HANDLE_H_
#define CSCORE_HANDLE_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "HttpCameraImpl.h"
@@ -33,26 +30,36 @@ HttpCameraImpl::~HttpCameraImpl() {
m_monitorCond.notify_one();
// join monitor thread
if (m_monitorThread.joinable()) m_monitorThread.join();
if (m_monitorThread.joinable()) {
m_monitorThread.join();
}
// Close file if it's open
{
std::scoped_lock lock(m_mutex);
if (m_streamConn) m_streamConn->stream->close();
if (m_settingsConn) m_settingsConn->stream->close();
if (m_streamConn) {
m_streamConn->stream->close();
}
if (m_settingsConn) {
m_settingsConn->stream->close();
}
}
// force wakeup of camera thread in case it's waiting on cv
m_sinkEnabledCond.notify_one();
// join camera thread
if (m_streamThread.joinable()) m_streamThread.join();
if (m_streamThread.joinable()) {
m_streamThread.join();
}
// force wakeup of settings thread
m_settingsCond.notify_one();
// join settings thread
if (m_settingsThread.joinable()) m_settingsThread.join();
if (m_settingsThread.joinable()) {
m_settingsThread.join();
}
}
void HttpCameraImpl::Start() {
@@ -69,7 +76,9 @@ void HttpCameraImpl::MonitorThreadMain() {
m_monitorCond.wait_for(lock, std::chrono::seconds(1),
[=] { return !m_active; });
if (!m_active) break;
if (!m_active) {
break;
}
// check to see if we got any frames, and close the stream if not
// (this will result in an error at the read point, and ultimately
@@ -96,20 +105,28 @@ void HttpCameraImpl::StreamThreadMain() {
// disconnect if not enabled
if (!IsEnabled()) {
std::unique_lock lock(m_mutex);
if (m_streamConn) m_streamConn->stream->close();
if (m_streamConn) {
m_streamConn->stream->close();
}
// Wait for enable
m_sinkEnabledCond.wait(lock, [=] { return !m_active || IsEnabled(); });
if (!m_active) return;
if (!m_active) {
return;
}
}
// connect
wpi::SmallString<64> boundary;
wpi::HttpConnection* conn = DeviceStreamConnect(boundary);
if (!m_active) break;
if (!m_active) {
break;
}
// keep retrying
if (!conn) continue;
if (!conn) {
continue;
}
// update connected since we're actually connected
SetConnected(true);
@@ -137,7 +154,9 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
std::this_thread::sleep_for(std::chrono::seconds(1));
return nullptr;
}
if (m_nextLocation >= m_locations.size()) m_nextLocation = 0;
if (m_nextLocation >= m_locations.size()) {
m_nextLocation = 0;
}
req = wpi::HttpRequest{m_locations[m_nextLocation++], m_streamSettings};
m_streamSettingsUpdated = false;
}
@@ -146,7 +165,9 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
auto stream =
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
if (!m_active || !stream) return nullptr;
if (!m_active || !stream) {
return nullptr;
}
auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
wpi::HttpConnection* conn = connPtr.get();
@@ -218,24 +239,33 @@ void HttpCameraImpl::DeviceStream(wpi::raw_istream& is,
// streaming loop
while (m_active && !is.has_error() && IsEnabled() && numErrors < 3 &&
!m_streamSettingsUpdated) {
if (!FindMultipartBoundary(is, boundary, nullptr)) break;
if (!FindMultipartBoundary(is, boundary, nullptr)) {
break;
}
// Read the next two characters after the boundary (normally \r\n)
// Handle just \n for LabVIEW however
char eol[2];
is.read(eol, 1);
if (!m_active || is.has_error()) break;
if (!m_active || is.has_error()) {
break;
}
if (eol[0] != '\n') {
is.read(eol + 1, 1);
if (!m_active || is.has_error()) break;
if (!m_active || is.has_error()) {
break;
}
// End-of-stream is indicated with trailing --
if (eol[0] == '-' && eol[1] == '-') break;
if (eol[0] == '-' && eol[1] == '-') {
break;
}
}
if (!DeviceStreamFrame(is, imageBuf))
if (!DeviceStreamFrame(is, imageBuf)) {
++numErrors;
else
} else {
numErrors = 0;
}
}
}
@@ -280,7 +310,9 @@ bool HttpCameraImpl::DeviceStreamFrame(wpi::raw_istream& is,
// the data directly into it.
auto image = AllocImage(VideoMode::PixelFormat::kMJPEG, 0, 0, contentLength);
is.read(image->data(), contentLength);
if (!m_active || is.has_error()) return false;
if (!m_active || is.has_error()) {
return false;
}
int width, height;
if (!GetJpegSize(image->str(), &width, &height)) {
SWARNING("did not receive a JPEG image");
@@ -302,7 +334,9 @@ void HttpCameraImpl::SettingsThreadMain() {
m_settingsCond.wait(lock, [=] {
return !m_active || (m_prefLocation != -1 && !m_settings.empty());
});
if (!m_active) break;
if (!m_active) {
break;
}
// Build the request
req = wpi::HttpRequest{m_locations[m_prefLocation], m_settings};
@@ -319,7 +353,9 @@ void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
auto stream =
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
if (!m_active || !stream) return;
if (!m_active || !stream) {
return;
}
auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
wpi::HttpConnection* conn = connPtr.get();
@@ -332,7 +368,9 @@ void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
// Just need a handshake as settings are sent via GET parameters
std::string warn;
if (!conn->Handshake(req, &warn)) SWARNING(GetName() << ": " << warn);
if (!conn->Handshake(req, &warn)) {
SWARNING(GetName() << ": " << warn);
}
conn->stream->close();
}
@@ -366,7 +404,9 @@ bool HttpCameraImpl::SetUrls(wpi::ArrayRef<std::string> urls,
std::vector<std::string> HttpCameraImpl::GetUrls() const {
std::scoped_lock lock(m_mutex);
std::vector<std::string> urls;
for (const auto& loc : m_locations) urls.push_back(loc.url);
for (const auto& loc : m_locations) {
urls.push_back(loc.url);
}
return urls;
}
@@ -396,7 +436,9 @@ void HttpCameraImpl::CreateEnumProperty(
auto& enumChoices = m_propertyData.back()->enumChoices;
enumChoices.clear();
for (const auto& choice : choices) enumChoices.emplace_back(choice);
for (const auto& choice : choices) {
enumChoices.emplace_back(choice);
}
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
m_propertyData.size() + 1, CS_PROP_ENUM,
@@ -471,7 +513,9 @@ void HttpCameraImpl::SetExposureManual(int value, CS_Status* status) {
}
bool HttpCameraImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
if (mode.pixelFormat != VideoMode::kMJPEG) return false;
if (mode.pixelFormat != VideoMode::kMJPEG) {
return false;
}
std::scoped_lock lock(m_mutex);
m_mode = mode;
m_streamSettingsUpdated = true;
@@ -530,7 +574,9 @@ CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
inst.notifier, inst.telemetry);
break;
}
if (!source->SetUrls(url.str(), status)) return 0;
if (!source->SetUrls(url.str(), status)) {
return 0;
}
return inst.CreateSource(CS_SOURCE_HTTP, source);
}
@@ -544,7 +590,9 @@ CS_Source CreateHttpCamera(const wpi::Twine& name,
}
auto source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
inst.notifier, inst.telemetry);
if (!source->SetUrls(urls, status)) return 0;
if (!source->SetUrls(urls, status)) {
return 0;
}
return inst.CreateSource(CS_SOURCE_HTTP, source);
}
@@ -595,7 +643,9 @@ CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls,
CS_Status* status) {
wpi::SmallVector<std::string, 4> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) vec.push_back(urls[i]);
for (int i = 0; i < count; ++i) {
vec.push_back(urls[i]);
}
return cs::CreateHttpCamera(name, vec, kind, status);
}
@@ -607,7 +657,9 @@ void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count,
CS_Status* status) {
wpi::SmallVector<std::string, 4> vec;
vec.reserve(count);
for (int i = 0; i < count; ++i) vec.push_back(urls[i]);
for (int i = 0; i < count; ++i) {
vec.push_back(urls[i]);
}
cs::SetHttpCameraUrls(source, vec, status);
}
@@ -616,13 +668,19 @@ char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status) {
char** out =
static_cast<char**>(wpi::safe_malloc(urls.size() * sizeof(char*)));
*count = urls.size();
for (size_t i = 0; i < urls.size(); ++i) out[i] = cs::ConvertToC(urls[i]);
for (size_t i = 0; i < urls.size(); ++i) {
out[i] = cs::ConvertToC(urls[i]);
}
return out;
}
void CS_FreeHttpCameraUrls(char** urls, int count) {
if (!urls) return;
for (int i = 0; i < count; ++i) std::free(urls[i]);
if (!urls) {
return;
}
for (int i = 0; i < count; ++i) {
std::free(urls[i]);
}
std::free(urls);
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_HTTPCAMERAIMPL_H_
#define CSCORE_HTTPCAMERAIMPL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_IMAGE_H_
#define CSCORE_IMAGE_H_
@@ -37,7 +34,7 @@ class Image {
Image& operator=(const Image&) = delete;
// Getters
operator wpi::StringRef() const { return str(); }
operator wpi::StringRef() const { return str(); } // NOLINT
wpi::StringRef str() const { return wpi::StringRef(data(), size()); }
size_t capacity() const { return m_data.capacity(); }
const char* data() const {

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "Instance.h"
@@ -25,14 +22,15 @@ static void def_log_func(unsigned int level, const char* file,
}
wpi::StringRef levelmsg;
if (level >= 50)
if (level >= 50) {
levelmsg = "CRITICAL: ";
else if (level >= 40)
} else if (level >= 40) {
levelmsg = "ERROR: ";
else if (level >= 30)
} else if (level >= 30) {
levelmsg = "WARNING: ";
else
} else {
return;
}
oss << "CS: " << levelmsg << msg << " (" << wpi::sys::path::filename(file)
<< ':' << line << ")\n";
wpi::errs() << oss.str();
@@ -42,7 +40,7 @@ Instance::Instance() : telemetry(notifier), networkListener(logger, notifier) {
SetDefaultLogger();
}
Instance::~Instance() {}
Instance::~Instance() = default;
Instance& Instance::GetInstance() {
static Instance* inst = new Instance;
@@ -58,7 +56,9 @@ void Instance::Shutdown() {
notifier.Stop();
}
void Instance::SetDefaultLogger() { logger.SetLogger(def_log_func); }
void Instance::SetDefaultLogger() {
logger.SetLogger(def_log_func);
}
std::pair<CS_Source, std::shared_ptr<SourceData>> Instance::FindSource(
const SourceImpl& source) {
@@ -87,11 +87,13 @@ CS_Sink Instance::CreateSink(CS_SinkKind kind, std::shared_ptr<SinkImpl> sink) {
}
void Instance::DestroySource(CS_Source handle) {
if (auto data = m_sources.Free(handle))
if (auto data = m_sources.Free(handle)) {
notifier.NotifySource(data->source->GetName(), handle, CS_SOURCE_DESTROYED);
}
}
void Instance::DestroySink(CS_Sink handle) {
if (auto data = m_sinks.Free(handle))
if (auto data = m_sinks.Free(handle)) {
notifier.NotifySink(data->sink->GetName(), handle, CS_SINK_DESTROYED);
}
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_INSTANCE_H_
#define CSCORE_INSTANCE_H_
@@ -26,7 +23,7 @@ namespace cs {
struct SourceData {
SourceData(CS_SourceKind kind_, std::shared_ptr<SourceImpl> source_)
: kind{kind_}, refCount{0}, source{source_} {}
: kind{kind_}, refCount{0}, source{std::move(source_)} {}
CS_SourceKind kind;
std::atomic_int refCount;
@@ -35,7 +32,7 @@ struct SourceData {
struct SinkData {
explicit SinkData(CS_SinkKind kind_, std::shared_ptr<SinkImpl> sink_)
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{std::move(sink_)} {}
CS_SinkKind kind;
std::atomic_int refCount;
@@ -101,7 +98,9 @@ class Instance {
CS_Source source, wpi::SmallVectorImpl<CS_Sink>& vec) {
vec.clear();
m_sinks.ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
if (source == data.sourceHandle.load()) vec.push_back(sinkHandle);
if (source == data.sourceHandle.load()) {
vec.push_back(sinkHandle);
}
});
return vec;
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "JpegUtil.h"
@@ -50,28 +47,43 @@ static const unsigned char dhtData[] = {
0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
bool IsJpeg(wpi::StringRef data) {
if (data.size() < 11) return false;
if (data.size() < 11) {
return false;
}
// Check for valid SOI
auto bytes = data.bytes_begin();
if (bytes[0] != 0xff || bytes[1] != 0xd8) return false;
if (bytes[0] != 0xff || bytes[1] != 0xd8) {
return false;
}
return true;
}
bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
if (!IsJpeg(data)) return false;
if (!IsJpeg(data)) {
return false;
}
data = data.substr(2); // Get to the first block
auto bytes = data.bytes_begin();
for (;;) {
if (data.size() < 4) return false; // EOF
bytes = data.bytes_begin();
if (bytes[0] != 0xff) return false; // not a tag
if (bytes[1] == 0xd9) return false; // EOI without finding SOF?
if (bytes[1] == 0xda) return false; // SOS without finding SOF?
if (data.size() < 4) {
return false; // EOF
}
auto bytes = data.bytes_begin();
if (bytes[0] != 0xff) {
return false; // not a tag
}
if (bytes[1] == 0xd9) {
return false; // EOI without finding SOF?
}
if (bytes[1] == 0xda) {
return false; // SOS without finding SOF?
}
if (bytes[1] == 0xc0) {
// SOF contains the file size
if (data.size() < 9) return false;
if (data.size() < 9) {
return false;
}
*height = bytes[5] * 256 + bytes[6];
*width = bytes[7] * 256 + bytes[8];
return true;
@@ -83,20 +95,31 @@ bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF) {
wpi::StringRef sdata(data, *size);
if (!IsJpeg(sdata)) return false;
if (!IsJpeg(sdata)) {
return false;
}
*locSOF = *size;
// Search until SOS for DHT tag
sdata = sdata.substr(2); // Get to the first block
auto bytes = sdata.bytes_begin();
for (;;) {
if (sdata.size() < 4) return false; // EOF
bytes = sdata.bytes_begin();
if (bytes[0] != 0xff) return false; // not a tag
if (bytes[1] == 0xda) break; // SOS
if (bytes[1] == 0xc4) return false; // DHT
if (bytes[1] == 0xc0) *locSOF = sdata.data() - data; // SOF
if (sdata.size() < 4) {
return false; // EOF
}
auto bytes = sdata.bytes_begin();
if (bytes[0] != 0xff) {
return false; // not a tag
}
if (bytes[1] == 0xda) {
break; // SOS
}
if (bytes[1] == 0xc4) {
return false; // DHT
}
if (bytes[1] == 0xc0) {
*locSOF = sdata.data() - data; // SOF
}
// Go to the next block
sdata = sdata.substr(bytes[2] * 256 + bytes[3] + 2);
}
@@ -129,18 +152,26 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
// read SOI and first marker
buf.resize(4);
is.read(&(*buf.begin()), 4);
if (is.has_error()) return false;
if (is.has_error()) {
return false;
}
// Check for valid SOI
auto bytes = reinterpret_cast<const unsigned char*>(buf.data());
if (bytes[0] != 0xff || bytes[1] != 0xd8) return false;
if (bytes[0] != 0xff || bytes[1] != 0xd8) {
return false;
}
size_t pos = 2; // point to first marker
for (;;) {
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
if (bytes[0] != 0xff) return false; // not a marker
if (bytes[0] != 0xff) {
return false; // not a marker
}
unsigned char marker = bytes[1];
if (marker == 0xd9) return true; // EOI, we're done
if (marker == 0xd9) {
return true; // EOI, we're done
}
if (marker == 0xda) {
// SOS: need to keep reading until we reach a normal marker.
@@ -150,12 +181,15 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
bool maybeMarker = false;
for (;;) {
ReadInto(is, buf, 1);
if (is.has_error()) return false;
if (is.has_error()) {
return false;
}
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
if (maybeMarker) {
if (bytes[0] != 0x00 && bytes[0] != 0xff &&
(bytes[0] < 0xd0 || bytes[0] > 0xd7))
(bytes[0] < 0xd0 || bytes[0] > 0xd7)) {
break;
}
maybeMarker = false;
} else if (bytes[0] == 0xff) {
maybeMarker = true;
@@ -168,7 +202,9 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
// A normal block. Read the length
ReadInto(is, buf, 2); // read length
if (is.has_error()) return false;
if (is.has_error()) {
return false;
}
// Point to length
pos += 2;
@@ -177,7 +213,9 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
// Read the block and the next marker
size_t blockLength = bytes[0] * 256 + bytes[1];
ReadInto(is, buf, blockLength);
if (is.has_error()) return false;
if (is.has_error()) {
return false;
}
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
// Special block processing

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_JPEGUTIL_H_
#define CSCORE_JPEGUTIL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_LOG_H_
#define CSCORE_LOG_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "MjpegServerImpl.h"
@@ -78,7 +75,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
explicit ConnThread(const wpi::Twine& name, wpi::Logger& logger)
: m_name(name.str()), m_logger(logger) {}
void Main();
void Main() override;
bool ProcessCommand(wpi::raw_ostream& os, SourceImpl& source,
wpi::StringRef parameters, bool respond);
@@ -111,13 +108,17 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
void StartStream() {
std::scoped_lock lock(m_mutex);
if (m_source) m_source->EnableSink();
if (m_source) {
m_source->EnableSink();
}
m_streaming = true;
}
void StopStream() {
std::scoped_lock lock(m_mutex);
if (m_source) m_source->DisableSink();
if (m_source) {
m_source->DisableSink();
}
m_streaming = false;
}
};
@@ -143,7 +144,9 @@ static void SendHeader(wpi::raw_ostream& os, int code,
os << "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: *\r\n";
wpi::SmallString<128> extraBuf;
wpi::StringRef extraStr = extra.toStringRef(extraBuf);
if (!extraStr.empty()) os << extraStr << "\r\n";
if (!extraStr.empty()) {
os << extraStr << "\r\n";
}
os << "\r\n"; // header ends with a blank line
}
@@ -201,9 +204,13 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
// split out next param and value
wpi::StringRef rawParam, rawValue;
std::tie(rawParam, parameters) = parameters.split('&');
if (rawParam.empty()) continue; // ignore "&&"
if (rawParam.empty()) {
continue; // ignore "&&"
}
std::tie(rawParam, rawValue) = rawParam.split('=');
if (rawParam.empty() || rawValue.empty()) continue; // ignore "param="
if (rawParam.empty() || rawValue.empty()) {
continue; // ignore "param="
}
SDEBUG4("HTTP parameter \"" << rawParam << "\" value \"" << rawValue
<< "\"");
@@ -285,7 +292,9 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
}
// ignore name parameter
if (param == "name") continue;
if (param == "name") {
continue;
}
// try to assign parameter
auto prop = source.GetPropertyIndex(param);
@@ -342,7 +351,9 @@ void MjpegServerImpl::ConnThread::SendHTMLHeadTitle(
// Send the root html file with controls for all the settable properties.
void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
SourceImpl& source, bool header) {
if (header) SendHeader(os, 200, "OK", "text/html");
if (header) {
SendHeader(os, 200, "OK", "text/html");
}
SendHTMLHeadTitle(os);
os << startRootPage;
@@ -351,7 +362,9 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
for (auto prop : source.EnumerateProperties(properties_vec, &status)) {
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
if (name.startswith("raw_")) continue;
if (name.startswith("raw_")) {
continue;
}
auto kind = source.GetPropertyKind(prop);
os << "<p />"
<< "<label for=\"" << name << "\">" << name << "</label>\n";
@@ -360,10 +373,11 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
os << "<input id=\"" << name
<< "\" type=\"checkbox\" onclick=\"update('" << name
<< "', this.checked ? 1 : 0)\" ";
if (source.GetProperty(prop, &status) != 0)
if (source.GetProperty(prop, &status) != 0) {
os << "checked />\n";
else
} else {
os << " />\n";
}
break;
case CS_PROP_INTEGER: {
auto valI = source.GetProperty(prop, &status);
@@ -384,11 +398,14 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
int j = 0;
for (auto choice = choices.begin(), end = choices.end(); choice != end;
++j, ++choice) {
if (choice->empty()) continue; // skip empty choices
if (choice->empty()) {
continue; // skip empty choices
}
// replace any non-printable characters in name with spaces
wpi::SmallString<128> ch_name;
for (char ch : *choice)
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
}
os << "<input id=\"" << name << j << "\" type=\"radio\" name=\""
<< name << "\" value=\"" << ch_name << "\" onclick=\"update('"
<< name << "', " << j << ")\"";
@@ -419,8 +436,9 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
&status);
if (status == CS_OK) {
os << "<p>USB device path: " << info.path << '\n';
for (auto&& path : info.otherPaths)
for (auto&& path : info.otherPaths) {
os << "<p>Alternate device path: " << path << '\n';
}
}
os << "<p>Supported Video Modes:</p>\n";
@@ -464,17 +482,20 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
// Send a JSON file which is contains information about the source parameters.
void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
SourceImpl& source, bool header) {
if (header) SendHeader(os, 200, "OK", "application/json");
if (header) {
SendHeader(os, 200, "OK", "application/json");
}
os << "{\n\"controls\": [\n";
wpi::SmallVector<int, 32> properties_vec;
bool first = true;
CS_Status status = 0;
for (auto prop : source.EnumerateProperties(properties_vec, &status)) {
if (first)
if (first) {
first = false;
else
} else {
os << ",\n";
}
os << '{';
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
@@ -514,10 +535,14 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
int j = 0;
for (auto choice = choices.begin(), end = choices.end(); choice != end;
++j, ++choice) {
if (j != 0) os << ", ";
if (j != 0) {
os << ", ";
}
// replace any non-printable characters in name with spaces
wpi::SmallString<128> ch_name;
for (char ch : *choice) ch_name.push_back(std::isprint(ch) ? ch : ' ');
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
}
os << '"' << j << "\": \"" << ch_name << '"';
}
os << "}\n";
@@ -527,10 +552,11 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
os << "\n],\n\"modes\": [\n";
first = true;
for (auto mode : source.EnumerateVideoModes(&status)) {
if (first)
if (first) {
first = false;
else
} else {
os << ",\n";
}
os << '{';
os << "\n\"pixelFormat\": \"";
switch (mode.pixelFormat) {
@@ -599,7 +625,9 @@ MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
m_serverThread = std::thread(&MjpegServerImpl::ServerThreadMain, this);
}
MjpegServerImpl::~MjpegServerImpl() { Stop(); }
MjpegServerImpl::~MjpegServerImpl() {
Stop();
}
void MjpegServerImpl::Stop() {
m_active = false;
@@ -608,18 +636,24 @@ void MjpegServerImpl::Stop() {
m_acceptor->shutdown();
// join server thread
if (m_serverThread.joinable()) m_serverThread.join();
if (m_serverThread.joinable()) {
m_serverThread.join();
}
// close streams
for (auto& connThread : m_connThreads) {
if (auto thr = connThread.GetThread()) {
if (thr->m_stream) thr->m_stream->close();
if (thr->m_stream) {
thr->m_stream->close();
}
}
connThread.Stop();
}
// wake up connection threads by forcing an empty frame to be sent
if (auto source = GetSource()) source->Wakeup();
if (auto source = GetSource()) {
source->Wakeup();
}
}
// Send HTTP response and a stream of JPG-frames
@@ -642,10 +676,14 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
Frame::Time lastFrameTime = 0;
Frame::Time timePerFrame = 0;
if (m_fps != 0) timePerFrame = 1000000.0 / m_fps;
if (m_fps != 0) {
timePerFrame = 1000000.0 / m_fps;
}
Frame::Time averageFrameTime = 0;
Frame::Time averagePeriod = 1000000; // 1 second window
if (averagePeriod < timePerFrame) averagePeriod = timePerFrame * 10;
if (averagePeriod < timePerFrame) {
averagePeriod = timePerFrame * 10;
}
StartStream();
while (m_active && !os.has_error()) {
@@ -658,7 +696,9 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
}
SDEBUG4("waiting for frame");
Frame frame = source->GetNextFrame(0.225); // blocks
if (!m_active) break;
if (!m_active) {
break;
}
if (!frame) {
// Bad frame; sleep for 20 ms so we don't consume all processor time.
os << "\r\n"; // Keep connection alive
@@ -807,8 +847,12 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
// The end of the request is marked by a single, empty line
wpi::SmallString<128> lineBuf;
for (;;) {
if (is.getline(lineBuf, 4096).startswith("\n")) break;
if (is.has_error()) return;
if (is.getline(lineBuf, 4096).startswith("\n")) {
break;
}
if (is.has_error()) {
return;
}
}
// Send response
@@ -816,7 +860,9 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
case kStream:
if (auto source = GetSource()) {
SDEBUG("request for stream " << source->GetName());
if (!ProcessCommand(os, *source, parameters, false)) return;
if (!ProcessCommand(os, *source, parameters, false)) {
return;
}
}
SendStream(os);
break;
@@ -832,10 +878,11 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
break;
case kGetSettings:
SDEBUG("request for JSON file");
if (auto source = GetSource())
if (auto source = GetSource()) {
SendJSON(os, *source, true);
else
} else {
SendError(os, 404, "Resource not found");
}
break;
case kGetSourceConfig:
SDEBUG("request for JSON file");
@@ -869,7 +916,9 @@ void MjpegServerImpl::ConnThread::Main() {
while (m_active) {
while (!m_stream) {
m_cond.wait(lock);
if (!m_active) return;
if (!m_active) {
return;
}
}
lock.unlock();
ProcessRequest();
@@ -892,7 +941,9 @@ void MjpegServerImpl::ServerThreadMain() {
m_active = false;
return;
}
if (!m_active) return;
if (!m_active) {
return;
}
SDEBUG("client connection from " << stream->getPeerIP());
@@ -942,9 +993,13 @@ void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
if (auto thr = connThread.GetThread()) {
if (thr->m_source != source) {
bool streaming = thr->m_streaming;
if (thr->m_source && streaming) thr->m_source->DisableSink();
if (thr->m_source && streaming) {
thr->m_source->DisableSink();
}
thr->m_source = source;
if (source && streaming) thr->m_source->EnableSink();
if (source && streaming) {
thr->m_source->EnableSink();
}
}
}
}

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2016-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_MJPEGSERVERIMPL_H_
#define CSCORE_MJPEGSERVERIMPL_H_

View File

@@ -1,9 +1,6 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2015-2018 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. */
/*----------------------------------------------------------------------------*/
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#ifndef CSCORE_NETWORKLISTENER_H_
#define CSCORE_NETWORKLISTENER_H_

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