Compare commits

...

185 Commits

Author SHA1 Message Date
Peter Johnson
d66555e42f [datalogtool] Add datalogtool
This is a support tool for datalog file conversion (and eventually
download/remote datalog file management).
2022-02-26 09:49:34 -08:00
Peter Johnson
9f52d8a3b1 [wpilib] DriverStation: Add DataLog support for modes and joystick data 2022-02-26 09:49:34 -08:00
Peter Johnson
757ea91932 [wpilib] Add DataLogManager
This creates a default log file that captures NT changes and
automatically renames the log file based on time and match info.

DriverStation joystick logging will be implemented by the DriverStation
class instead.
2022-02-26 09:49:34 -08:00
Peter Johnson
02a804f1c5 [ntcore] Add DataLog support 2022-02-26 09:49:34 -08:00
Peter Johnson
9b500df0d9 [wpiutil] Add high speed data logging 2022-02-26 09:49:34 -08:00
Peter Johnson
5a89575b3a [wpiutil] Import customized LLVM MemoryBuffer 2022-02-26 09:49:34 -08:00
Peter Johnson
b8c4d7527b [wpiutil] Add MappedFileRegion 2022-02-26 09:49:34 -08:00
Alberto Jahuey Moncada
ac5d46cfa7 [wpilibc] Fix ProfiledPID SetTolerance default velocity value (#4054)
When trying to set the tolerance of a ProfiledPID, it fails if you don't give it a velocity value. It was missing a conversion from double to the appropiate unit.
2022-02-25 20:27:56 -08:00
Thad House
bc9e96e86f [wpilib] Absolute Encoder API and behavior fixes (#4052)
SetPositionOffset was added. Been requested multiple times, and easy to implement.

The javadocs mentioned GetPositionInRotation. It has tripped up many people how to get the absolute position from the encoder (You currently have to have precreated the DutyCycle object). Add this method (as GetAbsolutePostition) to make this easier to do.

The checks for making sure a matching set of values was read was doing direct double comparisions. This worked ok in the DutyCycle case, but has problems in the analog case. Solve this by using an epsilon comparison.

And finally, scale AnalogEncoders analog input to 0-1 instead of 0-5. This was reported a few years ago, but the issue was missed. This caused the encoder to count from 0-5, then 1-6, then 2-7 etc. This is solved and now works correctly.

Closes #3188
Closes #4046
Closes #4051

And fixes the following issue on CD
https://www.chiefdelphi.com/t/wpilib-analogencoder-java/372649
2022-02-24 22:45:15 -08:00
Dustin Spicuzza
f88c435dd0 [hal] Add mechanism to cancel all periodic callbacks (#4049) 2022-02-23 09:46:01 -08:00
Leonard Abbas
e4b91005cf [examples] Update SwerveModule constructor doc (NFC) (#4042)
Renamed "port" to "channel" for consistency.
2022-02-22 09:26:16 -08:00
Leonard Abbas
a260bfd83b [examples] Remove "this" keyword from SwerveModule (#4043) 2022-02-21 09:27:00 -08:00
Leonard Abbas
18e262a100 [examples] Fix multiple doc typos in SwerveControllerCommand example (NFC) (#4044) 2022-02-21 09:26:20 -08:00
Dustin Spicuzza
4bd1f526ab [wpilibc] Prevent StopMotor from terminating robot during MotorSafety check (#4038)
- Nothing else in that function can throw, so protecting StopMotor should be sufficient
- Fixes #4036
2022-02-19 20:42:10 -08:00
Dustin Spicuzza
27847d7eb2 [sim] Expose GUI control functions via HAL_RegisterExtension (#4034) 2022-02-19 20:40:25 -08:00
Dustin Spicuzza
b2a8d3f0f3 [wpilibc] Add mechanism to reset MotorSafety list (#4037) 2022-02-19 20:38:30 -08:00
Tyler Veness
49adac9564 [wpilib] Check for signedness in ArcadeDriveIK() (#4028)
If xSpeed == -0.0 and zRotation > 0, the algorithm assumes it's in the
third quadrant instead of the first since +0.0 == -0.0.

Also added tests for inverse kinematic functions, fixed some
MecanumDrive test bugs, and added Java MecanumDrive.driveCartesianIK()
and KilloughDrive.driveCartesianIK() overloads with defaulted gyro angle
that C++ already had.

Fixes #4022.
2022-02-17 18:03:59 -08:00
Peter Johnson
a19d1133b1 [wpiutil] libuv: Fix sign compare warnings in gcc 11.2 (#4031) 2022-02-13 16:56:53 -08:00
Peter Johnson
dde91717e4 [build] cmake: Add ability to customize target warnings (#4032) 2022-02-13 16:53:55 -08:00
Peter Johnson
e9050afd67 [sim] Update sim match time to match real robot (#4024)
The real robot has match time set to -1.0 until it's enabled, and then
counts down. Disabling the robot sets the time to -1.0.

The sim GUI has been updated to add preset buttons for auto and teleop
match times. The enable match timing checkbox has been removed as it's
no longer required.

The DS socket plugin has also been fixed to properly initialize
matchTime to -1.0 and reset it to -1.0 on disable.
2022-02-12 22:31:10 -08:00
sciencewhiz
165d2837cf [wpilib] Preferences: Set Persistent in Init methods (#4025)
Fixes #4018
2022-02-12 22:30:02 -08:00
Peter Johnson
ac7549edca [glass] Fix snprintf truncation warning (#4029) 2022-02-12 22:29:26 -08:00
Jonah Snider
4d96bc72e0 [wpilibj] Fix typos in error messages for non-null assertions (#4014) 2022-02-11 18:11:15 -08:00
Dustin Spicuzza
3411eee20f [hal] Replace hardcoded sim array sizes with constants (#4015) 2022-02-10 00:12:07 -08:00
Dustin Spicuzza
74de97eeca [wpilibc] Add mechanism to reset various global structures (#4007) 2022-02-09 22:14:12 -08:00
sciencewhiz
4e3cc25012 [examples] Fix periodic function rate comment (NFC) (#4013)
Fixes #3979
2022-02-08 13:19:31 -08:00
Dustin Spicuzza
90c1db393e [sim] Add exported functions to control the sim GUI (#3995) 2022-02-07 00:39:45 -08:00
sciencewhiz
2f43274aa4 [wpilibj] MechanismRoot2d: Add flush to setPosition (#4011)
Fixes #4010.
2022-02-06 22:47:33 -08:00
Peter Johnson
aeca09db09 [glass] Support remapping of Enter key (#3994)
This is useful for editing of values without disabling the DS.
2022-02-06 00:11:37 -08:00
Peter Johnson
c107f22c67 [sim] Sim GUI: don't force-show Timing and Other Devices (#4001)
Instead preserve their saved visible state.
2022-02-06 00:11:12 -08:00
Peter Johnson
68fe51e8da [wpigui] Update PFD to latest, fix kdialog multiselect (#4005) 2022-02-06 00:10:43 -08:00
modelmat
8d08d67cf1 [wpigui] PFD: Add console warning if file chooser unavailable (#4003)
Also remove iostream use.
2022-02-06 00:10:20 -08:00
Dustin Spicuzza
4f1782f66e [wpilibc] Only call HAL_Report when initializing SmartDashboard (#4006) 2022-02-06 00:07:55 -08:00
Tyler Veness
3f77725cd3 Remove uses of iostream (#4004)
Most of these were unused, the IMU ones were just debug messages.

The only one that wasn't removed is in portable-file-dialogs.cpp since
the replacement looks less trivial.
2022-02-05 23:00:31 -08:00
Peter Johnson
5635f33a32 [glass] Increase plot depth to 20K points (#3993)
2K was sufficient for simulation because it's possible to pause time,
but isn't quite enough for looking at real robot data. 20K points
is 400 seconds at 50 Hz which should make pausing plots much more
useful.

As every point is looped over, this does increase CPU utilization
somewhat but doesn't seem to have much of an impact for typical
use cases. Increasing this further will necessitate some greater
optimizations (e.g. an initial cull using binary search).
2022-02-04 22:20:38 -08:00
Peter Johnson
bca4b7111b [glass] Fix PlotSeries::SetSource() (#3991)
This can be called in a delayed manner, so it's possible for
m_size to already be at maximum, which results in writing past
the end of the array. Instead, just call AppendValue().
2022-02-04 20:47:11 -08:00
Oblarg
6a6366b0d6 [commands] Add until() as alias for withInterrupt() (#3981)
This is a clearer description for the functionality.
Will deprecate withInterrupt next year.
2022-02-03 22:14:52 -08:00
Thad House
16bf2c70c5 [wpilib] Fix joystick out of range error messages (#3988) 2022-02-03 22:10:44 -08:00
Thad House
4b3edb742c [wpilib] Fix ADIS16448 IMU default constructor not working in Java (#3989)
Also fixes a few related uninitialized variables in C++.
2022-02-03 22:09:12 -08:00
Thad House
fcf23fc9e9 [hal] Fix potential gamedata out of bounds read (#3983)
The size was uninitialized.  If the size is smaller than the data,
NetComm just updates the size and does not initialize the data.
2022-02-01 22:22:48 -08:00
Jan-Felix Abellera
af5ef510c5 [wpilibc] Fix REV PH pulse duration units (#3982) 2022-02-01 20:28:48 -08:00
Jan-Felix Abellera
05401e2b81 [wpilib] Write REV PH firmware version to roboRIO to display on driver station (#3977) 2022-02-01 20:27:43 -08:00
Thad House
9fde0110b6 Update to 2022 v4.0 image (#3944) 2022-01-31 23:26:05 -08:00
sciencewhiz
b03f8ddb2e [examples] fix incorrect variable in Arm Simulation Pref (#3980) 2022-01-31 22:01:31 -08:00
sciencewhiz
a26df2a022 [examples] Update ArmSimulation example to use Preferences (#3976)
This shows more real world usage then hardcoding the setpoint and PID
gains. There were no current examples using Preferences. This will also
be used to update frc-docs article for Preferences.
2022-01-31 00:17:04 -08:00
Oblarg
d68d6674e8 [examples] Armbot: rename kCos to kG (#3975) 2022-01-31 00:16:26 -08:00
sciencewhiz
a8f0f6bb90 [wpilibj] Fix ADIS16448 getRate to return rate instead of angle (#3974) 2022-01-29 20:17:57 -08:00
Thad House
dd9c92d5bf [build] Remove debug info from examples (#3971)
They take up a LOT of disk space.
2022-01-27 20:59:13 -08:00
Thad House
84df14dd70 [rtns] Fix icons (#3972) 2022-01-27 20:58:07 -08:00
sciencewhiz
560094ad92 [examples] Correct Mecanum example axes (#3955) 2022-01-27 20:57:41 -08:00
Jan-Felix Abellera
7ea1be9c01 [wpilibc] Fix typo in hardware version for REV PDH (#3969) 2022-01-27 17:54:38 -08:00
Jan-Felix Abellera
700f13bffd [wpilibj] Make methods public for Java REV PDH (#3970) 2022-01-27 17:54:14 -08:00
Jan-Felix Abellera
b6aa7c1aa9 [wpilibj] Make methods public for Java REVPH (#3968) 2022-01-27 17:53:45 -08:00
Tyler Veness
eb4d183e48 [wpimath] Fix clang-tidy bugprone-integer-division warning (#3966)
The integer conversion is deliberate.
2022-01-26 18:38:45 -08:00
Thad House
77e4e81e1e [wpilib] Add Field widget to BuiltInWidgets in shuffleboard (#3961) 2022-01-24 20:33:11 -08:00
Thad House
88f5cb6eb0 [build] Publish PDBs with C++ tools (#3960) 2022-01-24 20:32:17 -08:00
Tyler Veness
efae552f3e [wpimath] Remove DifferentialDriveKinematics include from odometry (#3958) 2022-01-24 16:02:00 -08:00
sciencewhiz
46b277421a [glass] Update Speed Controller Type name for 2022 WPILib (#3952) 2022-01-21 21:30:44 -08:00
modelmat
42908126b9 [wpilib] Add DCMotorSim (#3910) 2022-01-21 20:42:06 -08:00
Peter Johnson
a467392cbd [wpiutil] StackTrace: Add ability to override default implementation (#3951) 2022-01-21 17:22:41 -08:00
modelmat
78d0bcf49d [templates] Add SimulationInit()/SimulationPeriodic() to robot templates (#3943) 2022-01-21 16:23:46 -08:00
sciencewhiz
02a0ced9b0 [wpilib] MecanumDrive: update docs for axis to match implementation (NFC) (#3942)
Added note that implementation may change in the future, #3930.
2022-01-21 16:22:17 -08:00
shueja-personal
4ccfe1c9f2 [wpilib] Added docs clarification on units for drive class WheelSpeeds (NFC) (#3939) 2022-01-21 15:51:28 -08:00
Peter Johnson
830c0c5c2f [wpilib] MechanismLigament2d: Add getters for color and line weight (#3947)
Also add missing locking in C++.
2022-01-21 15:47:44 -08:00
Peter Johnson
5548a37465 [wpilib] PowerDistribution: Add module type getter (#3948) 2022-01-21 15:46:44 -08:00
Thad House
2f9a600de2 [hal] Fix PCM one shot (#3949) 2022-01-21 15:46:08 -08:00
Thad House
559db11a20 [myRobot] Skip deploying debug libraries for myRobot deploys (#3950) 2022-01-21 15:45:47 -08:00
Lenny Abbas
76c78e295b [examples] Reorder SwerveModules in SwerveControllerCommand example odometry update (#3934) 2022-01-21 11:04:43 -08:00
sciencewhiz
debbd5ff4b [wpilib] Improve PowerDistribution docs (NFC) (#3925)
Add docs for switchable channel.
Use PDP/PDH appropriately and clarify differences.
Fix typos.
2022-01-20 23:33:01 -08:00
Tyler Veness
841174f302 [commands] Change command vendordep JSON version number to 1.0.0 (#3938)
While the number doesn't matter, it being old is confusing a lot of
people.  We never increment the internal vendordep versions, so using a year
version number was a poor choice.

Closes #3921.
2022-01-20 23:32:02 -08:00
sciencewhiz
8c55844f91 [wpilib] Remove comment about Mecanum right side inverted (NFC) (#3929) 2022-01-18 01:00:55 -08:00
Thad House
0b990bf0f5 [hal] Fix PCM sticky faults clear function crashing (#3932)
A call to the PCM clear function was using the wrong handle passed down to the CAN layer, causing an error.
2022-01-18 00:59:51 -08:00
Thad House
104d7e2abc [hal] Don't throw exceptions in PCM JNI (#3933)
Since the CAN bus can easily become disconnected, we don't want this to crash. Instead, we just want this to report errors. This matches previous behavior.
2022-01-18 00:58:26 -08:00
Lenny Abbas
5ba69e1af1 [examples] Updated type in Java SwerveModule (#3928)
Changed turnOutput from var to double in SwerveModule. It doesn't make sense for driveOutput and turnOutput to have different types so they should both be doubles.
2022-01-17 12:20:55 -08:00
Chirag Kaushik
f3a0b5c7d7 [wpimath] Fix Java SimpleMotorFeedforward Docs (NFC) (#3926) 2022-01-17 09:59:04 -08:00
Tyler Veness
7f4265facc [wpimath] Add LinearFilter::FiniteDifference() (#3900)
This allows making more general finite difference filters, like central
finite difference. SysId uses this for acceleration filtering.
2022-01-15 20:18:11 -08:00
Tyler Veness
63d1fb3bed [wpiutil] Modify fmt to not throw on write failure (#3919)
This was causing issues with tools, as the launchers would close stdout/stderr, resulting in write failures.
2022-01-15 20:10:32 -08:00
Tyler Veness
36af6d25a5 [wpimath] Fix input vector in pose estimator docs (NFC) (#3923) 2022-01-15 20:03:39 -08:00
Thad House
8f387f7255 [wpilibj] Switch ControlWord mutex to actual reentrant mutex (#3922)
It seems like the JVM does not handle recursive calls to object monitor based locks correctly. A few bugs in the past have been reported to have caused deadlocks if this occurs. It looks like the version of Java we use is fixed, but there could be other bugs, and it seems like this area of the code isn't tested much. Based on the stacks reported in #3896, it really seems like this is occurring. So we're going to attempt to switch to explicit mutex based classes, which shouldn't have bugs like this, and we will see if that fixes the issue.
2022-01-15 15:24:06 -08:00
David Vo
792e735e08 [wpimath] Move TrajectoryGenerator::SetErrorHandler definition to .cpp (#3920)
Otherwise this function causes linking errors when used on Windows.
2022-01-15 08:58:49 -08:00
Tyler Veness
3b76de83eb [commands] Fix ProfiledPIDCommand use-after-free (#3904)
Fixes #3903.
2022-01-14 23:56:48 -08:00
PJ Reiniger
ad9f738cfa [fieldimages] Fix maven publishing (#3897) 2022-01-14 23:55:10 -08:00
modelmat
49455199e5 [examples] Use left/rightGroup.Get() for simulator inputs to fix inversions (#3908) 2022-01-14 23:54:20 -08:00
modelmat
64426502ea [wpimath] Fix arm -> flywheel typo (NFC) (#3911) 2022-01-14 23:53:45 -08:00
Tyler Veness
8cc112d196 [wpiutil] Fix wpi::array for move-only types (#3917)
Fixes #3916.
2022-01-14 23:53:12 -08:00
Tyler Veness
e78cd49861 [build] Upgrade Java formatter plugins (#3894) 2022-01-11 22:24:16 -08:00
Tyler Veness
cfb4f756d6 [build] Upgrade to shadow 7.1.2 (#3893) 2022-01-11 21:10:15 -08:00
Tyler Veness
ba0908216c [wpimath] Fix crash in KF latency compensator (#3888)
It would crash in C++ if the global measurement was sooner than all the
snapshots.

Align Java with the changes and better document computation approach.
2022-01-09 23:01:04 -08:00
Peter Johnson
a3a0334fad [build] cmake: Move fieldImages to WITH_GUI (#3885)
This will only ever be used by GUI applications, and the jar build
method it uses can misbehave in some cross-compile scenarios.
2022-01-09 20:26:54 -08:00
sciencewhiz
cf7460c3a8 [fieldImages] Add 2022 field (#3883) 2022-01-08 23:24:24 -08:00
Tyler Veness
db0fbb6448 [wpimath] Fix LQR matrix constructor overload for Q, R, and N (#3884)
It was using the continuous B matrix to compute the feedback gain
instead of the discrete B matrix.

Tests were added for the matrix constructor overloads.
2022-01-08 23:23:53 -08:00
sciencewhiz
8ac45f20bb [commands] Update Command documentation (NFC) (#3881)
Add reference to which VendorDep the class is included in.
Add missing OldCommands C++ Documentation (copied from Java).
2022-01-08 11:11:34 -08:00
Tyler Veness
b3707cca0b [wpiutil] Upgrade to fmt 8.1.1 (#3879)
The changes to PneumaticsBase.cpp were to fix errors like the following
from enum classes not being formattable:
```
allwpilib/wpilibc/src/main/native/cpp/PneumaticsBase.cpp:36:9:   required from here
allwpilib/wpiutil/src/main/native/fmtlib/include/fmt/core.h:2672:12: error: use of deleted function ‘fmt::v8::detail::fallback_formatter<T, Char, Enable>::fallback_formatter() [with T = frc::PneumaticsModuleType; Char = char; Enable = void]’
 2672 |   auto f = conditional_t<has_formatter<mapped_type, context>::value,
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2673 |                          formatter<mapped_type, char_type>,
      |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 2674 |                          fallback_formatter<T, char_type>>();
      |                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
2022-01-08 11:10:42 -08:00
Tyler Veness
a69ee3ece9 [wpimath] Const-qualify Twist2d scalar multiply (#3882)
Fixes #3880.
2022-01-08 11:09:29 -08:00
Drew Williams
750d9a30c9 [examples] Fix Eigen out of range error when running example (#3877)
Simple typo fix.
2022-01-08 00:15:26 -08:00
Peter Johnson
41c5b2b5ac [rtns] Add cmake build (#3866)
This needs libssh to build, so on Linux systems it's necessary to
install libssh-dev.
2022-01-08 00:14:48 -08:00
Tyler Veness
6cf3f9b28e [build] Upgrade to Gradle 7.3.3 (#3878)
This is the same version robot projects currently use.
2022-01-08 00:14:27 -08:00
Starlight220
269cf03472 [examples] Add communication examples (e.g. arduino) (#2500)
Co-authored-by: Andrew Dassonville <dassonville.andrew@gmail.com>
2022-01-06 18:08:57 -08:00
sciencewhiz
5ccfc4adbd [oldcommands] Deprecate PIDWrappers, since they use deprecated interfaces (#3868) 2022-01-06 18:05:24 -08:00
Peter Johnson
b6f44f98be [hal] Add warning about onboard I2C (#3871)
Adds HAL layer warning for #3842. This is needed in the case when a
vendor uses the HAL directly rather than using the WPILib I2C class.

This should not result in a duplicate warning for WPILib I2C users due
to the duplicate message checking performed in HAL_SendError().

We don't want to remove the WPILib I2C warning because it gives stack
trace information while the HAL layer one can't.
2022-01-06 17:44:27 -08:00
Peter Johnson
0dca57e9ec [templates] romieducational: Invert drivetrain and disable motor safety (#3869) 2022-01-06 11:29:15 -08:00
Tyler Veness
22c4da152e [wpilib] Add GetRate() to ADIS classes (#3864)
The angular rate is treated somewhat like an angle during calibration,
but the datasheet says it's angular rate. The variables were renamed to
make this clearer.
2022-01-04 22:26:23 -08:00
Peter Johnson
05d66f862d [templates] Change the template ordering to put command based first (#3863)
Previously it was a bit buried.
2022-01-04 21:23:57 -08:00
Dustin Spicuzza
b09f5b2cf2 [wpilibc] Add virtual dtor for LinearSystemSim (#3861) 2022-01-03 21:25:02 -08:00
Tyler Veness
a2510aaa0e [wpilib] Make ADIS IMU classes unit-safe (#3860)
The gyro rate getters were removed since that data isn't available.
2022-01-03 20:00:53 -08:00
Tyler Veness
947f589916 [wpilibc] Rename ADIS_16470_IMU.cpp to match class name (#3859) 2022-01-03 17:53:57 -08:00
Peter Johnson
bbd8980a20 [myRobot] Fix cameraserver library order (#3858) 2022-01-03 11:59:29 -08:00
Tyler Veness
831052f118 [wpilib] Add simulation support to ADIS classes (#3857) 2022-01-03 11:44:12 -08:00
Noah Andrews
c137569f91 [wpilib] Throw exception if the REV Pneumatic Hub firmware version is older than 22.0.0 (#3853) 2022-01-03 11:09:30 -08:00
sciencewhiz
dae61226fa Fix Maven Artifacts readme (#3856)
Add wpiutil to wpimath
Add wpimath to wpilibj and wpilibc
2022-01-03 10:18:49 -08:00
sciencewhiz
3ad4594a88 Update Maven artifacts readme for 2022 (#3855) 2022-01-01 13:28:36 -08:00
Matteo Kimura
112acb9a62 [wpilibc] Move ADIS IMU constants to inside class (#3852) 2022-01-01 11:40:28 -08:00
Peter Johnson
ecee224e81 [wpilib] Allow SendableCameraWrappers to take arbitrary URLs (#3850)
Useful for adding cameras that are streamed from a coprocessor

Co-authored-by: Peter Johnson <johnson.peter@gmail.com>
Co-authored-by: Sam Carlberg <sam.carlberg@gmail.com>
2022-01-01 10:10:37 -08:00
Peter Johnson
a3645dea34 LICENSE: Bump year range to include 2022 (#3854) 2022-01-01 00:00:16 -08:00
Jan-Felix Abellera
7c09f44898 [wpilib] Use PSI for compressor config and sensor reading (#3847)
This adds the REV Analog Pressure Sensor PSI to volt (and vice versa) conversion to allow setting the compressor config in PSI and getting the sensor reading in PSI. Also adds input validation for pressure values at the higher level.

Co-authored-by: Tyler Veness <calcmogul@gmail.com>
2021-12-31 21:04:56 -08:00
Peter Johnson
f401ea9aae [wpigui] Remove wpiutil linkage (#3851)
It was only being used for fs::remove() (added in #3463), which is easily
replaced by std::remove().

The code change does not affect the WPILib tools, as this code is not used when JSON save files are used.
2021-12-31 07:56:31 -08:00
Peter Johnson
bf8517f1e6 [wpimath] TimeInterpolatableBufferTest: Fix lint warnings (#3849) 2021-12-31 00:06:08 -08:00
David Vo
528087e308 [hal] Use enums with fixed underlying type in clang C (#3297)
This will allow static analysis tools that use clang to always determine the correct intended parameter types for HAL functions.
2021-12-30 21:20:05 -08:00
Thad House
1f59ff72f9 [wpilib] Add ADIS IMUs (#3777)
Co-authored-by: Tyler Veness <calcmogul@gmail.com>
Co-authored-by: Matteo Kimura <mateus.sakata@gmail.com>
2021-12-30 19:43:53 -08:00
Matt
315be873c4 [wpimath] Add TimeInterpolatableBuffer (#2695)
These classes are useful for storing previous robot positions to use in conjunction with the upcoming pose estimators.

Co-authored-by: Prateek Machiraju <prateek.machiraju@gmail.com>
Co-authored-by: Tyler Veness <calcmogul@gmail.com>
Co-authored-by: cttew <cttewari@gmail.com>
2021-12-30 19:08:05 -08:00
Oblarg
b8d019cdb4 [wpilib] Rename NormalizeWheelSpeeds to DesaturateWheelSpeeds (#3791) 2021-12-30 18:30:08 -08:00
Peter Johnson
102f23bbdb [wpilibj] DriverStation: Set thread interrupted state (#3846)
This is a Java best practice when catching InterruptedException.
2021-12-30 13:13:52 -08:00
Kevin-OConnor
b85c24a79c [wpilib] Add warning about onboard I2C (#3842) 2021-12-30 13:13:03 -08:00
Oblarg
eee29daaf9 [newCommands] Trigger: Allow override of debounce type (#3845)
Previously Trigger could only be debounced on rising edges.
This change preserves the default behavior but adds the capability to override it.
2021-12-29 16:10:43 -08:00
Oblarg
aa9dfabde2 [wpimath] Move debouncer to filters (#3838) 2021-12-28 09:49:41 -08:00
Peter Johnson
5999a26fba [wpiutil] Add GetSystemTime() (#3840)
This portably gets the time in microseconds since the Unix epoch.
2021-12-27 23:06:31 -08:00
sciencewhiz
1e82595ffb [examples] Fix arcade inversions (#3841)
Accounts for differences between ArcadeDrive and the methods used
in some other examples.
2021-12-27 23:05:42 -08:00
Peter Johnson
e373fa476b [wpiutil] Add disableMockTime to JNI (#3839)
This exposes the equivalent of SetNowImpl(nullptr) to Java.
2021-12-27 09:51:32 -08:00
sciencewhiz
dceb5364f4 [examples] Ensure right side motors are inverted (#3836)
Fixes #3827
Adds MotorController inversion for right side, removes inversion in
setVoltage methods.

Also fixes various XboxController negations (was inconsistent throughout examples).
2021-12-26 19:25:26 -08:00
Oblarg
baacbc8e24 [wpilib] Tachometer: Add function to return RPS (#3833) 2021-12-26 15:52:18 -08:00
Austin Shalit
84b15f0883 [templates] Add Java Romi Educational template (#3837)
This is a combination of a Romi Gradle project and Educational robot (added in #3309)
2021-12-26 15:46:22 -08:00
Dalton Smith
c0da9d2d35 [examples] Invert Right Motor in Romi Java examples (#3828) 2021-12-26 15:42:53 -08:00
sciencewhiz
0fe0be2733 [build] Change project year to intellisense (#3835)
This means VSCode won't prompt to upgrade (added in beta 4)
2021-12-25 20:50:06 -06:00
Tyler Veness
eafa947338 [wpimath] Make copies of trajectory constraint arguments (#3832)
This avoids stack-use-after-scope bugs in code like the following when
the original argument goes out of scope:
```cpp
frc2::Command* RobotContainer::GetAutonomousCommand() {
  // Create a voltage constraint to ensure we don't accelerate too fast
  frc::DifferentialDriveVoltageConstraint autoVoltageConstraint(
      frc::SimpleMotorFeedforward<units::meters>(
          DriveConstants::ks, DriveConstants::kv, DriveConstants::ka),
      DriveConstants::kDriveKinematics, 10_V);
```
2021-12-25 07:19:43 -06:00
sciencewhiz
9d13ae8d01 [wpilib] Add notes for Servo get that it only returns cmd (NFC) (#3820)
Co-authored-by: Peter Johnson <johnson.peter@gmail.com>
2021-12-23 22:22:18 -08:00
Tyler Veness
2a64e4bae5 [wpimath] Give drivetrain a more realistic width in TrajectoryJsonTest.java (#3822)
Fixes #3819.
2021-12-22 22:28:23 -08:00
Tyler Veness
c3fd20db59 [wpilib] Fix trajectory sampling in DifferentialDriveSim test (#3821)
Also rename C++ test file to match class name.

Fixes #3818.
2021-12-22 22:27:51 -08:00
WarrenReynolds
6f91f37cd0 [examples] Fix SwerveControllerCommand order of Module States (#3815)
DriveSubsystem::SetModulesStates applies module state to incorrect modules.

Fixes #3814.
2021-12-22 12:26:02 -08:00
Peter Johnson
5158730b81 [wpigui] Upgrade to imgui 1.86, GLFW 3.3.6 (#3817)
The GLFW upgrade fixes gamepads not being mapped at startup.
2021-12-22 12:24:36 -08:00
Thad House
2ad2d2ca96 [wpiutil] MulticastServiceResolver: Fix C array returning functions (#3816) 2021-12-22 09:52:57 -08:00
Starlight220
b5fd29774f [wpilibj] Trigger: implement BooleanSupplier interface (#3811) 2021-12-21 11:33:16 -08:00
sciencewhiz
9f8f330e96 [wpilib] Fix Mecanum and SwerveControllerCommand when desired rotation passed (#3808) 2021-12-19 20:08:28 -08:00
Tyler Veness
1ad3b1b333 [hal] Don't copy byte to where null terminator goes (#3807)
Fixes the following compiler warning:
```
/__w/allwpilib/allwpilib/hal/src/main/native/sim/Notifier.cpp:323:21: error: 'char* strncpy(char*, const char*, size_t)' specified bound 64 equals destination size [-Werror=stringop-truncation]
         std::strncpy(arr[num].name, notifier->name.c_str(),
         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                      sizeof(arr[num].name));
                      ~~~~~~~~~~~~~~~~~~~~~~
```
2021-12-19 16:46:12 -08:00
Thad House
dfc24425c3 [build] Fix gazebo gradle IDE warnings (#3806)
Also add note on how to generate all files for the IDE.
2021-12-19 14:20:08 -08:00
Thad House
c02577bb51 [glass] Configure delay loading for windows camera server support (#3803)
We don't currently support cameras in glass, but it's something we want to do in the future. However, when we do this, glass will completely stop working on N builds of windows, and it would fail to load at all with no messages. To solve this, we can delayload the media foundation dlls that are missing. The executable will then launch even without the dlls present, and we can attempt to load them at runtime and dynamically disable camera support.

When we get around to implementing it, we can just call HasCameraSupport, and dynamically hide all camera related code behind that flag.
2021-12-19 14:19:24 -08:00
sciencewhiz
c9e6a96a61 [wpilib] Document range of Servo angle (NFC) (#3796) 2021-12-19 13:53:31 -08:00
Thad House
9778626f34 [wpilib, hal] Add support for getting faults and versions from power distribution (#3794) 2021-12-19 13:42:49 -08:00
Thad House
34b2d0dae1 [wpilib, hal] High Level REV PH changes (#3792)
More functionality was implemented at the HAL level, so expose that to the wpilib level.

This also does units changes for all the PH related functionality.
2021-12-19 13:41:35 -08:00
Thad House
59a7528fd6 [cscore] Fix crash when usbcamera is deleted before message pump thread fully starts (#3804)
shared_from_this will assert if the shared pointer is in the middle of being destructed. Because we access shared_from_this in the message pump, this can easily occur. The solution is to grab the weak pointer, manually attempt to lock it, and only continue if that succeeds. The message pump is already synchronized to the usb camera being destructed, so this is a fine behavior.
2021-12-19 13:39:23 -08:00
Thad House
11d9859ef1 [build] Update plugins to remove log4j vulnerabilities (#3805) 2021-12-19 13:38:48 -08:00
Peter Johnson
e44ed752ad [glass] Fix CollapsingHeader in Encoder, PCM, and DeviceTree (#3797)
The new storage approach was attempting to save both the name and the
open status to the same storage key.
2021-12-19 07:35:12 -08:00
Thad House
52b2dd5b89 [build] Bump native utils to remove log4j (#3802) 2021-12-19 07:33:12 -08:00
sciencewhiz
c46636f218 [wpilib] Improve new counter classes documentation (NFC) (#3801) 2021-12-18 21:40:03 -08:00
sciencewhiz
dc531462e1 [build] Update to gradle 7.3.2 (#3800) 2021-12-18 21:34:35 -08:00
Tyler Veness
92ba98621c [wpimath] Add helper variable templates for units type traits (#3790) 2021-12-18 11:32:32 -08:00
sciencewhiz
d41d051f1b [wpilibc] Fix Mecanum & Swerve ControllerCommand lambda capture (#3795)
Fixes #3765
Also fixes SwerveControllerCommand example calling command twice.
2021-12-18 11:30:57 -08:00
sciencewhiz
c5ae0effac OtherVersions.md: Add one missing case of useLocal (#3788) 2021-12-15 20:30:34 -08:00
Tyler Veness
b3974c6ed3 [wpimath] Upgrade to Drake v0.37.0 (#3786) 2021-12-14 06:41:38 -08:00
Peter Johnson
589a00e379 [wpilibc] Start DriverStation thread from RobotBase (#3785)
With the change from GetInstance to static functions, many functions
don't call DriverStation::GetInstance(), so the DS thread wasn't
getting started by default.  Call InDisabled() to make sure this
happens.
2021-12-12 22:23:13 -08:00
Tyler Veness
8d9836ca02 [wpilib] Improve curvature drive documentation (NFC) (#3783) 2021-12-12 17:59:04 -08:00
Peter Johnson
8b5bf8632e [myRobot] Add wpimath and wpiutil JNI (#3784) 2021-12-12 17:57:52 -08:00
sciencewhiz
1846114491 [examples] Update references from characterization to SysId (NFC) (#3782) 2021-12-11 21:25:43 -08:00
Thad House
2c461c794e [build] Update to gradle 7.3 (#3778) 2021-12-10 21:26:28 -08:00
Jan-Felix Abellera
109363daa4 [hal] Add remaining driver functions for REVPH (#3776)
Add the remaining HAL functions needed to fully support the Pneumatic Hub and its latest firmware.

- Clear sticky faults
- Get device voltage
- Get 5v supply voltage (used for analog to PSI calculation)
- Get solenoid voltage
- Get solenoid current
- Get device firmware and hardware version

Some minor refactoring was done for naming of some internal functions for consistency purposes.
2021-12-09 12:29:09 -08:00
Jan-Felix Abellera
41d26bee8d [hal] Refactor REV PDH (#3775)
Refactors retrieving the faults from the device to match the implementation that we have for the Pneumatic Hub. Instead of having a getter function for each fault, there is a single function to get all faults (sticky or normal) for use with the higher level API

Renames functions to be consistent

Removes some functions that don't need to be included in wpilib:
- Identify device - this just flashes the module LED on the device and has no use in wpilib
- Is PDH enabled - the PDH does not change state depending on robot enabled state

PDH frame and signal names were updated in our DBC, and this PR makes use of the newly generated CAN frame helper functions
2021-12-09 12:27:06 -08:00
Tyler Veness
7269a170fb Upgrade maven deps to latest versions and fix new linter errors (#3772)
This also makes the Gradle build work with JDK 17.

The extra JVM args in gradle.properties works around a bug with spotless
and JDK 17: https://github.com/diffplug/spotless/issues/834

PMD.CloseResource was ignored because it's almost always a false
positive, and there are many of them.
2021-12-09 12:20:08 -08:00
Thad House
441f2ed9b0 [build] actions: use fixed image versions instead latest (#3761) 2021-12-09 12:12:59 -08:00
Modelmat
15275433d4 [examples] Fix duplicate port allocations in C++ SwerveBot/SwerveDrivePoseEstimator/RomiReference (#3773)
- Remove duplicate motor port (2) from C++ SwerveBot/SwerveDrivePoseEstimator

Java has the correct motor ports.

- Fix duplicate port allocation in C++ RomiReference by correcting if/else check

Java logic was already correct, and confirms this change.
2021-12-06 21:08:34 -08:00
Jason Daming
1ac02d2f58 [examples] Fix drive Joystick axes in several examples (#3769) 2021-12-06 16:40:10 -08:00
Jason Daming
8ee6257e92 [wpilib] DifferentialDrivetrainSim.KitbotMotor: Add NEO and Falcon 500 (#3762) 2021-12-06 14:46:58 -08:00
Prateek Machiraju
d81ef2bc5c [wpilib] Fix deadlocks in Mechanism2d et al. (#3770)
UpdateEntries() and Flush() are called from methods that lock the mutex,
so locking it again will cause deadlocks. This also updates the Java
code to make MechanismObject2d::update synchronized like in the C++
version.
2021-12-06 14:42:02 -08:00
Tyler Veness
acb64dff97 [wpimath] Make RamseteController::Calculate() more concise (#3763) 2021-12-06 12:57:42 -08:00
Jan-Felix Abellera
3f6cf76a8c [hal] Refactor REV PH CAN frames (#3756) 2021-12-06 10:08:57 -08:00
Peter Johnson
3ef2dab465 [wpilib] DutyCycleEncoder: add setting of duty cycle range (#3759)
As the sensor needs to maintain an actual duty cycle, it can't go all
the way from 0-100, so provide a way to set the min and max and linearly
map between the two.
2021-12-05 14:28:08 -08:00
sciencewhiz
a5a56dd067 Readme: Add Visual Studio 2022 (#3760) 2021-12-05 14:27:37 -08:00
Tyler Veness
04957a6d30 [wpimath] Fix units of RamseteController's b and zeta (#3757)
Fixes #3755.
2021-12-03 18:21:30 -08:00
Peter Johnson
5da54888f8 [glass] Upgrade imgui to 0.85, implot to HEAD, glfw to 3.3.5 (#3754)
This in particular upgrades the plot widget with a few new features
and makes more plot configuration persistent.
2021-12-03 17:23:18 -08:00
Thad House
6c93365b0f [wpiutil] MulticastService cleanup (#3750)
Fix duplicated constructors, and also use simpler utf conversion API on windows.
2021-12-02 21:06:55 -08:00
Thad House
1c4a8bfb66 [cscore] Cleanup Windows USB camera impl (#3751)
- Use wpiutil string conversion rather than codecvt (which is deprecated).
- Force A function types.
2021-12-02 13:48:03 -08:00
Thad House
d51a1d3b3d [rtns] Fix icon (#3749) 2021-11-30 21:58:58 -08:00
Thad House
aced2e7da6 Add roboRIO Team Number Setter tool (#3744) 2021-11-30 11:17:30 -08:00
Thad House
fa1ceca83a [wpilibj] Use DS cache for iterative robot control word cache (#3748)
The root cause of #3747 is CommandScheduler's ds state checks are behind iterative robots checks. This means that the iterative robot state could return enabled, but the DS cache could still be reporting disabled. This results in a race in the Disabled -> Enabled transition, which manifests in commands not running.

Previously, iterative robot base pulled from the DS cache. This meant that the ds cache was always updated before an iterative robot base loop could run. This still had a race, but this could only occur on the Enabled -> Disable transition, which is much less noticeable and would usually just result in a command running for an extra loop.

We can move back to the old behavior by grabbing the new iterative robot base check variables to use the DS cache.
2021-11-29 20:56:58 -08:00
sciencewhiz
0ea05d34e6 [build] Update to gradle 7.2 (#3746) 2021-11-29 20:53:26 -08:00
Thad House
09db4f672b [build] Update to native utils 2022.6.1 (#3745) 2021-11-29 13:04:08 -08:00
Thad House
4ba80a3a8c [wpigui] Don't recursively render frames in size callback (#3743)
WindowSizeCallback can sometimes be called while doing a render. If this occurs, imgui asserts. Avoid this case.
2021-11-28 01:03:40 -08:00
806 changed files with 31968 additions and 6196 deletions

View File

@@ -12,7 +12,7 @@ jobs:
name: Linux
container: wpilib/roborio-cross-ubuntu:2022-20.04
flags: ""
- os: macos-latest
- os: macOS-11
name: macOS
container: ""
flags: "-DWITH_JAVA=OFF"
@@ -43,7 +43,7 @@ jobs:
build-vcpkg:
name: "Build - Windows"
runs-on: windows-latest
runs-on: windows-2019
steps:
- uses: actions/checkout@v2
- name: Prepare vcpkg

View File

@@ -44,13 +44,13 @@ jobs:
fail-fast: false
matrix:
include:
- os: windows-latest
- os: windows-2019
artifact-name: Win64
architecture: x64
- os: windows-latest
- os: windows-2019
artifact-name: Win32
architecture: x86
- os: macos-latest
- os: macOS-11
artifact-name: macOS
architecture: x64
name: "Build - ${{ matrix.artifact-name }}"

View File

@@ -11,6 +11,7 @@ cppSrcFileInclude {
modifiableFileExclude {
\.patch$
gradlew
}
generatedFileExclude {

View File

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

View File

@@ -145,6 +145,8 @@ if (USE_VCPKG_EIGEN)
set (EIGEN_VCPKG_REPLACE "find_package(Eigen3 CONFIG)")
endif()
find_package(LIBSSH 0.7.1)
if (WITH_FLAT_INSTALL)
set(WPIUTIL_DEP_REPLACE "include($\{SELF_DIR\}/wpiutil-config.cmake)")
set(NTCORE_DEP_REPLACE "include($\{SELF_DIR\}/ntcore-config.cmake)")
@@ -245,7 +247,6 @@ if (WITH_TESTS)
include(GoogleTest)
endif()
add_subdirectory(fieldImages)
add_subdirectory(wpiutil)
add_subdirectory(ntcore)
@@ -254,10 +255,15 @@ if (WITH_WPIMATH)
endif()
if (WITH_GUI)
add_subdirectory(fieldImages)
add_subdirectory(imgui)
add_subdirectory(wpigui)
add_subdirectory(glass)
add_subdirectory(outlineviewer)
if (LIBSSH_FOUND)
add_subdirectory(roborioteamnumbersetter)
add_subdirectory(datalogtool)
endif()
endif()
if (WITH_WPILIB OR WITH_SIMULATION_MODULES)

View File

@@ -1,4 +1,4 @@
Copyright (c) 2009-2021 FIRST and other WPILib contributors
Copyright (c) 2009-2022 FIRST and other WPILib contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@@ -69,15 +69,36 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* wpiutil
* wpigui
* imgui
* ntcore
* wpiutil
* wpimath
* wpiutil
* glass/libglass
* wpiutil
* wpimath
* wpigui
* glass/libglassnt
* wpiutil
* ntcore
* wpimath
* wpigui
* hal
* wpiutil
* halsim
* imgui
* wpiutil
* ntcore
* wpiutil
* ntcore
* wpimath
* wpigui
* libglass
* libglassnt
* cscore
* opencv
@@ -101,6 +122,7 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* cameraserver
* ntcore
* cscore
* wpimath
* wpiutil
* wpilibNewCommands
@@ -109,9 +131,10 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* cameraserver
* ntcore
* cscore
* wpimath
* wpiutil
* wpilibNewCommands
* wpilibOldCommands
* wpilibc
* hal
* cameraserver
@@ -119,6 +142,7 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
* cscore
* wpiutil
### Third Party Artifacts
This repository provides the builds of the following third party software.
@@ -128,3 +152,4 @@ All artifacts are based at `edu.wpi.first.thirdparty.frcYEAR` in the repository.
* googletest
* imgui
* opencv
* libssh

View File

@@ -11,6 +11,7 @@ Development builds are the per-commit build hosted everytime a commit is pushed
In order to build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version.
```groovy
wpi.maven.useLocal = false
wpi.maven.useDevelopment = true
wpi.versions.wpilibVersion = 'YEAR.+'
wpi.versions.wpimathVersion = 'YEAR.+

View File

@@ -39,7 +39,7 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
- On macOS, install the JDK 11 .pkg from the link above
- C++ compiler
- On Linux, install GCC 8 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 Windows, install [Visual Studio Community 2022 or 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)
- On macOS, install the Xcode command-line build tools via `xcode-select --install`
- ARM compiler toolchain
- Run `./gradlew installRoboRioToolchain` after cloning this repository
@@ -71,6 +71,8 @@ The gradlew wrapper only exists in the root of the main project, so be sure to r
There are a few tasks other than `build` available. To see them, run the meta-task `tasks`. This will print a list of all available tasks, with a description of each task.
If opening from a fresh clone, generated java dependencies will not exist. Most IDEs will not run the generation tasks, which will cause lots of IDE errors. Manually run `./gradlew compileJava` from a terminal to run all the compile tasks, and then refresh your IDE's configuration (In VS Code open settings.gradle and save).
### Faster builds
`./gradlew build` builds _everything_, which includes debug and release builds for desktop and all installed cross compilers. Many developers don't need or want to build all of this. Therefore, common tasks have shortcuts to only build necessary components for common development and testing tasks.

View File

@@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.hubspot.jinjava:jinjava:2.5.8'
classpath 'com.hubspot.jinjava:jinjava:2.6.0'
}
}
@@ -15,13 +15,13 @@ plugins {
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2'
id 'edu.wpi.first.NativeUtils' apply false
id 'edu.wpi.first.GradleJni' version '1.0.0'
id 'edu.wpi.first.GradleVsCode' version '1.0.0'
id 'edu.wpi.first.GradleVsCode'
id 'idea'
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' apply false
id 'com.github.spotbugs' version '5.0.0-beta.1' apply false
id 'net.ltgt.errorprone' version '2.0.2' apply false
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
id 'com.diffplug.spotless' version '6.1.2' apply false
id 'com.github.spotbugs' version '5.0.4' apply false
}
wpilibVersioning.buildServerMode = project.hasProperty('buildServer')
@@ -147,5 +147,5 @@ ext.getCurrentArch = {
}
wrapper {
gradleVersion = '7.1.1'
gradleVersion = '7.3.3'
}

View File

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

View File

@@ -27,7 +27,7 @@ repositories {
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.google.code.gson:gson:2.8.9'
implementation project(':wpiutil')
implementation project(':ntcore')

View File

@@ -56,9 +56,9 @@ public final class Main {
public JsonObject config;
}
static int team;
static boolean server;
static List<CameraConfig> cameras = new ArrayList<>();
private static int team;
private static boolean server;
private static List<CameraConfig> cameras = new ArrayList<>();
private Main() {}

View File

@@ -1,7 +1,7 @@
macro(wpilib_target_warnings target)
if(NOT MSVC)
target_compile_options(${target} PRIVATE -Wall -pedantic -Wextra -Werror -Wno-unused-parameter -Wno-error=deprecated-declarations)
target_compile_options(${target} PRIVATE -Wall -pedantic -Wextra -Werror -Wno-unused-parameter -Wno-error=deprecated-declarations ${WPILIB_TARGET_WARNINGS})
else()
target_compile_options(${target} PRIVATE /wd4146 /wd4244 /wd4251 /wd4267 /wd4996 /WX)
target_compile_options(${target} PRIVATE /wd4146 /wd4244 /wd4251 /wd4267 /wd4996 /WX ${WPILIB_TARGET_WARNINGS})
endif()
endmacro()

View File

@@ -0,0 +1,116 @@
# - Try to find LibSSH
# Once done this will define
#
# LIBSSH_FOUND - system has LibSSH
# LIBSSH_INCLUDE_DIRS - the LibSSH include directory
# LIBSSH_LIBRARIES - link these to use LibSSH
# LIBSSH_VERSION -
#
# Author Michal Vasko <mvasko@cesnet.cz>
# Copyright (c) 2020 CESNET, z.s.p.o.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# 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.
#
include(FindPackageHandleStandardArgs)
if(LIBSSH_LIBRARIES AND LIBSSH_INCLUDE_DIRS)
# in cache already
set(LIBSSH_FOUND TRUE)
else()
find_path(LIBSSH_INCLUDE_DIR
NAMES
libssh/libssh.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
${CMAKE_INCLUDE_PATH}
${CMAKE_INSTALL_PREFIX}/include
)
find_library(LIBSSH_LIBRARY
NAMES
ssh.so
libssh.so
libssh.dylib
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
${CMAKE_LIBRARY_PATH}
${CMAKE_INSTALL_PREFIX}/lib
)
if(LIBSSH_INCLUDE_DIR AND LIBSSH_LIBRARY)
# learn libssh version
if(EXISTS ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
else()
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h)
endif()
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MAJOR
REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+")
if(NOT LIBSSH_VERSION_MAJOR)
message(STATUS "LIBSSH_VERSION_MAJOR not found, assuming libssh is too old and cannot be used!")
set(LIBSSH_INCLUDE_DIR "LIBSSH_INCLUDE_DIR-NOTFOUND")
set(LIBSSH_LIBRARY "LIBSSH_LIBRARY-NOTFOUND")
else()
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MAJOR ${LIBSSH_VERSION_MAJOR})
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MINOR
REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+")
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MINOR ${LIBSSH_VERSION_MINOR})
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_PATCH
REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+")
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${LIBSSH_VERSION_PATCH})
set(LIBSSH_VERSION ${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH})
if(LIBSSH_VERSION VERSION_LESS 0.8.0)
# libssh_threads also needs to be linked for these versions
string(REPLACE "libssh.so" "libssh_threads.so"
LIBSSH_THREADS_LIBRARY
${LIBSSH_LIBRARY}
)
string(REPLACE "libssh.dylib" "libssh_threads.dylib"
LIBSSH_THREADS_LIBRARY
${LIBSSH_THREADS_LIBRARY}
)
string(REPLACE "ssh.so" "ssh_threads.so"
LIBSSH_THREADS_LIBRARY
${LIBSSH_THREADS_LIBRARY}
)
endif()
endif()
endif()
set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR})
set(LIBSSH_LIBRARIES ${LIBSSH_LIBRARY} ${LIBSSH_THREADS_LIBRARY})
mark_as_advanced(LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES)
find_package_handle_standard_args(LibSSH FOUND_VAR LIBSSH_FOUND
REQUIRED_VARS LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES
VERSION_VAR LIBSSH_VERSION)
endif()

View File

@@ -14,7 +14,6 @@
#include <windowsx.h>
#include <cmath>
#include <codecvt>
#include <memory>
#include <string>
#include <vector>
@@ -25,7 +24,9 @@
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <wpi/ConvertUTF.h>
#include <wpi/MemAlloc.h>
#include <wpi/SmallString.h>
#include <wpi/StringExtras.h>
#include <wpi/timestamp.h>
@@ -72,8 +73,9 @@ UsbCameraImpl::UsbCameraImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
std::string_view path)
: SourceImpl{name, logger, notifier, telemetry}, m_path{path} {
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
m_widePath = utf8_conv.from_bytes(m_path.c_str());
wpi::SmallVector<wchar_t, 128> wideStorage;
wpi::sys::windows::UTF8ToUTF16(m_path, wideStorage);
m_widePath = std::wstring{wideStorage.data(), wideStorage.size()};
m_deviceId = -1;
StartMessagePump();
}
@@ -227,7 +229,7 @@ void UsbCameraImpl::PostRequestNewFrame() {
bool UsbCameraImpl::CheckDeviceChange(WPARAM wParam, DEV_BROADCAST_HDR* pHdr,
bool* connected) {
DEV_BROADCAST_DEVICEINTERFACE* pDi = NULL;
DEV_BROADCAST_DEVICEINTERFACE_A* pDi = NULL;
*connected = false;
@@ -240,9 +242,9 @@ bool UsbCameraImpl::CheckDeviceChange(WPARAM wParam, DEV_BROADCAST_HDR* pHdr,
// Compare the device name with the symbolic link.
pDi = reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(pHdr);
pDi = reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE_A*>(pHdr);
if (_stricmp(m_path.c_str(), pDi->dbcc_name) == 0) {
if (wpi::equals_lower(m_path, pDi->dbcc_name)) {
if (wParam == DBT_DEVICEARRIVAL) {
*connected = true;
return true;
@@ -411,11 +413,12 @@ LRESULT UsbCameraImpl::PumpMain(HWND hwnd, UINT uiMsg, WPARAM wParam,
// If has device ID, use the device ID from the event
// because of windows bug
auto&& device = devices[m_deviceId];
DEV_BROADCAST_DEVICEINTERFACE* pDi =
reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE*>(parameter);
DEV_BROADCAST_DEVICEINTERFACE_A* pDi =
reinterpret_cast<DEV_BROADCAST_DEVICEINTERFACE_A*>(parameter);
m_path = pDi->dbcc_name;
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
m_widePath = utf8_conv.from_bytes(m_path.c_str());
wpi::SmallVector<wchar_t, 128> wideStorage;
wpi::sys::windows::UTF8ToUTF16(m_path, wideStorage);
m_widePath = std::wstring{wideStorage.data(), wideStorage.size()};
} else {
// This device not found
break;
@@ -482,9 +485,16 @@ bool UsbCameraImpl::DeviceConnect() {
const wchar_t* path = m_widePath.c_str();
m_mediaSource = CreateVideoCaptureDevice(path);
if (!m_mediaSource)
if (!m_mediaSource) {
return false;
m_imageCallback = CreateSourceReaderCB(shared_from_this(), m_mode);
}
auto weakThis = weak_from_this();
auto sharedThis = weakThis.lock();
if (sharedThis) {
m_imageCallback = CreateSourceReaderCB(sharedThis, m_mode);
} else {
return false;
}
m_sourceReader =
CreateSourceReader(m_mediaSource.Get(), m_imageCallback.Get());
@@ -747,8 +757,9 @@ CS_StatusValue UsbCameraImpl::DeviceProcessCommand(
{
std::scoped_lock lock(m_mutex);
m_path = msg->dataStr;
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
m_widePath = utf8_conv.from_bytes(m_path.c_str());
wpi::SmallVector<wchar_t, 128> wideStorage;
wpi::sys::windows::UTF8ToUTF16(m_path, wideStorage);
m_widePath = std::wstring{wideStorage.data(), wideStorage.size()};
}
DeviceDisconnect();
DeviceConnect();
@@ -1048,7 +1059,8 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
// Ensure we are initialized by grabbing the message pump
// GetMessagePump();
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
wpi::SmallString<128> storage;
WCHAR buf[512];
ComPtr<IMFAttributes> pAttributes;
IMFActivate** ppDevices = nullptr;
UINT32 count = 0;
@@ -1080,14 +1092,19 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
for (UINT32 i = 0; i < count; i++) {
UsbCameraInfo info;
info.dev = i;
WCHAR buf[512];
UINT32 characters = 0;
ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buf,
sizeof(buf) / sizeof(WCHAR), NULL);
info.name = utf8_conv.to_bytes(buf);
sizeof(buf) / sizeof(WCHAR), &characters);
storage.clear();
wpi::sys::windows::UTF16ToUTF8(buf, characters, storage);
info.name = storage.string();
ppDevices[i]->GetString(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buf,
sizeof(buf) / sizeof(WCHAR), NULL);
info.path = utf8_conv.to_bytes(buf);
sizeof(buf) / sizeof(WCHAR), &characters);
storage.clear();
wpi::sys::windows::UTF16ToUTF8(buf, characters, storage);
info.path = storage.string();
// Try to parse path from symbolic link
ParseVidAndPid(info.path, &info.productId, &info.vendorId);

View File

@@ -89,7 +89,7 @@ static std::shared_ptr<ClassHolder> GetClassHolder() {
WindowsMessagePump::WindowsMessagePump(
std::function<LRESULT(HWND, UINT, WPARAM, LPARAM)> callback) {
m_callback = callback;
auto handle = CreateEvent(NULL, true, false, NULL);
auto handle = CreateEventA(NULL, true, false, NULL);
m_mainThread = std::thread([=] { ThreadMain(handle); });
auto waitResult = WaitForSingleObject(handle, 1000);
if (waitResult == WAIT_OBJECT_0) {
@@ -98,7 +98,7 @@ WindowsMessagePump::WindowsMessagePump(
}
WindowsMessagePump::~WindowsMessagePump() {
auto res = SendMessage(hwnd, WM_CLOSE, NULL, NULL);
auto res = SendMessageA(hwnd, WM_CLOSE, NULL, NULL);
if (m_mainThread.joinable())
m_mainThread.join();
}
@@ -110,28 +110,28 @@ void WindowsMessagePump::ThreadMain(HANDLE eventHandle) {
MFStartup(MF_VERSION);
auto classHolder = GetClassHolder();
hwnd = CreateWindowEx(0, classHolder->class_name, "dummy_name", 0, 0, 0, 0, 0,
HWND_MESSAGE, NULL, NULL, this);
hwnd = CreateWindowExA(0, classHolder->class_name, "dummy_name", 0, 0, 0, 0,
0, HWND_MESSAGE, NULL, NULL, this);
// Register for device notifications
HDEVNOTIFY g_hdevnotify = NULL;
HDEVNOTIFY g_hdevnotify2 = NULL;
DEV_BROADCAST_DEVICEINTERFACE di = {0};
DEV_BROADCAST_DEVICEINTERFACE_A di = {0};
di.dbcc_size = sizeof(di);
di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
di.dbcc_classguid = KSCATEGORY_CAPTURE;
g_hdevnotify =
RegisterDeviceNotification(hwnd, &di, DEVICE_NOTIFY_WINDOW_HANDLE);
RegisterDeviceNotificationA(hwnd, &di, DEVICE_NOTIFY_WINDOW_HANDLE);
DEV_BROADCAST_DEVICEINTERFACE di2 = {0};
DEV_BROADCAST_DEVICEINTERFACE_A di2 = {0};
di2.dbcc_size = sizeof(di2);
di2.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
di2.dbcc_classguid = KSCATEGORY_VIDEO_CAMERA;
g_hdevnotify2 =
RegisterDeviceNotification(hwnd, &di2, DEVICE_NOTIFY_WINDOW_HANDLE);
RegisterDeviceNotificationA(hwnd, &di2, DEVICE_NOTIFY_WINDOW_HANDLE);
SetEvent(eventHandle);

29
datalogtool/.styleguide Normal file
View File

@@ -0,0 +1,29 @@
cppHeaderFileInclude {
\.h$
\.inc$
\.inl$
}
cppSrcFileInclude {
\.cpp$
}
generatedFileExclude {
src/main/native/resources/
src/main/native/win/datalogtool.ico
src/main/native/mac/datalogtool.icns
}
repoRootNameOverride {
datalogtool
}
includeOtherLibs {
^GLFW
^fmt/
^glass/
^imgui
^portable-file-dialog
^wpi/
^wpigui
}

View File

@@ -0,0 +1,29 @@
project(datalogtool)
include(CompileWarnings)
include(GenResources)
include(LinkMacOSGUI)
configure_file(src/main/generate/WPILibVersion.cpp.in WPILibVersion.cpp)
GENERATE_RESOURCES(src/main/native/resources generated/main/cpp DLT dlt datalogtool_resources_src)
file(GLOB datalogtool_src src/main/native/cpp/*.cpp ${CMAKE_CURRENT_BINARY_DIR}/WPILibVersion.cpp)
if (WIN32)
set(datalogtool_rc src/main/native/win/datalogtool.rc)
elseif(APPLE)
set(MACOSX_BUNDLE_ICON_FILE datalogtool.icns)
set(APP_ICON_MACOSX src/main/native/mac/datalogtool.icns)
set_source_files_properties(${APP_ICON_MACOSX} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
endif()
add_executable(datalogtool ${datalogtool_src} ${datalogtool_resources_src} ${datalogtool_rc} ${APP_ICON_MACOSX})
wpilib_link_macos_gui(datalogtool)
target_link_libraries(datalogtool libglass ${LIBSSH_LIBRARIES})
target_include_directories(datalogtool PRIVATE ${LIBSSH_INCLUDE_DIRS})
if (WIN32)
set_target_properties(datalogtool PROPERTIES WIN32_EXECUTABLE YES)
elseif(APPLE)
set_target_properties(datalogtool PROPERTIES MACOSX_BUNDLE YES OUTPUT_NAME "datalogTool")
endif()

32
datalogtool/Info.plist Normal file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>datalogTool</string>
<key>CFBundleExecutable</key>
<string>datalogtool</string>
<key>CFBundleDisplayName</key>
<string>datalogTool</string>
<key>CFBundleIdentifier</key>
<string>edu.wpi.first.tools.datalogTool</string>
<key>CFBundleIconFile</key>
<string>datalogtool.icns</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>2021</string>
<key>CFBundleVersion</key>
<string>2021</string>
<key>LSMinimumSystemVersion</key>
<string>10.11</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>

134
datalogtool/build.gradle Normal file
View File

@@ -0,0 +1,134 @@
import org.gradle.internal.os.OperatingSystem
if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxraspbian') && !project.hasProperty('onlylinuxaarch64bionic')) {
description = "roboRIO Team Number Setter"
apply plugin: 'cpp'
apply plugin: 'c'
apply plugin: 'google-test-test-suite'
apply plugin: 'visual-studio'
apply plugin: 'edu.wpi.first.NativeUtils'
if (OperatingSystem.current().isWindows()) {
apply plugin: 'windows-resources'
}
ext {
nativeName = 'datalogtool'
}
apply from: "${rootDir}/shared/resources.gradle"
apply from: "${rootDir}/shared/config.gradle"
def wpilibVersionFileInput = file("src/main/generate/WPILibVersion.cpp.in")
def wpilibVersionFileOutput = file("$buildDir/generated/main/cpp/WPILibVersion.cpp")
nativeUtils {
nativeDependencyContainer {
libssh(getNativeDependencyTypeClass('WPIStaticMavenDependency')) {
groupId = "edu.wpi.first.thirdparty.frc2022"
artifactId = "libssh"
headerClassifier = "headers"
sourceClassifier = "sources"
ext = "zip"
version = '0.95-1'
targetPlatforms.addAll(nativeUtils.wpi.platforms.desktopPlatforms)
}
}
}
task generateCppVersion() {
description = 'Generates the wpilib version class'
group = 'WPILib'
outputs.file wpilibVersionFileOutput
inputs.file wpilibVersionFileInput
if (wpilibVersioning.releaseMode) {
outputs.upToDateWhen { false }
}
// We follow a simple set of checks to determine whether we should generate a new version file:
// 1. If the release type is not development, we generate a new version file
// 2. If there is no generated version number, we generate a new version file
// 3. If there is a generated build number, and the release type is development, then we will
// only generate if the publish task is run.
doLast {
def version = wpilibVersioning.version.get()
println "Writing version ${version} to $wpilibVersionFileOutput"
if (wpilibVersionFileOutput.exists()) {
wpilibVersionFileOutput.delete()
}
def read = wpilibVersionFileInput.text.replace('${wpilib_version}', version)
wpilibVersionFileOutput.write(read)
}
}
gradle.taskGraph.addTaskExecutionGraphListener { graph ->
def willPublish = graph.hasTask(publish)
if (willPublish) {
generateCppVersion.outputs.upToDateWhen { false }
}
}
def generateTask = createGenerateResourcesTask('main', 'DLT', 'dlt', project)
project(':').libraryBuild.dependsOn build
tasks.withType(CppCompile) {
dependsOn generateTask
dependsOn generateCppVersion
}
model {
components {
// By default, a development executable will be generated. This is to help the case of
// testing specific functionality of the library.
"${nativeName}"(NativeExecutableSpec) {
baseName = 'datalogtool'
sources {
cpp {
source {
srcDirs 'src/main/native/cpp', "$buildDir/generated/main/cpp"
include '**/*.cpp'
}
exportedHeaders {
srcDirs 'src/main/native/include'
}
}
if (OperatingSystem.current().isWindows()) {
rc {
source {
srcDirs 'src/main/native/win'
include '*.rc'
}
}
}
}
binaries.all {
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio || it.targetPlatform.name == nativeUtils.wpi.platforms.raspbian || it.targetPlatform.name == nativeUtils.wpi.platforms.aarch64bionic) {
it.buildable = false
return
}
it.cppCompiler.define("LIBSSH_STATIC")
lib project: ':glass', library: 'glass', linkage: 'static'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
nativeUtils.useRequiredLibrary(it, 'imgui_static', 'libssh')
if (it.targetPlatform.operatingSystem.isWindows()) {
it.linker.args << 'Gdi32.lib' << 'Shell32.lib' << 'd3d11.lib' << 'd3dcompiler.lib'
it.linker.args << 'ws2_32.lib' << 'advapi32.lib' << 'crypt32.lib' << 'user32.lib'
} else if (it.targetPlatform.operatingSystem.isMacOsX()) {
it.linker.args << '-framework' << 'Metal' << '-framework' << 'MetalKit' << '-framework' << 'Cocoa' << '-framework' << 'IOKit' << '-framework' << 'CoreFoundation' << '-framework' << 'CoreVideo' << '-framework' << 'QuartzCore'
it.linker.args << '-framework' << 'Kerberos'
} else {
it.linker.args << '-lX11'
}
}
}
}
}
apply from: 'publish.gradle'
}

107
datalogtool/publish.gradle Normal file
View File

@@ -0,0 +1,107 @@
apply plugin: 'maven-publish'
def baseArtifactId = 'DataLogTool'
def artifactGroupId = 'edu.wpi.first.tools'
def zipBaseName = '_GROUP_edu_wpi_first_tools_ID_DataLogTool_CLS'
def outputsFolder = file("$project.buildDir/outputs")
model {
tasks {
// Create the run task.
$.components.datalogtool.binaries.each { bin ->
if (bin.buildable && bin.name.toLowerCase().contains("debug")) {
Task run = project.tasks.create("run", Exec) {
commandLine bin.tasks.install.runScriptFile.get().asFile.toString()
}
run.dependsOn bin.tasks.install
}
}
}
publishing {
def dataLogToolTaskList = []
$.components.each { component ->
component.binaries.each { binary ->
if (binary in NativeExecutableBinarySpec && binary.component.name.contains("datalogtool")) {
if (binary.buildable && binary.name.contains("Release")) {
// We are now in the binary that we want.
// This is the default application path for the ZIP task.
def applicationPath = binary.executable.file
def icon = file("$project.projectDir/src/main/native/mac/datalogtool.icns")
// Create the macOS bundle.
def bundleTask = project.tasks.create("bundleDataLogToolOsxApp", Copy) {
description("Creates a macOS application bundle for DataLogTool")
from(file("$project.projectDir/Info.plist"))
into(file("$project.buildDir/outputs/bundles/DataLogTool.app/Contents"))
into("MacOS") { with copySpec { from binary.executable.file } }
into("Resources") { with copySpec { from icon } }
doLast {
if (project.hasProperty("developerID")) {
// Get path to binary.
exec {
workingDir rootDir
def args = [
"sh",
"-c",
"codesign --force --strict --deep " +
"--timestamp --options=runtime " +
"--verbose -s ${project.findProperty("developerID")} " +
"$project.buildDir/outputs/bundles/DataLogTool.app/"
]
commandLine args
}
}
}
}
// Reset the application path if we are creating a bundle.
if (binary.targetPlatform.operatingSystem.isMacOsX()) {
applicationPath = file("$project.buildDir/outputs/bundles")
project.build.dependsOn bundleTask
}
// Create the ZIP.
def task = project.tasks.create("copyDataLogToolExecutable", Zip) {
description("Copies the DataLogTool executable to the outputs directory.")
destinationDirectory = outputsFolder
archiveBaseName = '_M_' + zipBaseName
duplicatesStrategy = 'exclude'
classifier = nativeUtils.getPublishClassifier(binary)
from(licenseFile) {
into '/'
}
from(applicationPath)
into(nativeUtils.getPlatformPath(binary))
}
if (binary.targetPlatform.operatingSystem.isMacOsX()) {
bundleTask.dependsOn binary.tasks.link
task.dependsOn(bundleTask)
}
task.dependsOn binary.tasks.link
dataLogToolTaskList.add(task)
project.build.dependsOn task
project.artifacts { task }
addTaskToCopyAllOutputs(task)
}
}
}
}
publications {
datalogtool(MavenPublication) {
dataLogToolTaskList.each { artifact it }
artifactId = baseArtifactId
groupId = artifactGroupId
version wpilibVersioning.version.get()
}
}
}
}

View File

@@ -0,0 +1,7 @@
/*
* Autogenerated file! Do not manually edit this file. This version is regenerated
* any time the publish task is run, or when this file is deleted.
*/
const char* GetWPILibVersion() {
return "${wpilib_version}";
}

View File

@@ -0,0 +1,156 @@
// 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 "App.h"
#include <libssh/libssh.h>
#include <memory>
#include <string_view>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <glass/Context.h>
#include <glass/MainMenuBar.h>
#include <glass/Storage.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <wpigui.h>
#include "Downloader.h"
#include "Exporter.h"
namespace gui = wpi::gui;
const char* GetWPILibVersion();
namespace dlt {
std::string_view GetResource_dlt_16_png();
std::string_view GetResource_dlt_32_png();
std::string_view GetResource_dlt_48_png();
std::string_view GetResource_dlt_64_png();
std::string_view GetResource_dlt_128_png();
std::string_view GetResource_dlt_256_png();
std::string_view GetResource_dlt_512_png();
} // namespace dlt
bool gShutdown = false;
static std::unique_ptr<Downloader> gDownloader;
static bool* gDownloadVisible;
static float gDefaultScale = 1.0;
void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) {
if ((cond & ImGuiCond_FirstUseEver) != 0) {
ImGui::SetNextWindowPos(pos * gDefaultScale, cond, pivot);
} else {
ImGui::SetNextWindowPos(pos, cond, pivot);
}
}
void SetNextWindowSize(const ImVec2& size, ImGuiCond cond) {
if ((cond & ImGuiCond_FirstUseEver) != 0) {
ImGui::SetNextWindowSize(size * gDefaultScale, cond);
} else {
ImGui::SetNextWindowPos(size, cond);
}
}
static void DisplayDownload() {
if (!*gDownloadVisible) {
return;
}
SetNextWindowPos(ImVec2{0, 250}, ImGuiCond_FirstUseEver);
SetNextWindowSize(ImVec2{375, 260}, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Download", gDownloadVisible)) {
if (!gDownloader) {
gDownloader = std::make_unique<Downloader>(
glass::GetStorageRoot().GetChild("download"));
}
gDownloader->Display();
}
ImGui::End();
}
static void DisplayMainMenu() {
ImGui::BeginMainMenuBar();
static glass::MainMenuBar mainMenu;
mainMenu.WorkspaceMenu();
gui::EmitViewMenu();
if (ImGui::BeginMenu("Window")) {
ImGui::MenuItem("Download", nullptr, gDownloadVisible);
ImGui::EndMenu();
}
bool about = false;
if (ImGui::BeginMenu("Info")) {
if (ImGui::MenuItem("About")) {
about = true;
}
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
if (about) {
ImGui::OpenPopup("About");
}
if (ImGui::BeginPopupModal("About")) {
ImGui::Text("Datalog Tool");
ImGui::Separator();
ImGui::Text("v%s", GetWPILibVersion());
ImGui::Separator();
ImGui::Text("Save location: %s", glass::GetStorageDir().c_str());
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
static void DisplayGui() {
DisplayMainMenu();
DisplayInputFiles();
DisplayEntries();
DisplayOutput(glass::GetStorageRoot().GetChild("output"));
DisplayDownload();
}
void Application(std::string_view saveDir) {
ssh_init();
gui::CreateContext();
glass::CreateContext();
// Add icons
gui::AddIcon(dlt::GetResource_dlt_16_png());
gui::AddIcon(dlt::GetResource_dlt_32_png());
gui::AddIcon(dlt::GetResource_dlt_48_png());
gui::AddIcon(dlt::GetResource_dlt_64_png());
gui::AddIcon(dlt::GetResource_dlt_128_png());
gui::AddIcon(dlt::GetResource_dlt_256_png());
gui::AddIcon(dlt::GetResource_dlt_512_png());
glass::SetStorageName("datalogtool");
glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
: saveDir);
gui::AddWindowScaler([](float scale) { gDefaultScale = scale; });
gui::AddLateExecute(DisplayGui);
gui::Initialize("Datalog Tool", 925, 510);
gDownloadVisible =
&glass::GetStorageRoot().GetChild("download").GetBool("visible", true);
gui::Main();
gShutdown = true;
glass::DestroyContext();
gui::DestroyContext();
gDownloader.reset();
ssh_finalize();
}

View File

@@ -0,0 +1,11 @@
// 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 <imgui.h>
void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0,
const ImVec2& pivot = ImVec2(0, 0));
void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0);

View File

@@ -0,0 +1,72 @@
// 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 "DataLogThread.h"
#include <fmt/format.h>
DataLogThread::~DataLogThread() {
if (m_thread.joinable()) {
m_active = false;
m_thread.join();
}
}
void DataLogThread::ReadMain() {
for (auto record : m_reader) {
if (!m_active) {
break;
}
++m_numRecords;
if (record.IsStart()) {
wpi::log::StartRecordData data;
if (record.GetStartData(&data)) {
std::scoped_lock lock{m_mutex};
if (m_entries.find(data.entry) != m_entries.end()) {
fmt::print("...DUPLICATE entry ID, overriding\n");
}
m_entries[data.entry] = data;
m_entryNames.emplace(data.name, data);
sigEntryAdded(data);
} else {
fmt::print("Start(INVALID)\n");
}
} else if (record.IsFinish()) {
int entry;
if (record.GetFinishEntry(&entry)) {
std::scoped_lock lock{m_mutex};
auto it = m_entries.find(entry);
if (it == m_entries.end()) {
fmt::print("...ID not found\n");
} else {
m_entries.erase(it);
}
} else {
fmt::print("Finish(INVALID)\n");
}
} else if (record.IsSetMetadata()) {
wpi::log::MetadataRecordData data;
if (record.GetSetMetadataData(&data)) {
std::scoped_lock lock{m_mutex};
auto it = m_entries.find(data.entry);
if (it == m_entries.end()) {
fmt::print("...ID not found\n");
} else {
it->second.metadata = data.metadata;
auto nameIt = m_entryNames.find(it->second.name);
if (nameIt != m_entryNames.end()) {
nameIt->second.metadata = data.metadata;
}
}
} else {
fmt::print("SetMetadata(INVALID)\n");
}
} else if (record.IsControl()) {
fmt::print("Unrecognized control record\n");
}
}
sigDone();
m_done = true;
}

View File

@@ -0,0 +1,71 @@
// 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 <atomic>
#include <functional>
#include <map>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <wpi/DataLogReader.h>
#include <wpi/DenseMap.h>
#include <wpi/Signal.h>
#include <wpi/mutex.h>
class DataLogThread {
public:
explicit DataLogThread(wpi::log::DataLogReader reader)
: m_reader{std::move(reader)}, m_thread{[=] { ReadMain(); }} {}
~DataLogThread();
bool IsDone() const { return m_done; }
std::string_view GetBufferIdentifier() const {
return m_reader.GetBufferIdentifier();
}
unsigned int GetNumRecords() const { return m_numRecords; }
unsigned int GetNumEntries() const {
std::scoped_lock lock{m_mutex};
return m_entryNames.size();
}
// Passes wpi::log::StartRecordData to func
template <typename T>
void ForEachEntryName(T&& func) {
std::scoped_lock lock{m_mutex};
for (auto&& kv : m_entryNames) {
func(kv.second);
}
}
wpi::log::StartRecordData GetEntry(std::string_view name) const {
std::scoped_lock lock{m_mutex};
auto it = m_entryNames.find(name);
if (it == m_entryNames.end()) {
return {};
}
return it->second;
}
const wpi::log::DataLogReader& GetReader() const { return m_reader; }
// note: these are called on separate thread
wpi::sig::Signal_mt<const wpi::log::StartRecordData&> sigEntryAdded;
wpi::sig::Signal_mt<> sigDone;
private:
void ReadMain();
wpi::log::DataLogReader m_reader;
mutable wpi::mutex m_mutex;
std::atomic_bool m_active{true};
std::atomic_bool m_done{false};
std::atomic<unsigned int> m_numRecords{0};
std::map<std::string, wpi::log::StartRecordData, std::less<>> m_entryNames;
wpi::DenseMap<int, wpi::log::StartRecordData> m_entries;
std::thread m_thread;
};

View File

@@ -0,0 +1,393 @@
// 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 "Downloader.h"
#include <libssh/sftp.h>
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#else
#include <sys/fcntl.h>
#endif
#include <algorithm>
#include <filesystem>
#include <fmt/format.h>
#include <glass/Storage.h>
#include <imgui.h>
#include <imgui_stdlib.h>
#include <portable-file-dialogs.h>
#include <wpi/StringExtras.h>
#include <wpi/fs.h>
#include "Sftp.h"
Downloader::Downloader(glass::Storage& storage)
: m_serverTeam{storage.GetString("serverTeam")},
m_remoteDir{storage.GetString("remoteDir", "/home/lvuser")},
m_username{storage.GetString("username", "lvuser")},
m_localDir{storage.GetString("localDir")},
m_deleteAfter{storage.GetBool("deleteAfter", true)},
m_thread{[this] { ThreadMain(); }} {}
Downloader::~Downloader() {
{
std::scoped_lock lock{m_mutex};
m_state = kExit;
}
m_cv.notify_all();
m_thread.join();
}
void Downloader::DisplayConnect() {
// IP or Team Number text box
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
ImGui::InputText("Team Number / Address", &m_serverTeam);
// Username/password
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
ImGui::InputText("Username", &m_username);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
ImGui::InputText("Password", &m_password, ImGuiInputTextFlags_Password);
// Connect button
if (ImGui::Button("Connect")) {
m_state = kConnecting;
m_cv.notify_all();
}
}
void Downloader::DisplayDisconnectButton() {
if (ImGui::Button("Disconnect")) {
m_state = kDisconnecting;
m_cv.notify_all();
}
}
void Downloader::DisplayRemoteDirSelector() {
ImGui::SameLine();
if (ImGui::Button("Refresh")) {
m_state = kGetFiles;
m_cv.notify_all();
}
// Remote directory text box
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
if (ImGui::InputText("Remote Dir", &m_remoteDir,
ImGuiInputTextFlags_EnterReturnsTrue)) {
m_state = kGetFiles;
m_cv.notify_all();
}
// List directories
for (auto&& dir : m_dirList) {
if (ImGui::Selectable(dir.c_str())) {
if (dir == "..") {
if (wpi::ends_with(m_remoteDir, '/')) {
m_remoteDir.resize(m_remoteDir.size() - 1);
}
m_remoteDir = wpi::rsplit(m_remoteDir, '/').first;
if (m_remoteDir.empty()) {
m_remoteDir = "/";
}
} else {
if (!wpi::ends_with(m_remoteDir, '/')) {
m_remoteDir += '/';
}
m_remoteDir += dir;
}
m_state = kGetFiles;
m_cv.notify_all();
}
}
}
void Downloader::DisplayLocalDirSelector() {
// Local directory text / select button
if (ImGui::Button("Select Download Folder...")) {
m_localDirSelector =
std::make_unique<pfd::select_folder>("Select Download Folder");
}
ImGui::TextUnformatted(m_localDir.c_str());
// Delete after download (checkbox)
ImGui::Checkbox("Delete after download", &m_deleteAfter);
// Download button
if (!m_localDir.empty()) {
if (ImGui::Button("Download")) {
m_state = kDownload;
m_cv.notify_all();
}
}
}
size_t Downloader::DisplayFiles() {
// List of files (multi-select) (changes to progress bar for downloading)
size_t fileCount = 0;
if (ImGui::BeginTable(
"files", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupColumn("File");
ImGui::TableSetupColumn("Size");
ImGui::TableSetupColumn("Download");
ImGui::TableHeadersRow();
for (auto&& download : m_downloadList) {
if ((m_state == kDownload || m_state == kDownloadDone) &&
!download.enabled) {
continue;
}
++fileCount;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(download.name.c_str());
ImGui::TableNextColumn();
auto sizeText = fmt::format("{}", download.size);
ImGui::TextUnformatted(sizeText.c_str());
ImGui::TableNextColumn();
if (m_state == kDownload || m_state == kDownloadDone) {
if (!download.status.empty()) {
ImGui::TextUnformatted(download.status.c_str());
} else {
ImGui::ProgressBar(download.complete);
}
} else {
auto checkboxLabel = fmt::format("##{}", download.name);
ImGui::Checkbox(checkboxLabel.c_str(), &download.enabled);
}
}
ImGui::EndTable();
}
return fileCount;
}
void Downloader::Display() {
if (m_localDirSelector && m_localDirSelector->ready(0)) {
m_localDir = m_localDirSelector->result();
m_localDirSelector.reset();
}
std::scoped_lock lock{m_mutex};
if (!m_error.empty()) {
ImGui::TextUnformatted(m_error.c_str());
}
switch (m_state) {
case kDisconnected:
DisplayConnect();
break;
case kConnecting:
DisplayDisconnectButton();
ImGui::Text("Connecting to %s...", m_serverTeam.c_str());
break;
case kDisconnecting:
ImGui::TextUnformatted("Disconnecting...");
break;
case kConnected:
case kGetFiles:
DisplayDisconnectButton();
DisplayRemoteDirSelector();
if (DisplayFiles() > 0) {
DisplayLocalDirSelector();
}
break;
case kDownload:
case kDownloadDone:
DisplayDisconnectButton();
DisplayFiles();
if (m_state == kDownloadDone) {
if (ImGui::Button("Download complete!")) {
m_state = kGetFiles;
m_cv.notify_all();
}
}
break;
default:
break;
}
}
void Downloader::ThreadMain() {
std::unique_ptr<sftp::Session> session;
static constexpr size_t kBufSize = 32 * 1024;
std::unique_ptr<uint8_t[]> copyBuf = std::make_unique<uint8_t[]>(kBufSize);
std::unique_lock lock{m_mutex};
while (m_state != kExit) {
State prev = m_state;
m_cv.wait(lock, [&] { return m_state != prev; });
m_error.clear();
try {
switch (m_state) {
case kConnecting:
if (auto team = wpi::parse_integer<unsigned int>(m_serverTeam, 10)) {
// team number
session = std::make_unique<sftp::Session>(
fmt::format("roborio-{}-frc.local", team.value()), 22,
m_username, m_password);
} else {
session = std::make_unique<sftp::Session>(m_serverTeam, 22,
m_username, m_password);
}
lock.unlock();
try {
session->Connect();
} catch (...) {
lock.lock();
throw;
}
lock.lock();
// FALLTHROUGH
case kGetFiles: {
std::string dir = m_remoteDir;
std::vector<sftp::Attributes> fileList;
lock.unlock();
try {
fileList = session->ReadDir(dir);
} catch (sftp::Exception& ex) {
lock.lock();
if (ex.err == SSH_FX_OK || ex.err == SSH_FX_CONNECTION_LOST) {
throw;
}
m_error = ex.what();
m_dirList.clear();
m_downloadList.clear();
m_state = kConnected;
break;
}
std::sort(
fileList.begin(), fileList.end(),
[](const auto& l, const auto& r) { return l.name < r.name; });
lock.lock();
m_dirList.clear();
m_downloadList.clear();
for (auto&& attr : fileList) {
if (attr.type == SSH_FILEXFER_TYPE_DIRECTORY) {
if (attr.name != ".") {
m_dirList.emplace_back(attr.name);
}
} else if (attr.type == SSH_FILEXFER_TYPE_REGULAR &&
(attr.flags & SSH_FILEXFER_ATTR_SIZE) != 0 &&
wpi::ends_with(attr.name, ".wpilog")) {
m_downloadList.emplace_back(attr.name, attr.size);
}
}
m_state = kConnected;
break;
}
case kDisconnecting:
session.reset();
m_state = kDisconnected;
break;
case kDownload: {
for (auto&& download : m_downloadList) {
if (m_state != kDownload) {
// user aborted
break;
}
if (!download.enabled) {
continue;
}
auto remoteFilename = fmt::format(
"{}{}{}", m_remoteDir,
wpi::ends_with(m_remoteDir, '/') ? "" : "/", download.name);
auto localFilename = fs::path{m_localDir} / download.name;
uint64_t fileSize = download.size;
lock.unlock();
// open local file
std::error_code ec;
fs::file_t of = fs::OpenFileForWrite(localFilename, ec,
fs::CD_CreateNew, fs::OF_None);
if (ec) {
// failed to open
lock.lock();
download.status = ec.message();
continue;
}
int ofd = fs::FileToFd(of, ec, fs::OF_None);
if (ofd == -1 || ec) {
// failed to convert to fd
lock.lock();
download.status = ec.message();
continue;
}
try {
// open remote file
sftp::File f = session->Open(remoteFilename, O_RDONLY, 0);
// copy in chunks
uint64_t total = 0;
while (total < fileSize) {
uint64_t toCopy = (std::min)(fileSize - total,
static_cast<uint64_t>(kBufSize));
auto copied = f.Read(copyBuf.get(), toCopy);
if (write(ofd, copyBuf.get(), copied) !=
static_cast<int64_t>(copied)) {
// error writing
close(ofd);
fs::remove(localFilename, ec);
lock.lock();
download.status = "error writing local file";
goto err;
}
total += copied;
lock.lock();
download.complete = static_cast<float>(total) / fileSize;
lock.unlock();
}
// close local file
close(ofd);
ofd = -1;
// delete remote file (if enabled)
if (m_deleteAfter) {
f = sftp::File{};
session->Unlink(remoteFilename);
}
} catch (sftp::Exception& ex) {
if (ofd != -1) {
// close local file and delete it (due to failure)
close(ofd);
fs::remove(localFilename, ec);
}
lock.lock();
download.status = ex.what();
if (ex.err == SSH_FX_OK || ex.err == SSH_FX_CONNECTION_LOST) {
throw;
}
continue;
}
lock.lock();
err : {}
}
if (m_state == kDownload) {
m_state = kDownloadDone;
}
break;
}
default:
break;
}
} catch (sftp::Exception& ex) {
m_error = ex.what();
session.reset();
m_state = kDisconnected;
}
}
}

View File

@@ -0,0 +1,78 @@
// 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 <memory>
#include <string>
#include <thread>
#include <vector>
#include <wpi/condition_variable.h>
#include <wpi/mutex.h>
namespace glass {
class Storage;
} // namespace glass
namespace pfd {
class select_folder;
} // namespace pfd
class Downloader {
public:
explicit Downloader(glass::Storage& storage);
~Downloader();
void Display();
private:
void DisplayConnect();
void DisplayDisconnectButton();
void DisplayRemoteDirSelector();
void DisplayLocalDirSelector();
size_t DisplayFiles();
void ThreadMain();
wpi::mutex m_mutex;
enum State {
kDisconnected,
kConnecting,
kConnected,
kDisconnecting,
kGetFiles,
kDownload,
kDownloadDone,
kExit
} m_state = kDisconnected;
std::condition_variable m_cv;
std::string& m_serverTeam;
std::string& m_remoteDir;
std::string& m_username;
std::string m_password;
std::string& m_localDir;
std::unique_ptr<pfd::select_folder> m_localDirSelector;
bool& m_deleteAfter;
std::vector<std::string> m_dirList;
struct DownloadState {
DownloadState(std::string_view name, uint64_t size)
: name{name}, size{size} {}
std::string name;
uint64_t size;
bool enabled = true;
float complete = 0.0;
std::string status;
};
std::vector<DownloadState> m_downloadList;
std::string m_error;
std::thread m_thread;
};

View File

@@ -0,0 +1,655 @@
// 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 "Exporter.h"
#include <atomic>
#include <ctime>
#include <future>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <string_view>
#include <vector>
#include <fmt/chrono.h>
#include <fmt/format.h>
#include <glass/Storage.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <imgui_stdlib.h>
#include <portable-file-dialogs.h>
#include <wpi/DenseMap.h>
#include <wpi/MemoryBuffer.h>
#include <wpi/SmallVector.h>
#include <wpi/SpanExtras.h>
#include <wpi/StringExtras.h>
#include <wpi/fmt/raw_ostream.h>
#include <wpi/fs.h>
#include <wpi/mutex.h>
#include <wpi/raw_ostream.h>
#include "App.h"
#include "DataLogThread.h"
namespace {
struct InputFile {
explicit InputFile(std::unique_ptr<DataLogThread> datalog);
InputFile(std::string_view filename, std::string_view status)
: filename{filename},
stem{fs::path{filename}.stem().string()},
status{status} {}
~InputFile();
std::string filename;
std::string stem;
std::unique_ptr<DataLogThread> datalog;
std::string status;
bool highlight = false;
};
struct Entry {
explicit Entry(const wpi::log::StartRecordData& srd)
: name{srd.name}, type{srd.type}, metadata{srd.metadata} {}
std::string name;
std::string type;
std::string metadata;
std::set<InputFile*> inputFiles;
bool typeConflict = false;
bool metadataConflict = false;
bool selected = true;
// used only during export
int column = -1;
};
struct EntryTreeNode {
explicit EntryTreeNode(std::string_view name) : name{name} {}
std::string name; // name of just this node
std::string path; // full path if entry is nullptr
Entry* entry = nullptr;
std::vector<EntryTreeNode> children; // children, sorted by name
int selected = 1;
};
} // namespace
static std::map<std::string, std::unique_ptr<InputFile>, std::less<>>
gInputFiles;
static wpi::mutex gEntriesMutex;
static std::map<std::string, std::unique_ptr<Entry>, std::less<>> gEntries;
static std::vector<EntryTreeNode> gEntryTree;
std::atomic_int gExportCount{0};
// must be called with gEntriesMutex held
static void RebuildEntryTree() {
gEntryTree.clear();
wpi::SmallVector<std::string_view, 16> parts;
for (auto& kv : gEntries) {
parts.clear();
// split on first : if one is present
auto [prefix, mainpart] = wpi::split(kv.first, ':');
if (mainpart.empty() || wpi::contains(prefix, '/')) {
mainpart = kv.first;
} else {
parts.emplace_back(prefix);
}
wpi::split(mainpart, parts, '/', -1, false);
// ignore a raw "/" key
if (parts.empty()) {
continue;
}
// get to leaf
auto nodes = &gEntryTree;
for (auto part : wpi::drop_back(wpi::span{parts.begin(), parts.end()})) {
auto it =
std::find_if(nodes->begin(), nodes->end(),
[&](const auto& node) { return node.name == part; });
if (it == nodes->end()) {
nodes->emplace_back(part);
// path is from the beginning of the string to the end of the current
// part; this works because part is a reference to the internals of
// kv.first
nodes->back().path.assign(kv.first.data(),
part.data() + part.size() - kv.first.data());
it = nodes->end() - 1;
}
nodes = &it->children;
}
auto it = std::find_if(nodes->begin(), nodes->end(), [&](const auto& node) {
return node.name == parts.back();
});
if (it == nodes->end()) {
nodes->emplace_back(parts.back());
// no need to set path, as it's identical to kv.first
it = nodes->end() - 1;
}
it->entry = kv.second.get();
}
}
InputFile::InputFile(std::unique_ptr<DataLogThread> datalog_)
: filename{datalog_->GetBufferIdentifier()},
stem{fs::path{filename}.stem().string()},
datalog{std::move(datalog_)} {
datalog->sigEntryAdded.connect([this](const wpi::log::StartRecordData& srd) {
std::scoped_lock lock{gEntriesMutex};
auto it = gEntries.find(srd.name);
if (it == gEntries.end()) {
it = gEntries.emplace(srd.name, std::make_unique<Entry>(srd)).first;
RebuildEntryTree();
} else {
if (it->second->type != srd.type) {
it->second->typeConflict = true;
}
if (it->second->metadata != srd.metadata) {
it->second->metadataConflict = true;
}
}
it->second->inputFiles.emplace(this);
});
}
InputFile::~InputFile() {
if (gShutdown || !datalog) {
return;
}
std::scoped_lock lock{gEntriesMutex};
bool changed = false;
for (auto it = gEntries.begin(); it != gEntries.end();) {
it->second->inputFiles.erase(this);
if (it->second->inputFiles.empty()) {
it = gEntries.erase(it);
changed = true;
} else {
++it;
}
}
if (changed) {
RebuildEntryTree();
}
}
static std::unique_ptr<InputFile> LoadDataLog(std::string_view filename) {
std::error_code ec;
auto buf = wpi::MemoryBuffer::GetFile(filename, ec);
std::string fn{filename};
if (ec) {
return std::make_unique<InputFile>(
fn, fmt::format("Could not open file: {}", ec.message()));
}
wpi::log::DataLogReader reader{std::move(buf)};
if (!reader.IsValid()) {
return std::make_unique<InputFile>(fn, "Not a valid datalog file");
}
return std::make_unique<InputFile>(
std::make_unique<DataLogThread>(std::move(reader)));
}
void DisplayInputFiles() {
static std::unique_ptr<pfd::open_file> dataFileSelector;
SetNextWindowPos(ImVec2{0, 20}, ImGuiCond_FirstUseEver);
SetNextWindowSize(ImVec2{375, 230}, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Input Files")) {
if (ImGui::Button("Open File(s)...")) {
dataFileSelector = std::make_unique<pfd::open_file>(
"Select Data Log", "",
std::vector<std::string>{"DataLog Files", "*.wpilog"},
pfd::opt::multiselect);
}
ImGui::BeginTable(
"Input Files", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchProp);
ImGui::TableSetupColumn("File");
ImGui::TableSetupColumn("Status");
ImGui::TableSetupColumn("X", ImGuiTableColumnFlags_WidthFixed |
ImGuiTableColumnFlags_NoHeaderLabel |
ImGuiTableColumnFlags_NoHeaderWidth);
ImGui::TableHeadersRow();
for (auto it = gInputFiles.begin(); it != gInputFiles.end();) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (it->second->highlight) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
IM_COL32(0, 64, 0, 255));
it->second->highlight = false;
}
ImGui::TextUnformatted(it->first.c_str());
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", it->second->filename.c_str());
}
ImGui::TableNextColumn();
if (it->second->datalog) {
ImGui::Text("%u records, %u entries%s",
it->second->datalog->GetNumRecords(),
it->second->datalog->GetNumEntries(),
it->second->datalog->IsDone() ? "" : " (working)");
} else {
ImGui::TextUnformatted(it->second->status.c_str());
}
ImGui::TableNextColumn();
ImGui::PushID(it->first.c_str());
if (ImGui::SmallButton("X")) {
it = gInputFiles.erase(it);
gExportCount = 0;
} else {
++it;
}
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::End();
// Load data file(s)
if (dataFileSelector && dataFileSelector->ready(0)) {
auto result = dataFileSelector->result();
for (auto&& filename : result) {
// don't allow duplicates
std::string stem = fs::path{filename}.stem().string();
auto it = gInputFiles.find(stem);
if (it == gInputFiles.end()) {
gInputFiles.emplace(std::move(stem), LoadDataLog(filename));
gExportCount = 0;
}
}
dataFileSelector.reset();
}
}
static bool EmitEntry(const std::string& name, Entry& entry) {
ImGui::TableNextColumn();
bool rv = ImGui::Checkbox(name.c_str(), &entry.selected);
if (ImGui::IsItemHovered() && gInputFiles.size() > 1) {
for (auto inputFile : entry.inputFiles) {
inputFile->highlight = true;
}
}
ImGui::TableNextColumn();
if (entry.typeConflict) {
ImGui::TextUnformatted("(Inconsistent)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
for (auto inputFile : entry.inputFiles) {
ImGui::Text(
"%s: %s", inputFile->stem.c_str(),
std::string{inputFile->datalog->GetEntry(entry.name).type}.c_str());
}
ImGui::EndTooltip();
}
} else {
ImGui::TextUnformatted(entry.type.c_str());
}
ImGui::TableNextColumn();
if (entry.metadataConflict) {
ImGui::TextUnformatted("(Inconsistent)");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
for (auto inputFile : entry.inputFiles) {
ImGui::Text(
"%s: %s", inputFile->stem.c_str(),
std::string{inputFile->datalog->GetEntry(entry.name).metadata}
.c_str());
}
ImGui::EndTooltip();
}
} else {
ImGui::TextUnformatted(entry.metadata.c_str());
}
return rv;
}
static bool EmitEntryTree(std::vector<EntryTreeNode>& tree) {
bool rv = false;
for (auto&& node : tree) {
if (node.entry) {
if (EmitEntry(node.name, *node.entry)) {
rv = true;
}
}
if (!node.children.empty()) {
ImGui::TableNextColumn();
auto label = fmt::format("##check_{}", node.name);
if (node.selected == -1) {
ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, true);
bool b = false;
if (ImGui::Checkbox(label.c_str(), &b)) {
node.selected = 3; // 3 = enable group
rv = true;
}
ImGui::PopItemFlag();
} else {
bool b = node.selected == 1 || node.selected == 3;
if (ImGui::Checkbox(label.c_str(), &b)) {
node.selected = b ? 3 : 2; // 2 = disable group
rv = true;
}
}
ImGui::SameLine();
bool open = ImGui::TreeNodeEx(node.name.c_str(),
ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
if (open) {
if (EmitEntryTree(node.children)) {
rv = true;
}
ImGui::TreePop();
}
}
}
return rv;
}
static void RefreshTreeCheckboxes(std::vector<EntryTreeNode>& tree,
int* selected) {
bool first = true;
for (auto&& node : tree) {
if (node.entry) {
if (first && *selected == -1) {
*selected = node.entry->selected ? 1 : 0;
}
if ((*selected == 0 && node.entry->selected) ||
(*selected == 1 && !node.entry->selected)) {
*selected = -1; // inconsistent
} else if (*selected == 2) { // disable group
node.entry->selected = false;
} else if (*selected == 3) { // enable group
node.entry->selected = true;
}
}
if (!node.children.empty()) {
if (*selected == 2) { // disable group
node.selected = 2;
} else if (*selected == 3) { // enable group
node.selected = 3;
}
RefreshTreeCheckboxes(node.children, &node.selected);
if (node.selected == 2) {
node.selected = 0;
} else if (node.selected == 3) {
node.selected = 1;
}
if (first && *selected == -1) {
*selected = node.selected;
} else if (node.selected == -1 ||
(*selected == 0 && node.selected == 1) ||
(*selected == 1 && node.selected == 0)) {
*selected = -1; // inconsistent
}
}
first = false;
}
}
void DisplayEntries() {
SetNextWindowPos(ImVec2{380, 20}, ImGuiCond_FirstUseEver);
SetNextWindowSize(ImVec2{540, 365}, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Entries")) {
static bool treeView = true;
if (ImGui::BeginPopupContextItem()) {
ImGui::MenuItem("Tree View", "", &treeView);
ImGui::EndPopup();
}
std::scoped_lock lock{gEntriesMutex};
ImGui::BeginTable(
"Entries", 3,
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchProp);
ImGui::TableSetupColumn("Name");
ImGui::TableSetupColumn("Type");
ImGui::TableSetupColumn("Metadata");
ImGui::TableHeadersRow();
if (treeView) {
if (EmitEntryTree(gEntryTree)) {
int selected = -1;
RefreshTreeCheckboxes(gEntryTree, &selected);
}
} else {
for (auto&& kv : gEntries) {
EmitEntry(kv.first, *kv.second);
}
}
ImGui::EndTable();
}
ImGui::End();
}
static wpi::mutex gExportMutex;
static std::vector<std::string> gExportErrors;
static void PrintEscapedCsvString(wpi::raw_ostream& os, std::string_view str) {
auto s = str;
while (!s.empty()) {
std::string_view fragment;
std::tie(fragment, s) = wpi::split(s, '"');
os << fragment;
if (!s.empty()) {
os << '"' << '"';
}
}
if (wpi::ends_with(str, '"')) {
os << '"' << '"';
}
}
static void ValueToCsv(wpi::raw_ostream& os, const Entry& entry,
const wpi::log::DataLogRecord& record) {
// handle systemTime specially
if (entry.name == "systemTime" && entry.type == "int64") {
int64_t val;
if (record.GetInteger(&val)) {
std::time_t timeval = val / 1000000;
fmt::print(os, "{:%Y-%m-%d %H:%M:%S}.{:06}", *std::localtime(&timeval),
val % 1000000);
return;
}
} else if (entry.type == "double") {
double val;
if (record.GetDouble(&val)) {
fmt::print(os, "{}", val);
return;
}
} else if (entry.type == "int64") {
int64_t val;
if (record.GetInteger(&val)) {
fmt::print(os, "{}", val);
return;
}
} else if (entry.type == "string" || entry.type == "json") {
std::string_view val;
record.GetString(&val);
os << '"';
PrintEscapedCsvString(os, val);
os << '"';
return;
} else if (entry.type == "boolean") {
bool val;
if (record.GetBoolean(&val)) {
fmt::print(os, "{}", val);
return;
}
} else if (entry.type == "double[]") {
std::vector<double> val;
if (record.GetDoubleArray(&val)) {
fmt::print(os, "{}", fmt::join(val, ";"));
return;
}
} else if (entry.type == "float[]") {
std::vector<float> val;
if (record.GetFloatArray(&val)) {
fmt::print(os, "{}", fmt::join(val, ";"));
return;
}
} else if (entry.type == "int64[]") {
std::vector<int64_t> val;
if (record.GetIntegerArray(&val)) {
fmt::print(os, "{}", fmt::join(val, ";"));
return;
}
} else if (entry.type == "string[]") {
std::vector<std::string_view> val;
if (record.GetStringArray(&val)) {
os << '"';
bool first = true;
for (auto&& v : val) {
if (!first) {
os << ';';
}
first = false;
PrintEscapedCsvString(os, v);
}
os << '"';
return;
}
}
fmt::print(os, "<invalid>");
}
static void ExportCsvFile(InputFile& f, wpi::raw_ostream& os, int style) {
// header
if (style == 0) {
os << "Timestamp,Name,Value\n";
} else if (style == 1) {
// scan for exported fields for this file to print header and assign columns
os << "Timestamp";
int columnNum = 0;
for (auto&& entry : gEntries) {
if (entry.second->selected &&
entry.second->inputFiles.find(&f) != entry.second->inputFiles.end()) {
os << ',' << '"';
PrintEscapedCsvString(os, entry.first);
os << '"';
entry.second->column = columnNum++;
} else {
entry.second->column = -1;
}
}
os << '\n';
}
wpi::DenseMap<int, Entry*> nameMap;
for (auto&& record : f.datalog->GetReader()) {
if (record.IsStart()) {
wpi::log::StartRecordData data;
if (record.GetStartData(&data)) {
auto it = gEntries.find(data.name);
if (it != gEntries.end() && it->second->selected) {
nameMap[data.entry] = it->second.get();
}
}
} else if (record.IsFinish()) {
int entry;
if (record.GetFinishEntry(&entry)) {
nameMap.erase(entry);
}
} else if (!record.IsControl()) {
auto entryIt = nameMap.find(record.GetEntry());
if (entryIt == nameMap.end()) {
continue;
}
Entry* entry = entryIt->second;
if (style == 0) {
fmt::print(os, "{},\"", record.GetTimestamp() / 1000000.0);
PrintEscapedCsvString(os, entry->name);
os << '"' << ',';
ValueToCsv(os, *entry, record);
os << '\n';
} else if (style == 1 && entry->column != -1) {
fmt::print(os, "{},", record.GetTimestamp() / 1000000.0);
for (int i = 0; i < entry->column; ++i) {
os << ',';
}
ValueToCsv(os, *entry, record);
os << '\n';
}
}
}
}
static void ExportCsv(std::string_view outputFolder, int style) {
fs::path outPath{outputFolder};
for (auto&& f : gInputFiles) {
if (f.second->datalog) {
std::error_code ec;
auto of = fs::OpenFileForWrite(
outPath / fs::path{f.first}.replace_extension("csv"), ec,
fs::CD_CreateNew, fs::OF_Text);
if (ec) {
std::scoped_lock lock{gExportMutex};
gExportErrors.emplace_back(
fmt::format("{}: {}", f.first, ec.message()));
++gExportCount;
continue;
}
wpi::raw_fd_ostream os{fs::FileToFd(of, ec, fs::OF_Text), true};
ExportCsvFile(*f.second, os, style);
}
++gExportCount;
}
}
void DisplayOutput(glass::Storage& storage) {
static std::string& outputFolder = storage.GetString("outputFolder");
static std::unique_ptr<pfd::select_folder> outputFolderSelector;
SetNextWindowPos(ImVec2{380, 390}, ImGuiCond_FirstUseEver);
SetNextWindowSize(ImVec2{540, 120}, ImGuiCond_FirstUseEver);
if (ImGui::Begin("Output")) {
if (ImGui::Button("Select Output Folder...")) {
outputFolderSelector =
std::make_unique<pfd::select_folder>("Select Output Folder");
}
ImGui::TextUnformatted(outputFolder.c_str());
static const char* const options[] = {"List", "Table"};
static int style = 0;
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
ImGui::Combo("Style", &style, options,
sizeof(options) / sizeof(const char*));
static std::future<void> exporter;
if (!gInputFiles.empty() && !outputFolder.empty() &&
ImGui::Button("Export CSV") &&
(gExportCount == 0 ||
gExportCount == static_cast<int>(gInputFiles.size()))) {
gExportCount = 0;
gExportErrors.clear();
exporter = std::async(std::launch::async, ExportCsv, outputFolder, style);
}
if (exporter.valid()) {
ImGui::SameLine();
ImGui::Text("Exported %d/%d", gExportCount.load(),
static_cast<int>(gInputFiles.size()));
}
{
std::scoped_lock lock{gExportMutex};
for (auto&& err : gExportErrors) {
ImGui::TextUnformatted(err.c_str());
}
}
}
ImGui::End();
if (outputFolderSelector && outputFolderSelector->ready(0)) {
outputFolder = outputFolderSelector->result();
outputFolderSelector.reset();
}
}

View File

@@ -0,0 +1,15 @@
// 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
namespace glass {
class Storage;
} // namespace glass
void DisplayInputFiles();
void DisplayEntries();
void DisplayOutput(glass::Storage& storage);
extern bool gShutdown;

View File

@@ -0,0 +1,215 @@
// 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 "Sftp.h"
#include <fmt/format.h>
using namespace sftp;
Attributes::Attributes(sftp_attributes&& attr)
: name{attr->name}, flags{attr->flags}, type{attr->type}, size{attr->size} {
sftp_attributes_free(attr);
}
static std::string GetError(sftp_session sftp) {
switch (sftp_get_error(sftp)) {
case SSH_FX_EOF:
return "end of file";
case SSH_FX_NO_SUCH_FILE:
return "no such file";
case SSH_FX_PERMISSION_DENIED:
return "permission denied";
case SSH_FX_FAILURE:
return "SFTP failure";
case SSH_FX_BAD_MESSAGE:
return "SFTP bad message";
case SSH_FX_NO_CONNECTION:
return "SFTP no connection";
case SSH_FX_CONNECTION_LOST:
return "SFTP connection lost";
case SSH_FX_OP_UNSUPPORTED:
return "SFTP operation unsupported";
case SSH_FX_INVALID_HANDLE:
return "SFTP invalid handle";
case SSH_FX_NO_SUCH_PATH:
return "no such path";
case SSH_FX_FILE_ALREADY_EXISTS:
return "file already exists";
case SSH_FX_WRITE_PROTECT:
return "write protected filesystem";
case SSH_FX_NO_MEDIA:
return "no media inserted";
default:
return ssh_get_error(sftp->session);
}
}
Exception::Exception(sftp_session sftp)
: runtime_error{GetError(sftp)}, err{sftp_get_error(sftp)} {}
File::~File() {
if (m_handle) {
sftp_close(m_handle);
}
}
Attributes File::Stat() const {
sftp_attributes attr = sftp_fstat(m_handle);
if (!attr) {
throw Exception{m_handle->sftp};
}
return Attributes{std::move(attr)};
}
size_t File::Read(void* buf, uint32_t count) {
auto rv = sftp_read(m_handle, buf, count);
if (rv < 0) {
throw Exception{m_handle->sftp};
}
return rv;
}
File::AsyncId File::AsyncReadBegin(uint32_t len) const {
int rv = sftp_async_read_begin(m_handle, len);
if (rv < 0) {
throw Exception{m_handle->sftp};
}
return rv;
}
size_t File::AsyncRead(void* data, uint32_t len, AsyncId id) {
auto rv = sftp_async_read(m_handle, data, len, id);
if (rv == SSH_ERROR) {
throw Exception{ssh_get_error(m_handle->sftp->session)};
}
if (rv == SSH_AGAIN) {
return 0;
}
return rv;
}
size_t File::Write(wpi::span<const uint8_t> data) {
auto rv = sftp_write(m_handle, data.data(), data.size());
if (rv < 0) {
throw Exception{m_handle->sftp};
}
return rv;
}
void File::Seek(uint64_t offset) {
if (sftp_seek64(m_handle, offset) < 0) {
throw Exception{m_handle->sftp};
}
}
uint64_t File::Tell() const {
return sftp_tell64(m_handle);
}
void File::Rewind() {
sftp_rewind(m_handle);
}
void File::Sync() {
if (sftp_fsync(m_handle) < 0) {
throw Exception{m_handle->sftp};
}
}
Session::Session(std::string_view host, int port, std::string_view user,
std::string_view pass)
: m_host{host}, m_port{port}, m_username{user}, m_password{pass} {
// Create a new SSH session.
m_session = ssh_new();
if (!m_session) {
throw Exception{"The SSH session could not be allocated."};
}
// Set the host, user, and port.
ssh_options_set(m_session, SSH_OPTIONS_HOST, m_host.c_str());
ssh_options_set(m_session, SSH_OPTIONS_USER, m_username.c_str());
ssh_options_set(m_session, SSH_OPTIONS_PORT, &m_port);
// Set timeout to 3 seconds.
int64_t timeout = 3L;
ssh_options_set(m_session, SSH_OPTIONS_TIMEOUT, &timeout);
// Set other miscellaneous options.
ssh_options_set(m_session, SSH_OPTIONS_STRICTHOSTKEYCHECK, "no");
}
Session::~Session() {
if (m_sftp) {
sftp_free(m_sftp);
}
if (m_session) {
ssh_free(m_session);
}
}
void Session::Connect() {
// Connect to the server.
int rc = ssh_connect(m_session);
if (rc != SSH_OK) {
throw Exception{ssh_get_error(m_session)};
}
// Authenticate with password.
rc = ssh_userauth_password(m_session, nullptr, m_password.c_str());
if (rc != SSH_AUTH_SUCCESS) {
throw Exception{ssh_get_error(m_session)};
}
// Allocate the SFTP session.
m_sftp = sftp_new(m_session);
if (!m_sftp) {
throw Exception{ssh_get_error(m_session)};
}
// Initialize.
rc = sftp_init(m_sftp);
if (rc != SSH_OK) {
sftp_free(m_sftp);
m_sftp = nullptr;
throw Exception{ssh_get_error(m_session)};
}
}
void Session::Disconnect() {
if (m_sftp) {
sftp_free(m_sftp);
m_sftp = nullptr;
}
ssh_disconnect(m_session);
}
std::vector<Attributes> Session::ReadDir(const std::string& path) {
sftp_dir dir = sftp_opendir(m_sftp, path.c_str());
if (!dir) {
throw Exception{m_sftp};
}
std::vector<Attributes> rv;
while (sftp_attributes attr = sftp_readdir(m_sftp, dir)) {
rv.emplace_back(std::move(attr));
}
sftp_closedir(dir);
return rv;
}
void Session::Unlink(const std::string& filename) {
if (sftp_unlink(m_sftp, filename.c_str()) < 0) {
throw Exception{m_sftp};
}
}
File Session::Open(const std::string& filename, int accesstype, mode_t mode) {
sftp_file f = sftp_open(m_sftp, filename.c_str(), accesstype, mode);
if (!f) {
throw Exception{m_sftp};
}
return File{std::move(f)};
}

View File

@@ -0,0 +1,144 @@
// 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 <libssh/libssh.h>
#include <libssh/sftp.h>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <wpi/span.h>
namespace sftp {
struct Attributes {
Attributes() = default;
explicit Attributes(sftp_attributes&& attr);
std::string name;
uint32_t flags = 0;
uint8_t type = 0;
uint64_t size = 0;
};
/**
* This is the exception that will be thrown if something goes wrong.
*/
class Exception : public std::runtime_error {
public:
explicit Exception(const std::string& msg) : std::runtime_error{msg} {}
explicit Exception(sftp_session sftp);
int err = 0;
};
class File {
public:
File() = default;
explicit File(sftp_file&& handle) : m_handle{handle} {}
~File();
Attributes Stat() const;
void SetNonblocking() { sftp_file_set_nonblocking(m_handle); }
void SetBlocking() { sftp_file_set_blocking(m_handle); }
using AsyncId = uint32_t;
size_t Read(void* buf, uint32_t count);
AsyncId AsyncReadBegin(uint32_t len) const;
size_t AsyncRead(void* data, uint32_t len, AsyncId id);
size_t Write(wpi::span<const uint8_t> data);
void Seek(uint64_t offset);
uint64_t Tell() const;
void Rewind();
void Sync();
std::string_view GetName() const { return m_handle->name; }
uint64_t GetOffset() const { return m_handle->offset; }
bool IsEof() const { return m_handle->eof; }
bool IsNonblocking() const { return m_handle->nonblocking; }
private:
sftp_file m_handle{nullptr};
};
/**
* This class is a C++ implementation of the SshSessionController in
* wpilibsuite/deploy-utils. It handles connecting to an SSH server, running
* commands, and transferring files.
*/
class Session {
public:
/**
* Constructs a new session controller.
*
* @param host The hostname of the server to connect to.
* @param port The port that the sshd server is operating on.
* @param user The username to login as.
* @param pass The password for the given username.
*/
Session(std::string_view host, int port, std::string_view user,
std::string_view pass);
/**
* Destroys the controller object. This also disconnects the session from the
* server.
*/
~Session();
/**
* Opens the SSH connection to the given host.
*/
void Connect();
/**
* Disconnects the SSH connection.
*/
void Disconnect();
/**
* Reads directory entries
*
* @param path remote path
* @return vector of file attributes
*/
std::vector<Attributes> ReadDir(const std::string& path);
/**
* Unlinks (deletes) a file.
*
* @param filename filename
*/
void Unlink(const std::string& filename);
/**
* Opens a file.
*
* @param filename filename
* @param accesstype O_RDONLY, O_WRONLY, or O_RDWR, combined with O_CREAT,
* O_EXCL, or O_TRUNC
* @param mode permissions to use if a new file is created
* @return File
*/
File Open(const std::string& filename, int accesstype, mode_t mode);
private:
ssh_session m_session{nullptr};
sftp_session m_sftp{nullptr};
std::string m_host;
int m_port;
std::string m_username;
std::string m_password;
};
} // namespace sftp

View File

@@ -0,0 +1,25 @@
// 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 <string_view>
void Application(std::string_view saveDir);
#ifdef _WIN32
int __stdcall WinMain(void* hInstance, void* hPrevInstance, char* pCmdLine,
int nCmdShow) {
int argc = __argc;
char** argv = __argv;
#else
int main(int argc, char** argv) {
#endif
std::string_view saveDir;
if (argc == 2) {
saveDir = argv[1];
}
Application(saveDir);
return 0;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

View File

@@ -0,0 +1 @@
IDI_ICON1 ICON "datalogtool.ico"

View File

@@ -15,10 +15,14 @@ if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxra
ext {
nativeName = 'fieldImages'
baseId = nativeName
groupId = 'edu.wpi.first.fieldImages'
devMain = "edu.wpi.first.fieldImages.DevMain"
}
apply from: "${rootDir}/shared/resources.gradle"
apply from: "${rootDir}/shared/config.gradle"
apply from: "${rootDir}/shared/java/javacommon.gradle"
def generateTask = createGenerateResourcesTask('main', 'FIELDS', 'fields', project)

View File

@@ -1,14 +1,14 @@
apply plugin: 'maven-publish'
def baseArtifactId = 'fieldImages'
def artifactGroupId = 'edu.wpi.first.fieldImages'
def zipBaseName = '_GROUP_edu_wpi_first_field_images_ID_CLS'
def baseArtifactId = project.nativeName
def artifactGroupId = project.groupId
def cppZipBaseName = "_GROUP_edu_wpi_first_fieldIimages_ID_${baseArtifactId}-cpp_CLS"
def outputsFolder = file("$project.buildDir/outputs")
task cppSourcesZip(type: Zip) {
destinationDirectory = outputsFolder
archiveBaseName = zipBaseName
archiveBaseName = cppZipBaseName
classifier = "sources"
from(licenseFile) {
@@ -25,7 +25,7 @@ task cppSourcesZip(type: Zip) {
task cppHeadersZip(type: Zip) {
destinationDirectory = outputsFolder
archiveBaseName = zipBaseName
archiveBaseName = cppZipBaseName
classifier = "headers"
from(licenseFile) {
@@ -51,7 +51,7 @@ addTaskToCopyAllOutputs(cppSourcesZip)
model {
publishing {
def wpilibCTaskList = createComponentZipTasks($.components, ['fieldImages'], zipBaseName, Zip, project, includeStandardZipFormat)
def wpilibCTaskList = createComponentZipTasks($.components, ['fieldImages'], cppZipBaseName, Zip, project, includeStandardZipFormat)
publications {
cpp(MavenPublication) {
@@ -62,7 +62,7 @@ model {
artifact cppHeadersZip
artifact cppSourcesZip
artifactId = baseArtifactId
artifactId = "${baseArtifactId}-cpp"
groupId artifactGroupId
version wpilibVersioning.version.get()
}

View File

@@ -20,4 +20,6 @@ public class FieldImages {
public static final String k2021GalacticSearchBFieldConfig =
"/edu/wpi/first/fields/2021-galacticsearchb.json";
public static final String k2021SlalomFieldConfig = "/edu/wpi/first/fields/2021-slalompath.json";
public static final String k2022RapidReactFieldConfig =
"/edu/wpi/first/fields/2022-rapidreact.json";
}

View File

@@ -0,0 +1,12 @@
// 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_view>
namespace fields {
std::string_view GetResource_2022_rapidreact_json();
std::string_view GetResource_2022_field_png();
} // namespace fields

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,10 @@
{
"game": "Rapid React",
"field-image": "2022-field.png",
"field-corners": {
"top-left": [74, 50],
"bottom-right": [1774, 900]
},
"field-size": [54, 27],
"field-unit": "foot"
}

View File

@@ -185,15 +185,18 @@ if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxra
it.buildable = false
return
}
lib project: ':cscore', library: 'cscore', linkage: 'static'
lib library: 'glassnt', linkage: 'static'
lib library: nativeName, linkage: 'static'
lib project: ':ntcore', library: 'ntcore', linkage: 'static'
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
lib project: ':wpimath', library: 'wpimath', linkage: 'static'
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
nativeUtils.useRequiredLibrary(it, 'opencv_static')
nativeUtils.useRequiredLibrary(it, 'imgui_static')
if (it.targetPlatform.operatingSystem.isWindows()) {
it.linker.args << 'Gdi32.lib' << 'Shell32.lib' << 'd3d11.lib' << 'd3dcompiler.lib'
it.linker.args << '/DELAYLOAD:MF.dll' << '/DELAYLOAD:MFReadWrite.dll' << '/DELAYLOAD:MFPlat.dll' << '/delay:nobind'
} else if (it.targetPlatform.operatingSystem.isMacOsX()) {
it.linker.args << '-framework' << 'Metal' << '-framework' << 'MetalKit' << '-framework' << 'Cocoa' << '-framework' << 'IOKit' << '-framework' << 'CoreFoundation' << '-framework' << 'CoreVideo' << '-framework' << 'QuartzCore'
} else {

View File

@@ -130,6 +130,14 @@ model {
}
from(applicationPath)
if (binary.targetPlatform.operatingSystem.isWindows()) {
def exePath = binary.executable.file.absolutePath
exePath = exePath.substring(0, exePath.length() - 4)
def pdbPath = new File(exePath + '.pdb')
from(pdbPath)
}
into(nativeUtils.getPlatformPath(binary))
}

View File

@@ -0,0 +1,52 @@
// 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 "camerasupport.h"
#ifdef _WIN32
#include "Windows.h"
#include "delayimp.h"
#pragma comment(lib, "delayimp.lib")
static int CheckDelayException(int exception_value) {
if (exception_value ==
VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) ||
exception_value ==
VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND)) {
// This example just executes the handler.
return EXCEPTION_EXECUTE_HANDLER;
}
// Don't attempt to handle other errors
return EXCEPTION_CONTINUE_SEARCH;
}
static bool TryDelayLoadAllImports(LPCSTR szDll) {
__try {
HRESULT hr = __HrLoadAllImportsForDll(szDll);
if (FAILED(hr)) {
return false;
}
} __except (CheckDelayException(GetExceptionCode())) {
return false;
}
return true;
}
namespace glass {
bool HasCameraSupport() {
bool hasCameraSupport = false;
hasCameraSupport = TryDelayLoadAllImports("MF.dll");
if (hasCameraSupport) {
hasCameraSupport = TryDelayLoadAllImports("MFPlat.dll");
}
if (hasCameraSupport) {
hasCameraSupport = TryDelayLoadAllImports("MFReadWrite.dll");
}
return hasCameraSupport;
}
} // namespace glass
#else
namespace glass {
bool HasCameraSupport() {
return true;
}
} // namespace glass
#endif

View File

@@ -0,0 +1,9 @@
// 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
namespace glass {
bool HasCameraSupport();
} // namespace glass

View File

@@ -47,6 +47,8 @@ static std::unique_ptr<glass::Window> gNetworkTablesLogWindow;
static glass::MainMenuBar gMainMenu;
static bool gAbout = false;
static bool gSetEnterKey = false;
static bool gKeyEdit = false;
static void NtInitialize() {
// update window title when connection status changes
@@ -178,6 +180,9 @@ int main(int argc, char** argv) {
gMainMenu.AddMainMenu([] {
if (ImGui::BeginMenu("View")) {
if (ImGui::MenuItem("Set Enter Key")) {
gSetEnterKey = true;
}
if (ImGui::MenuItem("Reset Time")) {
glass::ResetTime();
}
@@ -231,6 +236,57 @@ int main(int argc, char** argv) {
}
ImGui::EndPopup();
}
int& enterKey = glass::GetStorageRoot().GetInt("enterKey", GLFW_KEY_ENTER);
ImGuiIO& io = ImGui::GetIO();
io.KeyMap[ImGuiKey_Enter] = enterKey;
if (gSetEnterKey) {
ImGui::OpenPopup("Set Enter Key");
gSetEnterKey = false;
}
if (ImGui::BeginPopupModal("Set Enter Key")) {
ImGui::Text("Set the key to use to mean 'Enter'");
ImGui::Text("This is useful to edit values without the DS disabling");
ImGui::Separator();
if (gKeyEdit) {
for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); ++i) {
if (io.KeysDown[i]) {
// remove all other uses
enterKey = i;
gKeyEdit = false;
break;
}
}
}
ImGui::Text("Key:");
ImGui::SameLine();
char editLabel[40];
char nameBuf[32];
const char* name = glfwGetKeyName(enterKey, 0);
if (!name) {
std::snprintf(nameBuf, sizeof(nameBuf), "%d", enterKey);
name = nameBuf;
}
std::snprintf(editLabel, sizeof(editLabel), "%s###edit",
gKeyEdit ? "(press key)" : name);
if (ImGui::SmallButton(editLabel)) {
gKeyEdit = true;
}
ImGui::SameLine();
if (ImGui::SmallButton("Reset")) {
enterKey = GLFW_KEY_ENTER;
}
if (ImGui::Button("Close")) {
ImGui::CloseCurrentPopup();
gKeyEdit = false;
}
ImGui::EndPopup();
}
});
gui::Initialize("Glass - DISCONNECTED", 1024, 768);

View File

@@ -70,17 +70,17 @@ void glass::DisplayEncoder(EncoderModel* model) {
std::string& name = GetStorage().GetString("name");
char label[128];
if (!name.empty()) {
std::snprintf(label, sizeof(label), "%s [%d,%d]###name", name.c_str(), chA,
chB);
std::snprintf(label, sizeof(label), "%s [%d,%d]###header", name.c_str(),
chA, chB);
} else {
std::snprintf(label, sizeof(label), "Encoder[%d,%d]###name", chA, chB);
std::snprintf(label, sizeof(label), "Encoder[%d,%d]###header", chA, chB);
}
// header
bool open = CollapsingHeader(label);
// context menu to change name
if (PopupEditName("name", &name)) {
if (PopupEditName("header", &name)) {
model->SetName(name);
}

View File

@@ -46,15 +46,16 @@ bool glass::DisplayPCMSolenoids(PCMModel* model, int index,
std::string& name = GetStorage().GetString("name");
char label[128];
if (!name.empty()) {
std::snprintf(label, sizeof(label), "%s [%d]###name", name.c_str(), index);
std::snprintf(label, sizeof(label), "%s [%d]###header", name.c_str(),
index);
} else {
std::snprintf(label, sizeof(label), "PCM[%d]###name", index);
std::snprintf(label, sizeof(label), "PCM[%d]###header", index);
}
// header
bool open = CollapsingHeader(label);
PopupEditName("name", &name);
PopupEditName("header", &name);
ImGui::SetItemAllowOverlap();
ImGui::SameLine();

View File

@@ -53,11 +53,11 @@ bool glass::BeginDevice(const char* id, ImGuiTreeNodeFlags flags) {
// build label
std::string& name = GetStorage().GetString("name");
char label[128];
std::snprintf(label, sizeof(label), "%s###name",
std::snprintf(label, sizeof(label), "%s###header",
name.empty() ? id : name.c_str());
bool open = CollapsingHeader(label, flags);
PopupEditName("name", &name);
PopupEditName("header", &name);
if (!open) {
PopID();

View File

@@ -14,7 +14,7 @@ using namespace glass;
static const char* stations[] = {"Red 1", "Red 2", "Red 3",
"Blue 1", "Blue 2", "Blue 3"};
void glass::DisplayFMS(FMSModel* model, bool* matchTimeEnabled) {
void glass::DisplayFMS(FMSModel* model) {
if (!model->Exists() || model->IsReadOnly()) {
return DisplayFMSReadOnly(model);
}
@@ -49,10 +49,6 @@ void glass::DisplayFMS(FMSModel* model, bool* matchTimeEnabled) {
// Match Time
if (auto data = model->GetMatchTimeData()) {
if (matchTimeEnabled) {
ImGui::Checkbox("Match Time Enabled", matchTimeEnabled);
}
double val = data->GetValue();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
if (ImGui::InputDouble("Match Time", &val, 0, 0, "%.1f",
@@ -60,9 +56,17 @@ void glass::DisplayFMS(FMSModel* model, bool* matchTimeEnabled) {
model->SetMatchTime(val);
}
data->EmitDrag();
bool enabled = false;
if (auto enabledData = model->GetEnabledData()) {
enabled = enabledData->GetValue();
}
ImGui::SameLine();
if (ImGui::Button("Reset")) {
model->SetMatchTime(0.0);
if (ImGui::Button("Auto") && !enabled) {
model->SetMatchTime(15.0);
}
ImGui::SameLine();
if (ImGui::Button("Teleop") && !enabled) {
model->SetMatchTime(135.0);
}
}

View File

@@ -17,10 +17,15 @@
#include <fmt/format.h>
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
#include <imgui_stdlib.h>
#include <implot.h>
#include <implot_internal.h>
#include <wpi/Signal.h>
#include <wpi/SmallString.h>
#include <wpi/SmallVector.h>
@@ -36,6 +41,8 @@
using namespace glass;
static constexpr int kAxisCount = 3;
namespace {
class PlotView;
@@ -98,7 +105,7 @@ class PlotSeries {
int& m_digitalBitGap;
// value storage
static constexpr int kMaxSize = 2000;
static constexpr int kMaxSize = 20000;
static constexpr double kTimeGap = 0.05;
std::atomic<int> m_size = 0;
std::atomic<int> m_offset = 0;
@@ -129,6 +136,7 @@ class Plot {
private:
void EmitSettingsLimits(int axis);
void DragDropAccept(PlotView& view, size_t i, int yAxis);
bool m_paused = false;
@@ -137,13 +145,19 @@ class Plot {
bool& m_showPause;
bool& m_lockPrevX;
bool& m_legend;
bool& m_legendOutside;
bool& m_legendHorizontal;
int& m_legendLocation;
bool& m_crosshairs;
bool& m_antialiased;
bool& m_mousePosition;
bool& m_yAxis2;
bool& m_yAxis3;
float& m_viewTime;
bool& m_autoHeight;
int& m_height;
struct PlotRange {
explicit PlotRange(Storage& storage);
struct PlotAxis {
PlotAxis(Storage& storage, int num);
std::string& label;
double& min;
@@ -151,8 +165,15 @@ class Plot {
bool& lockMin;
bool& lockMax;
bool apply = false;
bool& autoFit;
bool& logScale;
bool& invert;
bool& opposite;
bool& gridLines;
bool& tickMarks;
bool& tickLabels;
};
std::vector<PlotRange> m_axis;
std::vector<PlotAxis> m_axis;
ImPlotRange m_xaxisRange; // read from plot, used for lockPrevX
};
@@ -178,7 +199,7 @@ class PlotView : public View {
PlotSeries::PlotSeries(Storage& storage, int yAxis)
: m_id{storage.GetString("id")},
m_name{storage.GetString("name")},
m_yAxis{storage.GetInt("yAxis", yAxis)},
m_yAxis{storage.GetInt("yAxis", 0)},
m_color{storage.GetFloatArray("color", kDefaultColor)},
m_marker{storage.GetString("marker"),
0,
@@ -188,7 +209,9 @@ PlotSeries::PlotSeries(Storage& storage, int yAxis)
m_digital{
storage.GetString("digital"), kAuto, {"Auto", "Digital", "Analog"}},
m_digitalBitHeight{storage.GetInt("digitalBitHeight", 8)},
m_digitalBitGap{storage.GetInt("digitalBitGap", 4)} {}
m_digitalBitGap{storage.GetInt("digitalBitGap", 4)} {
m_yAxis = yAxis;
}
PlotSeries::PlotSeries(Storage& storage, std::string_view id)
: PlotSeries{storage, 0} {
@@ -223,7 +246,7 @@ void PlotSeries::SetSource(DataSource* source) {
m_source = source;
// add initial value
m_data[m_size++] = ImPlotPoint{wpi::Now() * 1.0e-6, source->GetValue()};
AppendValue(source->GetValue(), 0);
m_newValueConn = source->valueChanged.connect_connection(
[this](double value, uint64_t time) { AppendValue(value, time); });
@@ -288,7 +311,8 @@ PlotSeries::Action PlotSeries::EmitPlot(PlotView& view, double now, size_t i,
CheckSource();
char label[128];
std::snprintf(label, sizeof(label), "%s###name", GetName());
std::snprintf(label, sizeof(label), "%s###name%d_%d", GetName(),
static_cast<int>(i), static_cast<int>(plotIndex));
int size = m_size;
int offset = m_offset;
@@ -330,7 +354,11 @@ PlotSeries::Action PlotSeries::EmitPlot(PlotView& view, double now, size_t i,
ImPlot::PopStyleVar();
ImPlot::PopStyleVar();
} else {
ImPlot::SetPlotYAxis(m_yAxis);
if (ImPlot::GetCurrentPlot()->YAxis(m_yAxis).Enabled) {
ImPlot::SetAxis(ImAxis_Y1 + m_yAxis);
} else {
ImPlot::SetAxis(ImAxis_Y1);
}
ImPlot::SetNextMarkerStyle(m_marker.GetValue() - 1);
ImPlot::PlotLineG(label, getter, &getterData, size + 1);
}
@@ -433,12 +461,19 @@ void PlotSeries::EmitSettings(size_t i) {
}
}
Plot::PlotRange::PlotRange(Storage& storage)
Plot::PlotAxis::PlotAxis(Storage& storage, int num)
: label{storage.GetString("label")},
min{storage.GetDouble("min", 0)},
max{storage.GetDouble("max", 1)},
lockMin{storage.GetBool("lockMin", false)},
lockMax{storage.GetBool("lockMax", false)} {}
lockMax{storage.GetBool("lockMax", false)},
autoFit{storage.GetBool("autoFit", false)},
logScale{storage.GetBool("logScale", false)},
invert{storage.GetBool("invert", false)},
opposite{storage.GetBool("opposite", num != 0)},
gridLines{storage.GetBool("gridLines", num == 0)},
tickMarks{storage.GetBool("tickMarks", true)},
tickLabels{storage.GetBool("tickLabels", true)} {}
Plot::Plot(Storage& storage)
: m_seriesStorage{storage.GetChildArray("series")},
@@ -447,18 +482,25 @@ Plot::Plot(Storage& storage)
m_showPause{storage.GetBool("showPause", true)},
m_lockPrevX{storage.GetBool("lockPrevX", false)},
m_legend{storage.GetBool("legend", true)},
m_legendOutside{storage.GetBool("legendOutside", false)},
m_legendHorizontal{storage.GetBool("legendHorizontal", false)},
m_legendLocation{
storage.GetInt("legendLocation", ImPlotLocation_NorthWest)},
m_crosshairs{storage.GetBool("crosshairs", false)},
m_antialiased{storage.GetBool("antialiased", false)},
m_mousePosition{storage.GetBool("mousePosition", true)},
m_yAxis2{storage.GetBool("yaxis2", false)},
m_yAxis3{storage.GetBool("yaxis3", false)},
m_viewTime{storage.GetFloat("viewTime", 10)},
m_autoHeight{storage.GetBool("autoHeight", true)},
m_height{storage.GetInt("height", 300)} {
auto& axesStorage = storage.GetChildArray("axis");
axesStorage.resize(3);
for (auto&& axisStorage : axesStorage) {
if (!axisStorage) {
axisStorage = std::make_unique<Storage>();
axesStorage.resize(kAxisCount);
for (int i = 0; i < kAxisCount; ++i) {
if (!axesStorage[i]) {
axesStorage[i] = std::make_unique<Storage>();
}
m_axis.emplace_back(*axisStorage);
m_axis.emplace_back(*axesStorage[i], i);
}
// loop over series
@@ -468,20 +510,7 @@ Plot::Plot(Storage& storage)
}
}
void Plot::DragDropTarget(PlotView& view, size_t i, bool inPlot) {
if (!ImGui::BeginDragDropTarget()) {
return;
}
// handle dragging onto a specific Y axis
int yAxis = -1;
if (inPlot) {
for (int y = 0; y < 3; ++y) {
if (ImPlot::IsPlotYAxisHovered(y)) {
yAxis = y;
break;
}
}
}
void Plot::DragDropAccept(PlotView& view, size_t i, int yAxis) {
if (const ImGuiPayload* payload =
ImGui::AcceptDragDropPayload("DataSource")) {
auto source = *static_cast<DataSource**>(payload->Data);
@@ -508,6 +537,26 @@ void Plot::DragDropTarget(PlotView& view, size_t i, bool inPlot) {
}
}
void Plot::DragDropTarget(PlotView& view, size_t i, bool inPlot) {
if (inPlot) {
if (ImPlot::BeginDragDropTargetPlot() ||
ImPlot::BeginDragDropTargetLegend()) {
DragDropAccept(view, i, -1);
ImPlot::EndDragDropTarget();
}
for (int y = 0; y < kAxisCount; ++y) {
if (ImPlot::GetCurrentPlot()->YAxis(y).Enabled &&
ImPlot::BeginDragDropTargetAxis(ImAxis_Y1 + y)) {
DragDropAccept(view, i, y);
ImPlot::EndDragDropTarget();
}
}
} else if (ImGui::BeginDragDropTarget()) {
DragDropAccept(view, i, -1);
ImGui::EndDragDropTarget();
}
}
void Plot::EmitPlot(PlotView& view, double now, bool paused, size_t i) {
if (!m_visible) {
return;
@@ -520,49 +569,63 @@ void Plot::EmitPlot(PlotView& view, double now, bool paused, size_t i) {
}
char label[128];
std::snprintf(label, sizeof(label), "%s##plot", m_name.c_str());
if (lockX) {
ImPlot::SetNextPlotLimitsX(view.m_plots[i - 1]->m_xaxisRange.Min,
view.m_plots[i - 1]->m_xaxisRange.Max,
ImGuiCond_Always);
} else {
// also force-pause plots if overall timing is paused
double zeroTime = GetZeroTime() * 1.0e-6;
ImPlot::SetNextPlotLimitsX(
now - zeroTime - m_viewTime, now - zeroTime,
(paused || m_paused) ? ImGuiCond_Once : ImGuiCond_Always);
}
ImPlotAxisFlags yFlags[3] = {ImPlotAxisFlags_None,
ImPlotAxisFlags_NoGridLines,
ImPlotAxisFlags_NoGridLines};
for (int i = 0; i < 3; ++i) {
ImPlot::SetNextPlotLimitsY(
m_axis[i].min, m_axis[i].max,
m_axis[i].apply ? ImGuiCond_Always : ImGuiCond_Once, i);
m_axis[i].apply = false;
if (m_axis[i].lockMin) {
yFlags[i] |= ImPlotAxisFlags_LockMin;
}
if (m_axis[i].lockMax) {
yFlags[i] |= ImPlotAxisFlags_LockMax;
}
}
std::snprintf(label, sizeof(label), "%s###plot%d", m_name.c_str(),
static_cast<int>(i));
ImPlotFlags plotFlags = (m_legend ? 0 : ImPlotFlags_NoLegend) |
(m_yAxis2 ? ImPlotFlags_YAxis2 : 0) |
(m_yAxis3 ? ImPlotFlags_YAxis3 : 0);
(m_crosshairs ? ImPlotFlags_Crosshairs : 0) |
(m_antialiased ? ImPlotFlags_AntiAliased : 0) |
(m_mousePosition ? 0 : ImPlotFlags_NoMouseText);
if (ImPlot::BeginPlot(label, ImVec2(-1, m_height), plotFlags)) {
// setup legend
if (m_legend) {
ImPlotLegendFlags legendFlags =
(m_legendOutside ? ImPlotLegendFlags_Outside : 0) |
(m_legendHorizontal ? ImPlotLegendFlags_Horizontal : 0);
ImPlot::SetupLegend(m_legendLocation, legendFlags);
}
// setup x axis
ImPlot::SetupAxis(ImAxis_X1, nullptr, ImPlotAxisFlags_NoMenus);
if (lockX) {
ImPlot::SetupAxisLimits(ImAxis_X1, view.m_plots[i - 1]->m_xaxisRange.Min,
view.m_plots[i - 1]->m_xaxisRange.Max,
ImGuiCond_Always);
} else {
// also force-pause plots if overall timing is paused
double zeroTime = GetZeroTime() * 1.0e-6;
ImPlot::SetupAxisLimits(
ImAxis_X1, now - zeroTime - m_viewTime, now - zeroTime,
(paused || m_paused) ? ImGuiCond_Once : ImGuiCond_Always);
}
// setup y axes
for (int i = 0; i < kAxisCount; ++i) {
if ((i == 1 && !m_yAxis2) || (i == 2 && !m_yAxis3)) {
continue;
}
ImPlotAxisFlags flags =
(m_axis[i].lockMin ? ImPlotAxisFlags_LockMin : 0) |
(m_axis[i].lockMax ? ImPlotAxisFlags_LockMax : 0) |
(m_axis[i].autoFit ? ImPlotAxisFlags_AutoFit : 0) |
(m_axis[i].logScale ? ImPlotAxisFlags_AutoFit : 0) |
(m_axis[i].invert ? ImPlotAxisFlags_Invert : 0) |
(m_axis[i].opposite ? ImPlotAxisFlags_Opposite : 0) |
(m_axis[i].gridLines ? 0 : ImPlotAxisFlags_NoGridLines) |
(m_axis[i].tickMarks ? 0 : ImPlotAxisFlags_NoTickMarks) |
(m_axis[i].tickLabels ? 0 : ImPlotAxisFlags_NoTickLabels);
ImPlot::SetupAxis(
ImAxis_Y1 + i,
m_axis[i].label.empty() ? nullptr : m_axis[i].label.c_str(), flags);
ImPlot::SetupAxisLimits(
ImAxis_Y1 + i, m_axis[i].min, m_axis[i].max,
m_axis[i].apply ? ImGuiCond_Always : ImGuiCond_Once);
m_axis[i].apply = false;
}
ImPlot::SetupFinish();
if (ImPlot::BeginPlot(
label, nullptr,
m_axis[0].label.empty() ? nullptr : m_axis[0].label.c_str(),
ImVec2(-1, m_height), plotFlags, ImPlotAxisFlags_None, yFlags[0],
yFlags[1], yFlags[2],
m_axis[1].label.empty() ? nullptr : m_axis[1].label.c_str(),
m_axis[2].label.empty() ? nullptr : m_axis[2].label.c_str())) {
for (size_t j = 0; j < m_series.size(); ++j) {
ImGui::PushID(j);
switch (m_series[j]->EmitPlot(view, now, j, i)) {
case PlotSeries::kMoveUp:
if (j > 0) {
@@ -583,11 +646,38 @@ void Plot::EmitPlot(PlotView& view, double now, bool paused, size_t i) {
default:
break;
}
ImGui::PopID();
}
DragDropTarget(view, i, true);
m_xaxisRange = ImPlot::GetPlotLimits().X;
ImPlotPlot* plot = ImPlot::GetCurrentPlot();
ImPlot::EndPlot();
// copy plot settings back to storage
m_legend = (plot->Flags & ImPlotFlags_NoLegend) == 0;
m_crosshairs = (plot->Flags & ImPlotFlags_Crosshairs) != 0;
m_antialiased = (plot->Flags & ImPlotFlags_AntiAliased) != 0;
m_legendOutside =
(plot->Items.Legend.Flags & ImPlotLegendFlags_Outside) != 0;
m_legendHorizontal =
(plot->Items.Legend.Flags & ImPlotLegendFlags_Horizontal) != 0;
m_legendLocation = plot->Items.Legend.Location;
for (int i = 0; i < kAxisCount; ++i) {
if ((i == 1 && !m_yAxis2) || (i == 2 && !m_yAxis3)) {
continue;
}
auto flags = plot->Axes[ImAxis_Y1 + i].Flags;
m_axis[i].lockMin = (flags & ImPlotAxisFlags_LockMin) != 0;
m_axis[i].lockMax = (flags & ImPlotAxisFlags_LockMax) != 0;
m_axis[i].autoFit = (flags & ImPlotAxisFlags_AutoFit) != 0;
m_axis[i].logScale = (flags & ImPlotAxisFlags_LogScale) != 0;
m_axis[i].invert = (flags & ImPlotAxisFlags_Invert) != 0;
m_axis[i].opposite = (flags & ImPlotAxisFlags_Opposite) != 0;
m_axis[i].gridLines = (flags & ImPlotAxisFlags_NoGridLines) == 0;
m_axis[i].tickMarks = (flags & ImPlotAxisFlags_NoTickMarks) == 0;
m_axis[i].tickLabels = (flags & ImPlotAxisFlags_NoTickLabels) == 0;
}
}
}
@@ -622,7 +712,6 @@ void Plot::EmitSettings(size_t i) {
ImGui::InputText("##editname", &m_name);
ImGui::Checkbox("Visible", &m_visible);
ImGui::Checkbox("Show Pause Button", &m_showPause);
ImGui::Checkbox("Show Legend", &m_legend);
if (i != 0) {
ImGui::Checkbox("Lock X-axis to previous plot", &m_lockPrevX);
}

View File

@@ -160,17 +160,17 @@ bool DeleteButton(ImGuiID id, const ImVec2& pos) {
bool HeaderDeleteButton(const char* label) {
ImGuiWindow* window = ImGui::GetCurrentWindow();
ImGuiContext& g = *GImGui;
ImGuiLastItemDataBackup last_item_backup;
ImGuiLastItemData last_item_backup = g.LastItemData;
ImGuiID id = window->GetID(label);
float button_size = g.FontSize;
float button_x = ImMax(window->DC.LastItemRect.Min.x,
window->DC.LastItemRect.Max.x -
g.Style.FramePadding.x * 2.0f - button_size);
float button_y = window->DC.LastItemRect.Min.y;
float button_x = ImMax(
g.LastItemData.Rect.Min.x,
g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
float button_y = g.LastItemData.Rect.Min.y;
bool rv = DeleteButton(
window->GetID(reinterpret_cast<void*>(static_cast<intptr_t>(id) + 1)),
ImVec2(button_x, button_y));
last_item_backup.Restore();
g.LastItemData = last_item_backup;
return rv;
}

View File

@@ -47,7 +47,7 @@ class FMSModel : public Model {
* @param matchTimeEnabled If not null, a checkbox is displayed for
* "enable match time" linked to this value
*/
void DisplayFMS(FMSModel* model, bool* matchTimeEnabled = nullptr);
void DisplayFMS(FMSModel* model);
void DisplayFMSReadOnly(FMSModel* model);
} // namespace glass

View File

@@ -16,7 +16,7 @@
namespace glass {
class NTSpeedControllerModel : public SpeedControllerModel {
public:
static constexpr const char* kType = "Speed Controller";
static constexpr const char* kType = "Motor Controller";
explicit NTSpeedControllerModel(std::string_view path);
NTSpeedControllerModel(NT_Inst instance, std::string_view path);

View File

@@ -1 +1,8 @@
org.gradle.jvmargs=-Xmx1g
# The --add-exports flags work around a bug with spotless and JDK 17
# https://github.com/diffplug/spotless/issues/834
org.gradle.jvmargs=-Xmx1g \
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

269
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

View File

@@ -28,6 +28,20 @@ public class ControlWord {
m_dsAttached = dsAttached;
}
/**
* Updates from an existing word.
*
* @param word word to update from
*/
public void update(ControlWord word) {
m_enabled = word.m_enabled;
m_autonomous = word.m_autonomous;
m_test = word.m_test;
m_emergencyStop = word.m_emergencyStop;
m_fmsAttached = word.m_fmsAttached;
m_dsAttached = word.m_dsAttached;
}
public boolean getEnabled() {
return m_enabled;
}

View File

@@ -196,8 +196,8 @@ public final class HAL extends JNIWrapper {
@SuppressWarnings("MissingJavadocMethod")
public static native boolean waitForDSDataTimeout(double timeout);
public static int kMaxJoystickAxes = 12;
public static int kMaxJoystickPOVs = 12;
public static final int kMaxJoystickAxes = 12;
public static final int kMaxJoystickPOVs = 12;
public static native short getJoystickAxes(byte joystickNum, float[] axesArray);

View File

@@ -0,0 +1,123 @@
// 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.hal;
public class PowerDistributionFaults {
@SuppressWarnings("MemberName")
public final boolean Channel0BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel1BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel2BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel3BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel4BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel5BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel6BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel7BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel8BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel9BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel10BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel11BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel12BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel13BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel14BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel15BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel16BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel17BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel18BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel19BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel20BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel21BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel22BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel23BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Brownout;
@SuppressWarnings("MemberName")
public final boolean CanWarning;
@SuppressWarnings("MemberName")
public final boolean HardwareFault;
/**
* Constructs from a bitfield.
*
* @param faults faults
*/
public PowerDistributionFaults(int faults) {
Channel0BreakerFault = (faults & 0x1) != 0;
Channel1BreakerFault = (faults & 0x2) != 0;
Channel2BreakerFault = (faults & 0x4) != 0;
Channel3BreakerFault = (faults & 0x8) != 0;
Channel4BreakerFault = (faults & 0x10) != 0;
Channel5BreakerFault = (faults & 0x20) != 0;
Channel6BreakerFault = (faults & 0x40) != 0;
Channel7BreakerFault = (faults & 0x80) != 0;
Channel8BreakerFault = (faults & 0x100) != 0;
Channel9BreakerFault = (faults & 0x200) != 0;
Channel10BreakerFault = (faults & 0x400) != 0;
Channel11BreakerFault = (faults & 0x800) != 0;
Channel12BreakerFault = (faults & 0x1000) != 0;
Channel13BreakerFault = (faults & 0x2000) != 0;
Channel14BreakerFault = (faults & 0x4000) != 0;
Channel15BreakerFault = (faults & 0x8000) != 0;
Channel16BreakerFault = (faults & 0x10000) != 0;
Channel17BreakerFault = (faults & 0x20000) != 0;
Channel18BreakerFault = (faults & 0x40000) != 0;
Channel19BreakerFault = (faults & 0x80000) != 0;
Channel20BreakerFault = (faults & 0x100000) != 0;
Channel21BreakerFault = (faults & 0x200000) != 0;
Channel22BreakerFault = (faults & 0x400000) != 0;
Channel23BreakerFault = (faults & 0x800000) != 0;
Brownout = (faults & 0x1000000) != 0;
CanWarning = (faults & 0x2000000) != 0;
HardwareFault = (faults & 0x4000000) != 0;
}
}

View File

@@ -56,4 +56,18 @@ public class PowerDistributionJNI extends JNIWrapper {
public static native boolean getSwitchableChannelNoError(int handle);
public static native void setSwitchableChannelNoError(int handle, boolean enabled);
public static native int getFaultsNative(int handle);
public static PowerDistributionFaults getFaults(int handle) {
return new PowerDistributionFaults(getFaultsNative(handle));
}
public static native int getStickyFaultsNative(int handle);
public static PowerDistributionStickyFaults getStickyFaults(int handle) {
return new PowerDistributionStickyFaults(getStickyFaultsNative(handle));
}
public static native PowerDistributionVersion getVersion(int handle);
}

View File

@@ -0,0 +1,127 @@
// 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.hal;
public class PowerDistributionStickyFaults {
@SuppressWarnings("MemberName")
public final boolean Channel0BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel1BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel2BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel3BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel4BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel5BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel6BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel7BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel8BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel9BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel10BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel11BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel12BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel13BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel14BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel15BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel16BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel17BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel18BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel19BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel20BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel21BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel22BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Channel23BreakerFault;
@SuppressWarnings("MemberName")
public final boolean Brownout;
@SuppressWarnings("MemberName")
public final boolean CanWarning;
@SuppressWarnings("MemberName")
public final boolean CanBusOff;
@SuppressWarnings("MemberName")
public final boolean HasReset;
/**
* Constructs from a bitfield.
*
* @param faults faults
*/
public PowerDistributionStickyFaults(int faults) {
Channel0BreakerFault = (faults & 0x1) != 0;
Channel1BreakerFault = (faults & 0x2) != 0;
Channel2BreakerFault = (faults & 0x4) != 0;
Channel3BreakerFault = (faults & 0x8) != 0;
Channel4BreakerFault = (faults & 0x10) != 0;
Channel5BreakerFault = (faults & 0x20) != 0;
Channel6BreakerFault = (faults & 0x40) != 0;
Channel7BreakerFault = (faults & 0x80) != 0;
Channel8BreakerFault = (faults & 0x100) != 0;
Channel9BreakerFault = (faults & 0x200) != 0;
Channel10BreakerFault = (faults & 0x400) != 0;
Channel11BreakerFault = (faults & 0x800) != 0;
Channel12BreakerFault = (faults & 0x1000) != 0;
Channel13BreakerFault = (faults & 0x2000) != 0;
Channel14BreakerFault = (faults & 0x4000) != 0;
Channel15BreakerFault = (faults & 0x8000) != 0;
Channel16BreakerFault = (faults & 0x10000) != 0;
Channel17BreakerFault = (faults & 0x20000) != 0;
Channel18BreakerFault = (faults & 0x40000) != 0;
Channel19BreakerFault = (faults & 0x80000) != 0;
Channel20BreakerFault = (faults & 0x100000) != 0;
Channel21BreakerFault = (faults & 0x200000) != 0;
Channel22BreakerFault = (faults & 0x400000) != 0;
Channel23BreakerFault = (faults & 0x800000) != 0;
Brownout = (faults & 0x1000000) != 0;
CanWarning = (faults & 0x2000000) != 0;
CanBusOff = (faults & 0x4000000) != 0;
HasReset = (faults & 0x8000000) != 0;
}
}

View File

@@ -0,0 +1,50 @@
// 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.hal;
public class PowerDistributionVersion {
@SuppressWarnings("MemberName")
public final int firmwareMajor;
@SuppressWarnings("MemberName")
public final int firmwareMinor;
@SuppressWarnings("MemberName")
public final int firmwareFix;
@SuppressWarnings("MemberName")
public final int hardwareMinor;
@SuppressWarnings("MemberName")
public final int hardwareMajor;
@SuppressWarnings("MemberName")
public final int uniqueId;
/**
* Constructs a power distribution version (Called from the HAL).
*
* @param firmwareMajor firmware major
* @param firmwareMinor firmware minor
* @param firmwareFix firmware fix
* @param hardwareMinor hardware minor
* @param hardwareMajor hardware major
* @param uniqueId unique id
*/
public PowerDistributionVersion(
int firmwareMajor,
int firmwareMinor,
int firmwareFix,
int hardwareMinor,
int hardwareMajor,
int uniqueId) {
this.firmwareMajor = firmwareMajor;
this.firmwareMinor = firmwareMinor;
this.firmwareFix = firmwareFix;
this.hardwareMinor = hardwareMinor;
this.hardwareMajor = hardwareMajor;
this.uniqueId = uniqueId;
}
}

View File

@@ -0,0 +1,104 @@
// 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.hal;
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHFaults {
@SuppressWarnings("MemberName")
public final boolean Channel0Fault;
@SuppressWarnings("MemberName")
public final boolean Channel1Fault;
@SuppressWarnings("MemberName")
public final boolean Channel2Fault;
@SuppressWarnings("MemberName")
public final boolean Channel3Fault;
@SuppressWarnings("MemberName")
public final boolean Channel4Fault;
@SuppressWarnings("MemberName")
public final boolean Channel5Fault;
@SuppressWarnings("MemberName")
public final boolean Channel6Fault;
@SuppressWarnings("MemberName")
public final boolean Channel7Fault;
@SuppressWarnings("MemberName")
public final boolean Channel8Fault;
@SuppressWarnings("MemberName")
public final boolean Channel9Fault;
@SuppressWarnings("MemberName")
public final boolean Channel10Fault;
@SuppressWarnings("MemberName")
public final boolean Channel11Fault;
@SuppressWarnings("MemberName")
public final boolean Channel12Fault;
@SuppressWarnings("MemberName")
public final boolean Channel13Fault;
@SuppressWarnings("MemberName")
public final boolean Channel14Fault;
@SuppressWarnings("MemberName")
public final boolean Channel15Fault;
@SuppressWarnings("MemberName")
public final boolean CompressorOverCurrent;
@SuppressWarnings("MemberName")
public final boolean CompressorOpen;
@SuppressWarnings("MemberName")
public final boolean SolenoidOverCurrent;
@SuppressWarnings("MemberName")
public final boolean Brownout;
@SuppressWarnings("MemberName")
public final boolean CanWarning;
@SuppressWarnings("MemberName")
public final boolean HardwareFault;
/**
* Called from HAL to construct.
*
* @param faults the fault bitfields
*/
public REVPHFaults(int faults) {
Channel0Fault = (faults & 0x1) != 0;
Channel1Fault = (faults & 0x2) != 0;
Channel2Fault = (faults & 0x4) != 0;
Channel3Fault = (faults & 0x8) != 0;
Channel4Fault = (faults & 0x10) != 0;
Channel5Fault = (faults & 0x20) != 0;
Channel6Fault = (faults & 0x40) != 0;
Channel7Fault = (faults & 0x80) != 0;
Channel8Fault = (faults & 0x100) != 0;
Channel9Fault = (faults & 0x200) != 0;
Channel10Fault = (faults & 0x400) != 0;
Channel11Fault = (faults & 0x800) != 0;
Channel12Fault = (faults & 0x1000) != 0;
Channel13Fault = (faults & 0x2000) != 0;
Channel14Fault = (faults & 0x4000) != 0;
Channel15Fault = (faults & 0x8000) != 0;
CompressorOverCurrent = (faults & 0x8000) != 0;
CompressorOpen = (faults & 0x10000) != 0;
SolenoidOverCurrent = (faults & 0x20000) != 0;
Brownout = (faults & 0x40000) != 0;
CanWarning = (faults & 0x80000) != 0;
HardwareFault = (faults & 0x100000) != 0;
}
}

View File

@@ -40,7 +40,7 @@ public class REVPHJNI extends JNIWrapper {
public static native boolean getPressureSwitch(int handle);
public static native double getAnalogPressure(int handle, int channel);
public static native double getAnalogVoltage(int handle, int channel);
public static native double getCompressorCurrent(int handle);
@@ -49,4 +49,28 @@ public class REVPHJNI extends JNIWrapper {
public static native void setSolenoids(int handle, int mask, int values);
public static native void fireOneShot(int handle, int index, int durMs);
public static native void clearStickyFaults(int handle);
public static native double getInputVoltage(int handle);
public static native double get5VVoltage(int handle);
public static native double getSolenoidCurrent(int handle);
public static native double getSolenoidVoltage(int handle);
public static native int getStickyFaultsNative(int handle);
public static REVPHStickyFaults getStickyFaults(int handle) {
return new REVPHStickyFaults(getStickyFaultsNative(handle));
}
public static native int getFaultsNative(int handle);
public static REVPHFaults getFaults(int handle) {
return new REVPHFaults(getFaultsNative(handle));
}
public static native REVPHVersion getVersion(int handle);
}

View File

@@ -0,0 +1,44 @@
// 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.hal;
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHStickyFaults {
@SuppressWarnings("MemberName")
public final boolean CompressorOverCurrent;
@SuppressWarnings("MemberName")
public final boolean CompressorOpen;
@SuppressWarnings("MemberName")
public final boolean SolenoidOverCurrent;
@SuppressWarnings("MemberName")
public final boolean Brownout;
@SuppressWarnings("MemberName")
public final boolean CanWarning;
@SuppressWarnings("MemberName")
public final boolean CanBusOff;
@SuppressWarnings("MemberName")
public final boolean HasReset;
/**
* Called from HAL.
*
* @param faults sticky fault bit mask
*/
public REVPHStickyFaults(int faults) {
CompressorOverCurrent = (faults & 0x1) != 0;
CompressorOpen = (faults & 0x2) != 0;
SolenoidOverCurrent = (faults & 0x4) != 0;
Brownout = (faults & 0x8) != 0;
CanWarning = (faults & 0x10) != 0;
CanBusOff = (faults & 0x20) != 0;
HasReset = (faults & 0x40) != 0;
}
}

View File

@@ -0,0 +1,51 @@
// 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.hal;
@SuppressWarnings("AbbreviationAsWordInName")
public class REVPHVersion {
@SuppressWarnings("MemberName")
public final int firmwareMajor;
@SuppressWarnings("MemberName")
public final int firmwareMinor;
@SuppressWarnings("MemberName")
public final int firmwareFix;
@SuppressWarnings("MemberName")
public final int hardwareMinor;
@SuppressWarnings("MemberName")
public final int hardwareMajor;
@SuppressWarnings("MemberName")
public final int uniqueId;
/**
* Constructs a revph version (Called from the HAL).
*
* @param firmwareMajor firmware major
* @param firmwareMinor firmware minor
* @param firmwareFix firmware fix
* @param hardwareMinor hardware minor
* @param hardwareMajor hardware major
* @param uniqueId unique id
*/
public REVPHVersion(
int firmwareMajor,
int firmwareMinor,
int firmwareFix,
int hardwareMinor,
int hardwareMajor,
int uniqueId) {
this.firmwareMajor = firmwareMajor;
this.firmwareMinor = firmwareMinor;
this.firmwareFix = firmwareFix;
this.hardwareMinor = hardwareMinor;
this.hardwareMajor = hardwareMajor;
this.uniqueId = uniqueId;
}
}

View File

@@ -14,10 +14,17 @@ public final class CANExceptionFactory {
static final int ERR_CANSessionMux_NotAllowed = -44088;
static final int ERR_CANSessionMux_NotInitialized = -44089;
@SuppressWarnings("MissingJavadocMethod")
public static void checkStatus(int status, int messageID)
throws CANInvalidBufferException, CANMessageNotAllowedException, CANNotInitializedException,
UncleanStatusException {
/**
* Checks the status of a CAN message with the given message ID.
*
* @param status The CAN status.
* @param messageID The CAN message ID.
* @throws CANInvalidBufferException if the buffer is invalid.
* @throws CANMessageNotAllowedException if the message isn't allowed.
* @throws CANNotInitializedException if the CAN bus isn't initialized.
* @throws UncleanStatusException if the status code passed in reports an error.
*/
public static void checkStatus(int status, int messageID) {
switch (status) {
case NIRioStatus.kRioStatusSuccess:
// Everything is ok... don't throw.

View File

@@ -335,8 +335,13 @@ HAL_Bool HAL_GetCTREPCMSolenoidVoltageFault(HAL_CTREPCMHandle handle,
void HAL_ClearAllCTREPCMStickyFaults(HAL_CTREPCMHandle handle,
int32_t* status) {
auto pcm = pcmHandles->Get(handle);
if (pcm == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
uint8_t controlData[] = {0, 0, 0, 0x80};
HAL_WriteCANPacket(handle, controlData, sizeof(controlData), Control2,
HAL_WriteCANPacket(pcm->canHandle, controlData, sizeof(controlData), Control2,
status);
}
@@ -393,7 +398,7 @@ void HAL_SetCTREPCMOneShotDuration(HAL_CTREPCMHandle handle, int32_t index,
(std::min)(static_cast<uint32_t>(durMs) / 10,
static_cast<uint32_t>(0xFF));
HAL_WriteCANPacketRepeating(pcm->canHandle, pcm->oneShot.sol10MsPerUnit, 8,
Control2, SendPeriod, status);
Control3, SendPeriod, status);
}
} // extern "C"

View File

@@ -110,10 +110,15 @@ static int32_t HAL_GetControlWordInternal(HAL_ControlWord* controlWord) {
static int32_t HAL_GetMatchInfoInternal(HAL_MatchInfo* info) {
MatchType_t matchType = MatchType_t::kMatchType_none;
info->gameSpecificMessageSize = sizeof(info->gameSpecificMessage);
int status = FRC_NetworkCommunication_getMatchInfo(
info->eventName, &matchType, &info->matchNumber, &info->replayNumber,
info->gameSpecificMessage, &info->gameSpecificMessageSize);
if (info->gameSpecificMessageSize > sizeof(info->gameSpecificMessage)) {
info->gameSpecificMessageSize = 0;
}
info->matchType = static_cast<HAL_MatchType>(matchType);
*(std::end(info->eventName) - 1) = '\0';

View File

@@ -54,6 +54,10 @@ void HAL_InitializeI2C(HAL_I2CPort port, int32_t* status) {
}
if (port == HAL_I2C_kOnboard) {
HAL_SendError(0, 0, 0,
"Onboard I2C port is subject to system lockups. See Known "
"Issues page for details",
"", "", true);
std::scoped_lock lock(digitalI2COnBoardMutex);
i2COnboardObjCount++;
if (i2COnboardObjCount > 1) {

View File

@@ -4,6 +4,7 @@
#include "hal/PowerDistribution.h"
#include <cstring>
#include <thread>
#include "CTREPDP.h"
@@ -55,7 +56,7 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
HAL_CleanPDP(pdpHandle);
}
*status = 0;
auto pdhHandle = HAL_REV_InitializePDH(1, allocationLocation, status);
auto pdhHandle = HAL_InitializeREVPDH(1, allocationLocation, status);
return static_cast<HAL_PowerDistributionHandle>(pdhHandle);
}
@@ -70,7 +71,7 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
moduleNumber = 1;
}
return static_cast<HAL_PowerDistributionHandle>(
HAL_REV_InitializePDH(moduleNumber, allocationLocation, status));
HAL_InitializeREVPDH(moduleNumber, allocationLocation, status));
}
}
@@ -80,7 +81,7 @@ void HAL_CleanPowerDistribution(HAL_PowerDistributionHandle handle) {
if (IsCtre(handle)) {
HAL_CleanPDP(handle);
} else {
HAL_REV_FreePDH(handle);
HAL_FreeREVPDH(handle);
}
}
@@ -89,7 +90,7 @@ int32_t HAL_GetPowerDistributionModuleNumber(HAL_PowerDistributionHandle handle,
if (IsCtre(handle)) {
return HAL_GetPDPModuleNumber(handle, status);
} else {
return HAL_REV_GetPDHModuleNumber(handle, status);
return HAL_GetREVPDHModuleNumber(handle, status);
}
}
@@ -98,7 +99,7 @@ HAL_Bool HAL_CheckPowerDistributionChannel(HAL_PowerDistributionHandle handle,
if (IsCtre(handle)) {
return HAL_CheckPDPChannel(channel);
} else {
return HAL_REV_CheckPDHChannelNumber(channel);
return HAL_CheckREVPDHChannelNumber(channel);
}
}
@@ -107,7 +108,7 @@ HAL_Bool HAL_CheckPowerDistributionModule(int32_t module,
if (type == HAL_PowerDistributionType::HAL_PowerDistributionType_kCTRE) {
return HAL_CheckPDPModule(module);
} else {
return HAL_REV_CheckPDHModuleNumber(module);
return HAL_CheckREVPDHModuleNumber(module);
}
}
@@ -142,7 +143,7 @@ double HAL_GetPowerDistributionVoltage(HAL_PowerDistributionHandle handle,
if (IsCtre(handle)) {
return HAL_GetPDPVoltage(handle, status);
} else {
return HAL_REV_GetPDHSupplyVoltage(handle, status);
return HAL_GetREVPDHVoltage(handle, status);
}
}
@@ -151,7 +152,7 @@ double HAL_GetPowerDistributionChannelCurrent(
if (IsCtre(handle)) {
return HAL_GetPDPChannelCurrent(handle, channel, status);
} else {
return HAL_REV_GetPDHChannelCurrent(handle, channel, status);
return HAL_GetREVPDHChannelCurrent(handle, channel, status);
}
}
@@ -171,7 +172,7 @@ void HAL_GetPowerDistributionAllChannelCurrents(
SetLastError(status, "Output array not large enough");
return;
}
return HAL_REV_GetPDHAllChannelCurrents(handle, currents, status);
return HAL_GetREVPDHAllChannelCurrents(handle, currents, status);
}
}
@@ -180,7 +181,7 @@ double HAL_GetPowerDistributionTotalCurrent(HAL_PowerDistributionHandle handle,
if (IsCtre(handle)) {
return HAL_GetPDPTotalCurrent(handle, status);
} else {
return HAL_REV_GetPDHTotalCurrent(handle, status);
return HAL_GetREVPDHTotalCurrent(handle, status);
}
}
@@ -218,7 +219,7 @@ void HAL_ClearPowerDistributionStickyFaults(HAL_PowerDistributionHandle handle,
if (IsCtre(handle)) {
HAL_ClearPDPStickyFaults(handle, status);
} else {
HAL_REV_ClearPDHFaults(handle, status);
HAL_ClearREVPDHStickyFaults(handle, status);
}
}
@@ -228,7 +229,7 @@ void HAL_SetPowerDistributionSwitchableChannel(
// No-op on CTRE
return;
} else {
HAL_REV_SetPDHSwitchableChannel(handle, enabled, status);
HAL_SetREVPDHSwitchableChannel(handle, enabled, status);
}
}
@@ -238,7 +239,37 @@ HAL_Bool HAL_GetPowerDistributionSwitchableChannel(
// No-op on CTRE
return false;
} else {
return HAL_REV_GetPDHSwitchableChannelState(handle, status);
return HAL_GetREVPDHSwitchableChannelState(handle, status);
}
}
void HAL_GetPowerDistributionVersion(HAL_PowerDistributionHandle handle,
HAL_PowerDistributionVersion* version,
int32_t* status) {
if (IsCtre(handle)) {
std::memset(version, 0, sizeof(*version));
} else {
HAL_GetREVPDHVersion(handle, version, status);
}
}
void HAL_GetPowerDistributionFaults(HAL_PowerDistributionHandle handle,
HAL_PowerDistributionFaults* faults,
int32_t* status) {
if (IsCtre(handle)) {
std::memset(faults, 0, sizeof(*faults));
} else {
HAL_GetREVPDHFaults(handle, faults, status);
}
}
void HAL_GetPowerDistributionStickyFaults(
HAL_PowerDistributionHandle handle,
HAL_PowerDistributionStickyFaults* stickyFaults, int32_t* status) {
if (IsCtre(handle)) {
std::memset(stickyFaults, 0, sizeof(*stickyFaults));
} else {
HAL_GetREVPDHStickyFaults(handle, stickyFaults, status);
}
}

View File

@@ -11,6 +11,7 @@
#include <hal/handles/IndexedHandleResource.h>
#include <cstring>
#include <thread>
#include <fmt/format.h>
@@ -35,6 +36,7 @@ struct REV_PDHObj {
int32_t controlPeriod;
HAL_CANHandle hcan;
std::string previousAllocation;
HAL_PowerDistributionVersion versionInfo;
};
} // namespace
@@ -43,32 +45,26 @@ static constexpr uint32_t APIFromExtId(uint32_t extId) {
return (extId >> 6) & 0x3FF;
}
static constexpr uint32_t PDH_SWITCH_CHANNEL_SET_FRAME_API =
APIFromExtId(PDH_SWITCH_CHANNEL_SET_FRAME_ID);
static constexpr uint32_t PDH_SET_SWITCH_CHANNEL_FRAME_API =
APIFromExtId(PDH_SET_SWITCH_CHANNEL_FRAME_ID);
static constexpr uint32_t PDH_STATUS0_FRAME_API =
APIFromExtId(PDH_STATUS0_FRAME_ID);
static constexpr uint32_t PDH_STATUS1_FRAME_API =
APIFromExtId(PDH_STATUS1_FRAME_ID);
static constexpr uint32_t PDH_STATUS2_FRAME_API =
APIFromExtId(PDH_STATUS2_FRAME_ID);
static constexpr uint32_t PDH_STATUS3_FRAME_API =
APIFromExtId(PDH_STATUS3_FRAME_ID);
static constexpr uint32_t PDH_STATUS4_FRAME_API =
APIFromExtId(PDH_STATUS4_FRAME_ID);
static constexpr uint32_t PDH_STATUS_0_FRAME_API =
APIFromExtId(PDH_STATUS_0_FRAME_ID);
static constexpr uint32_t PDH_STATUS_1_FRAME_API =
APIFromExtId(PDH_STATUS_1_FRAME_ID);
static constexpr uint32_t PDH_STATUS_2_FRAME_API =
APIFromExtId(PDH_STATUS_2_FRAME_ID);
static constexpr uint32_t PDH_STATUS_3_FRAME_API =
APIFromExtId(PDH_STATUS_3_FRAME_ID);
static constexpr uint32_t PDH_STATUS_4_FRAME_API =
APIFromExtId(PDH_STATUS_4_FRAME_ID);
static constexpr uint32_t PDH_CLEAR_FAULTS_FRAME_API =
APIFromExtId(PDH_CLEAR_FAULTS_FRAME_ID);
static constexpr uint32_t PDH_IDENTIFY_FRAME_API =
APIFromExtId(PDH_IDENTIFY_FRAME_ID);
static constexpr uint32_t PDH_VERSION_FRAME_API =
APIFromExtId(PDH_VERSION_FRAME_ID);
static constexpr uint32_t PDH_CONFIGURE_HR_CHANNEL_FRAME_API =
APIFromExtId(PDH_CONFIGURE_HR_CHANNEL_FRAME_ID);
static constexpr int32_t kPDHFrameStatus0Timeout = 20;
static constexpr int32_t kPDHFrameStatus1Timeout = 20;
static constexpr int32_t kPDHFrameStatus2Timeout = 20;
@@ -89,97 +85,97 @@ void InitializeREVPDH() {
extern "C" {
static PDH_status0_t HAL_REV_ReadPDHStatus0(HAL_CANHandle hcan,
static PDH_status_0_t HAL_ReadREVPDHStatus0(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_status0_t result = {};
PDH_status_0_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS0_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_0_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus0Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status0_unpack(&result, packedData, PDH_STATUS0_LENGTH);
PDH_status_0_unpack(&result, packedData, PDH_STATUS_0_LENGTH);
return result;
}
static PDH_status1_t HAL_REV_ReadPDHStatus1(HAL_CANHandle hcan,
static PDH_status_1_t HAL_ReadREVPDHStatus1(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_status1_t result = {};
PDH_status_1_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS1_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_1_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus1Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status1_unpack(&result, packedData, PDH_STATUS1_LENGTH);
PDH_status_1_unpack(&result, packedData, PDH_STATUS_1_LENGTH);
return result;
}
static PDH_status2_t HAL_REV_ReadPDHStatus2(HAL_CANHandle hcan,
static PDH_status_2_t HAL_ReadREVPDHStatus2(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_status2_t result = {};
PDH_status_2_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS2_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_2_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus2Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status2_unpack(&result, packedData, PDH_STATUS2_LENGTH);
PDH_status_2_unpack(&result, packedData, PDH_STATUS_2_LENGTH);
return result;
}
static PDH_status3_t HAL_REV_ReadPDHStatus3(HAL_CANHandle hcan,
static PDH_status_3_t HAL_ReadREVPDHStatus3(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_status3_t result = {};
PDH_status_3_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS3_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_3_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus3Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status3_unpack(&result, packedData, PDH_STATUS3_LENGTH);
PDH_status_3_unpack(&result, packedData, PDH_STATUS_3_LENGTH);
return result;
}
static PDH_status4_t HAL_REV_ReadPDHStatus4(HAL_CANHandle hcan,
static PDH_status_4_t HAL_ReadREVPDHStatus4(HAL_CANHandle hcan,
int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PDH_status4_t result = {};
PDH_status_4_t result = {};
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS4_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PDH_STATUS_4_FRAME_API, packedData, &length,
&timestamp, kPDHFrameStatus4Timeout * 2, status);
if (*status != 0) {
return result;
}
PDH_status4_unpack(&result, packedData, PDH_STATUS4_LENGTH);
PDH_status_4_unpack(&result, packedData, PDH_STATUS_4_LENGTH);
return result;
}
@@ -187,23 +183,23 @@ static PDH_status4_t HAL_REV_ReadPDHStatus4(HAL_CANHandle hcan,
/**
* Helper function for the individual getter functions for status 4
*/
PDH_status4_t HAL_REV_GetPDHStatus4(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = {};
PDH_status_4_t HAL_GetREVPDHStatus4(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status_4_t statusFrame = {};
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return statusFrame;
}
statusFrame = HAL_REV_ReadPDHStatus4(hpdh->hcan, status);
statusFrame = HAL_ReadREVPDHStatus4(hpdh->hcan, status);
return statusFrame;
}
HAL_REVPDHHandle HAL_REV_InitializePDH(int32_t module,
const char* allocationLocation,
int32_t* status) {
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t module,
const char* allocationLocation,
int32_t* status) {
hal::init::CheckInit();
if (!HAL_REV_CheckPDHModuleNumber(module)) {
if (!HAL_CheckREVPDHModuleNumber(module)) {
*status = RESOURCE_OUT_OF_RANGE;
return HAL_kInvalidHandle;
}
@@ -232,11 +228,12 @@ HAL_REVPDHHandle HAL_REV_InitializePDH(int32_t module,
hpdh->previousAllocation = allocationLocation ? allocationLocation : "";
hpdh->hcan = hcan;
hpdh->controlPeriod = kDefaultControlPeriod;
std::memset(&hpdh->versionInfo, 0, sizeof(hpdh->versionInfo));
return handle;
}
void HAL_REV_FreePDH(HAL_REVPDHHandle handle) {
void HAL_FreeREVPDH(HAL_REVPDHHandle handle) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
return;
@@ -247,27 +244,27 @@ void HAL_REV_FreePDH(HAL_REVPDHHandle handle) {
REVPDHHandles->Free(handle);
}
int32_t HAL_REV_GetPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status) {
int32_t HAL_GetREVPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status) {
return hal::getHandleIndex(handle);
}
HAL_Bool HAL_REV_CheckPDHModuleNumber(int32_t module) {
HAL_Bool HAL_CheckREVPDHModuleNumber(int32_t module) {
return ((module >= 1) && (module < kNumREVPDHModules)) ? 1 : 0;
}
HAL_Bool HAL_REV_CheckPDHChannelNumber(int32_t channel) {
HAL_Bool HAL_CheckREVPDHChannelNumber(int32_t channel) {
return ((channel >= 0) && (channel < kNumREVPDHChannels)) ? 1 : 0;
}
double HAL_REV_GetPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
int32_t* status) {
double HAL_GetREVPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
if (!HAL_REV_CheckPDHChannelNumber(channel)) {
if (!HAL_CheckREVPDHChannelNumber(channel)) {
*status = RESOURCE_OUT_OF_RANGE;
return 0;
}
@@ -275,174 +272,101 @@ double HAL_REV_GetPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
// Determine what periodic status the channel is in
if (channel < 6) {
// Periodic status 0
PDH_status0_t statusFrame = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
PDH_status_0_t statusFrame = HAL_ReadREVPDHStatus0(hpdh->hcan, status);
switch (channel) {
case 0:
return PDH_status0_channel_0_current_decode(
return PDH_status_0_channel_0_current_decode(
statusFrame.channel_0_current);
case 1:
return PDH_status0_channel_1_current_decode(
return PDH_status_0_channel_1_current_decode(
statusFrame.channel_1_current);
case 2:
return PDH_status0_channel_2_current_decode(
return PDH_status_0_channel_2_current_decode(
statusFrame.channel_2_current);
case 3:
return PDH_status0_channel_3_current_decode(
return PDH_status_0_channel_3_current_decode(
statusFrame.channel_3_current);
case 4:
return PDH_status0_channel_4_current_decode(
return PDH_status_0_channel_4_current_decode(
statusFrame.channel_4_current);
case 5:
return PDH_status0_channel_5_current_decode(
return PDH_status_0_channel_5_current_decode(
statusFrame.channel_5_current);
}
} else if (channel < 12) {
// Periodic status 1
PDH_status1_t statusFrame = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
PDH_status_1_t statusFrame = HAL_ReadREVPDHStatus1(hpdh->hcan, status);
switch (channel) {
case 6:
return PDH_status1_channel_6_current_decode(
return PDH_status_1_channel_6_current_decode(
statusFrame.channel_6_current);
case 7:
return PDH_status1_channel_7_current_decode(
return PDH_status_1_channel_7_current_decode(
statusFrame.channel_7_current);
case 8:
return PDH_status1_channel_8_current_decode(
return PDH_status_1_channel_8_current_decode(
statusFrame.channel_8_current);
case 9:
return PDH_status1_channel_9_current_decode(
return PDH_status_1_channel_9_current_decode(
statusFrame.channel_9_current);
case 10:
return PDH_status1_channel_10_current_decode(
return PDH_status_1_channel_10_current_decode(
statusFrame.channel_10_current);
case 11:
return PDH_status1_channel_11_current_decode(
return PDH_status_1_channel_11_current_decode(
statusFrame.channel_11_current);
}
} else if (channel < 18) {
// Periodic status 2
PDH_status2_t statusFrame = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
PDH_status_2_t statusFrame = HAL_ReadREVPDHStatus2(hpdh->hcan, status);
switch (channel) {
case 12:
return PDH_status2_channel_12_current_decode(
return PDH_status_2_channel_12_current_decode(
statusFrame.channel_12_current);
case 13:
return PDH_status2_channel_13_current_decode(
return PDH_status_2_channel_13_current_decode(
statusFrame.channel_13_current);
case 14:
return PDH_status2_channel_14_current_decode(
return PDH_status_2_channel_14_current_decode(
statusFrame.channel_14_current);
case 15:
return PDH_status2_channel_15_current_decode(
return PDH_status_2_channel_15_current_decode(
statusFrame.channel_15_current);
case 16:
return PDH_status2_channel_16_current_decode(
return PDH_status_2_channel_16_current_decode(
statusFrame.channel_16_current);
case 17:
return PDH_status2_channel_17_current_decode(
return PDH_status_2_channel_17_current_decode(
statusFrame.channel_17_current);
}
} else if (channel < 24) {
// Periodic status 3
PDH_status3_t statusFrame = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
PDH_status_3_t statusFrame = HAL_ReadREVPDHStatus3(hpdh->hcan, status);
switch (channel) {
case 18:
return PDH_status3_channel_18_current_decode(
return PDH_status_3_channel_18_current_decode(
statusFrame.channel_18_current);
case 19:
return PDH_status3_channel_19_current_decode(
return PDH_status_3_channel_19_current_decode(
statusFrame.channel_19_current);
case 20:
return PDH_status3_channel_20_current_decode(
return PDH_status_3_channel_20_current_decode(
statusFrame.channel_20_current);
case 21:
return PDH_status3_channel_21_current_decode(
return PDH_status_3_channel_21_current_decode(
statusFrame.channel_21_current);
case 22:
return PDH_status3_channel_22_current_decode(
return PDH_status_3_channel_22_current_decode(
statusFrame.channel_22_current);
case 23:
return PDH_status3_channel_23_current_decode(
return PDH_status_3_channel_23_current_decode(
statusFrame.channel_23_current);
}
}
return 0;
}
void HAL_REV_GetPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
PDH_status0_t statusFrame0 = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
PDH_status1_t statusFrame1 = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
PDH_status2_t statusFrame2 = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
PDH_status3_t statusFrame3 = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
currents[0] =
PDH_status0_channel_0_current_decode(statusFrame0.channel_0_current);
currents[1] =
PDH_status0_channel_1_current_decode(statusFrame0.channel_1_current);
currents[2] =
PDH_status0_channel_2_current_decode(statusFrame0.channel_2_current);
currents[3] =
PDH_status0_channel_3_current_decode(statusFrame0.channel_3_current);
currents[4] =
PDH_status0_channel_4_current_decode(statusFrame0.channel_4_current);
currents[5] =
PDH_status0_channel_5_current_decode(statusFrame0.channel_5_current);
currents[6] =
PDH_status1_channel_6_current_decode(statusFrame1.channel_6_current);
currents[7] =
PDH_status1_channel_7_current_decode(statusFrame1.channel_7_current);
currents[8] =
PDH_status1_channel_8_current_decode(statusFrame1.channel_8_current);
currents[9] =
PDH_status1_channel_9_current_decode(statusFrame1.channel_9_current);
currents[10] =
PDH_status1_channel_10_current_decode(statusFrame1.channel_10_current);
currents[11] =
PDH_status1_channel_11_current_decode(statusFrame1.channel_11_current);
currents[12] =
PDH_status2_channel_12_current_decode(statusFrame2.channel_12_current);
currents[13] =
PDH_status2_channel_13_current_decode(statusFrame2.channel_13_current);
currents[14] =
PDH_status2_channel_14_current_decode(statusFrame2.channel_14_current);
currents[15] =
PDH_status2_channel_15_current_decode(statusFrame2.channel_15_current);
currents[16] =
PDH_status2_channel_16_current_decode(statusFrame2.channel_16_current);
currents[17] =
PDH_status2_channel_17_current_decode(statusFrame2.channel_17_current);
currents[18] =
PDH_status3_channel_18_current_decode(statusFrame3.channel_18_current);
currents[19] =
PDH_status3_channel_19_current_decode(statusFrame3.channel_19_current);
currents[20] =
PDH_status3_channel_20_current_decode(statusFrame3.channel_20_current);
currents[21] =
PDH_status3_channel_21_current_decode(statusFrame3.channel_21_current);
currents[22] =
PDH_status3_channel_22_current_decode(statusFrame3.channel_22_current);
currents[23] =
PDH_status3_channel_23_current_decode(statusFrame3.channel_23_current);
}
uint16_t HAL_REV_GetPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0;
}
return PDH_status4_total_current_decode(statusFrame.total_current);
}
void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
void HAL_GetREVPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
@@ -450,291 +374,115 @@ void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
return;
}
uint8_t packedData[8] = {0};
PDH_switch_channel_set_t frame;
frame.output_set_value = enabled;
frame.use_system_enable = false;
PDH_switch_channel_set_pack(packedData, &frame, 1);
PDH_status_0_t statusFrame0 = HAL_ReadREVPDHStatus0(hpdh->hcan, status);
PDH_status_1_t statusFrame1 = HAL_ReadREVPDHStatus1(hpdh->hcan, status);
PDH_status_2_t statusFrame2 = HAL_ReadREVPDHStatus2(hpdh->hcan, status);
PDH_status_3_t statusFrame3 = HAL_ReadREVPDHStatus3(hpdh->hcan, status);
HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_SWITCH_CHANNEL_SET_LENGTH,
PDH_SWITCH_CHANNEL_SET_FRAME_API, status);
currents[0] =
PDH_status_0_channel_0_current_decode(statusFrame0.channel_0_current);
currents[1] =
PDH_status_0_channel_1_current_decode(statusFrame0.channel_1_current);
currents[2] =
PDH_status_0_channel_2_current_decode(statusFrame0.channel_2_current);
currents[3] =
PDH_status_0_channel_3_current_decode(statusFrame0.channel_3_current);
currents[4] =
PDH_status_0_channel_4_current_decode(statusFrame0.channel_4_current);
currents[5] =
PDH_status_0_channel_5_current_decode(statusFrame0.channel_5_current);
currents[6] =
PDH_status_1_channel_6_current_decode(statusFrame1.channel_6_current);
currents[7] =
PDH_status_1_channel_7_current_decode(statusFrame1.channel_7_current);
currents[8] =
PDH_status_1_channel_8_current_decode(statusFrame1.channel_8_current);
currents[9] =
PDH_status_1_channel_9_current_decode(statusFrame1.channel_9_current);
currents[10] =
PDH_status_1_channel_10_current_decode(statusFrame1.channel_10_current);
currents[11] =
PDH_status_1_channel_11_current_decode(statusFrame1.channel_11_current);
currents[12] =
PDH_status_2_channel_12_current_decode(statusFrame2.channel_12_current);
currents[13] =
PDH_status_2_channel_13_current_decode(statusFrame2.channel_13_current);
currents[14] =
PDH_status_2_channel_14_current_decode(statusFrame2.channel_14_current);
currents[15] =
PDH_status_2_channel_15_current_decode(statusFrame2.channel_15_current);
currents[16] =
PDH_status_2_channel_16_current_decode(statusFrame2.channel_16_current);
currents[17] =
PDH_status_2_channel_17_current_decode(statusFrame2.channel_17_current);
currents[18] =
PDH_status_3_channel_18_current_decode(statusFrame3.channel_18_current);
currents[19] =
PDH_status_3_channel_19_current_decode(statusFrame3.channel_19_current);
currents[20] =
PDH_status_3_channel_20_current_decode(statusFrame3.channel_20_current);
currents[21] =
PDH_status_3_channel_21_current_decode(statusFrame3.channel_21_current);
currents[22] =
PDH_status_3_channel_22_current_decode(statusFrame3.channel_22_current);
currents[23] =
PDH_status_3_channel_23_current_decode(statusFrame3.channel_23_current);
}
HAL_Bool HAL_REV_GetPDHSwitchableChannelState(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
uint16_t HAL_GetREVPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status_4_t statusFrame = HAL_GetREVPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
return 0;
}
return PDH_status4_sw_state_decode(statusFrame.sw_state);
return PDH_status_4_total_current_decode(statusFrame.total_current);
}
HAL_Bool HAL_REV_CheckPDHChannelBrownout(HAL_REVPDHHandle handle,
int32_t channel, int32_t* status) {
void HAL_SetREVPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
return;
}
if (!HAL_REV_CheckPDHChannelNumber(channel)) {
*status = RESOURCE_OUT_OF_RANGE;
return 0;
}
uint8_t packedData[8] = {0};
PDH_set_switch_channel_t frame;
frame.output_set_value = enabled;
PDH_set_switch_channel_pack(packedData, &frame,
PDH_SET_SWITCH_CHANNEL_LENGTH);
// Determine what periodic status the channel is in
if (channel < 4) {
// Periodic status 0
PDH_status0_t statusFrame = HAL_REV_ReadPDHStatus0(hpdh->hcan, status);
switch (channel) {
case 0:
return PDH_status0_channel_0_brownout_decode(
statusFrame.channel_0_brownout);
case 1:
return PDH_status0_channel_1_brownout_decode(
statusFrame.channel_1_brownout);
case 2:
return PDH_status0_channel_2_brownout_decode(
statusFrame.channel_2_brownout);
case 3:
return PDH_status0_channel_3_brownout_decode(
statusFrame.channel_3_brownout);
}
} else if (channel < 8) {
// Periodic status 1
PDH_status1_t statusFrame = HAL_REV_ReadPDHStatus1(hpdh->hcan, status);
switch (channel) {
case 4:
return PDH_status1_channel_4_brownout_decode(
statusFrame.channel_4_brownout);
case 5:
return PDH_status1_channel_5_brownout_decode(
statusFrame.channel_5_brownout);
case 6:
return PDH_status1_channel_6_brownout_decode(
statusFrame.channel_6_brownout);
case 7:
return PDH_status1_channel_7_brownout_decode(
statusFrame.channel_7_brownout);
}
} else if (channel < 12) {
// Periodic status 2
PDH_status2_t statusFrame = HAL_REV_ReadPDHStatus2(hpdh->hcan, status);
switch (channel) {
case 8:
return PDH_status2_channel_8_brownout_decode(
statusFrame.channel_8_brownout);
case 9:
return PDH_status2_channel_9_brownout_decode(
statusFrame.channel_9_brownout);
case 10:
return PDH_status2_channel_10_brownout_decode(
statusFrame.channel_10_brownout);
case 11:
return PDH_status2_channel_11_brownout_decode(
statusFrame.channel_11_brownout);
}
} else if (channel < 24) {
// Periodic status 3
PDH_status3_t statusFrame = HAL_REV_ReadPDHStatus3(hpdh->hcan, status);
switch (channel) {
case 12:
return PDH_status3_channel_12_brownout_decode(
statusFrame.channel_12_brownout);
case 13:
return PDH_status3_channel_13_brownout_decode(
statusFrame.channel_13_brownout);
case 14:
return PDH_status3_channel_14_brownout_decode(
statusFrame.channel_14_brownout);
case 15:
return PDH_status3_channel_15_brownout_decode(
statusFrame.channel_15_brownout);
case 16:
return PDH_status3_channel_16_brownout_decode(
statusFrame.channel_16_brownout);
case 17:
return PDH_status3_channel_17_brownout_decode(
statusFrame.channel_17_brownout);
case 18:
return PDH_status3_channel_18_brownout_decode(
statusFrame.channel_18_brownout);
case 19:
return PDH_status3_channel_19_brownout_decode(
statusFrame.channel_19_brownout);
case 20:
return PDH_status3_channel_20_brownout_decode(
statusFrame.channel_20_brownout);
case 21:
return PDH_status3_channel_21_brownout_decode(
statusFrame.channel_21_brownout);
case 22:
return PDH_status3_channel_22_brownout_decode(
statusFrame.channel_22_brownout);
case 23:
return PDH_status3_channel_23_brownout_decode(
statusFrame.channel_23_brownout);
}
}
return 0;
HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_SET_SWITCH_CHANNEL_LENGTH,
PDH_SET_SWITCH_CHANNEL_FRAME_API, status);
}
double HAL_REV_GetPDHSupplyVoltage(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_v_bus_decode(statusFrame.v_bus);
}
HAL_Bool HAL_REV_IsPDHEnabled(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return false;
}
return PDH_status4_system_enable_decode(statusFrame.system_enable);
}
HAL_Bool HAL_REV_CheckPDHBrownout(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return false;
}
return PDH_status4_brownout_decode(statusFrame.brownout);
}
HAL_Bool HAL_REV_CheckPDHCANWarning(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_can_warning_decode(statusFrame.can_warning);
}
HAL_Bool HAL_REV_CheckPDHHardwareFault(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_hardware_fault_decode(statusFrame.hardware_fault);
}
HAL_Bool HAL_REV_CheckPDHStickyBrownout(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_brownout_decode(statusFrame.sticky_brownout);
}
HAL_Bool HAL_REV_CheckPDHStickyCANWarning(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_can_warning_decode(statusFrame.sticky_can_warning);
}
HAL_Bool HAL_REV_CheckPDHStickyCANBusOff(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_can_bus_off_decode(statusFrame.sticky_can_bus_off);
}
HAL_Bool HAL_REV_CheckPDHStickyHardwareFault(HAL_REVPDHHandle handle,
HAL_Bool HAL_GetREVPDHSwitchableChannelState(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
PDH_status_4_t statusFrame = HAL_GetREVPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_hardware_fault_decode(
statusFrame.sticky_hardware_fault);
return PDH_status_4_switch_channel_state_decode(
statusFrame.switch_channel_state);
}
HAL_Bool HAL_REV_CheckPDHStickyFirmwareFault(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
double HAL_GetREVPDHVoltage(HAL_REVPDHHandle handle, int32_t* status) {
PDH_status_4_t statusFrame = HAL_GetREVPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_firmware_fault_decode(
statusFrame.sticky_firmware_fault);
return PDH_status_4_v_bus_decode(statusFrame.v_bus);
}
HAL_Bool HAL_REV_CheckPDHStickyChannelBrownout(HAL_REVPDHHandle handle,
int32_t channel,
int32_t* status) {
if (channel < 20 || channel > 23) {
*status = RESOURCE_OUT_OF_RANGE;
return 0.0;
}
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
switch (channel) {
case 20:
return PDH_status4_sticky_ch20_brownout_decode(
statusFrame.sticky_ch20_brownout);
case 21:
return PDH_status4_sticky_ch21_brownout_decode(
statusFrame.sticky_ch21_brownout);
case 22:
return PDH_status4_sticky_ch22_brownout_decode(
statusFrame.sticky_ch22_brownout);
case 23:
return PDH_status4_sticky_ch23_brownout_decode(
statusFrame.sticky_ch23_brownout);
}
return 0;
}
HAL_Bool HAL_REV_CheckPDHStickyHasReset(HAL_REVPDHHandle handle,
int32_t* status) {
PDH_status4_t statusFrame = HAL_REV_GetPDHStatus4(handle, status);
if (*status != 0) {
return 0.0;
}
return PDH_status4_sticky_has_reset_decode(statusFrame.sticky_has_reset);
}
REV_PDH_Version HAL_REV_GetPDHVersion(HAL_REVPDHHandle handle,
int32_t* status) {
REV_PDH_Version version;
std::memset(&version, 0, sizeof(version));
void HAL_GetREVPDHVersion(HAL_REVPDHHandle handle,
HAL_PowerDistributionVersion* version,
int32_t* status) {
std::memset(version, 0, sizeof(*version));
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
@@ -742,36 +490,141 @@ REV_PDH_Version HAL_REV_GetPDHVersion(HAL_REVPDHHandle handle,
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return version;
return;
}
if (hpdh->versionInfo.firmwareMajor > 0) {
version->firmwareMajor = hpdh->versionInfo.firmwareMajor;
version->firmwareMinor = hpdh->versionInfo.firmwareMinor;
version->firmwareFix = hpdh->versionInfo.firmwareFix;
version->hardwareMajor = hpdh->versionInfo.hardwareMajor;
version->hardwareMinor = hpdh->versionInfo.hardwareMinor;
version->uniqueId = hpdh->versionInfo.uniqueId;
*status = 0;
return;
}
HAL_WriteCANRTRFrame(hpdh->hcan, PDH_VERSION_LENGTH, PDH_VERSION_FRAME_API,
status);
if (*status != 0) {
return version;
return;
}
HAL_ReadCANPacketTimeout(hpdh->hcan, PDH_VERSION_FRAME_API, packedData,
&length, &timestamp, kDefaultControlPeriod * 2,
status);
uint32_t timeoutMs = 100;
for (uint32_t i = 0; i <= timeoutMs; i++) {
HAL_ReadCANPacketNew(hpdh->hcan, PDH_VERSION_FRAME_API, packedData, &length,
&timestamp, status);
if (*status == 0) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (*status != 0) {
return version;
return;
}
PDH_version_unpack(&result, packedData, PDH_VERSION_LENGTH);
version.firmwareMajor = result.firmware_year;
version.firmwareMinor = result.firmware_minor;
version.firmwareFix = result.firmware_fix;
version.hardwareRev = result.hardware_code;
version.uniqueId = result.unique_id;
version->firmwareMajor = result.firmware_year;
version->firmwareMinor = result.firmware_minor;
version->firmwareFix = result.firmware_fix;
version->hardwareMinor = result.hardware_minor;
version->hardwareMajor = result.hardware_major;
version->uniqueId = result.unique_id;
return version;
hpdh->versionInfo = *version;
}
void HAL_REV_ClearPDHFaults(HAL_REVPDHHandle handle, int32_t* status) {
void HAL_GetREVPDHFaults(HAL_REVPDHHandle handle,
HAL_PowerDistributionFaults* faults, int32_t* status) {
std::memset(faults, 0, sizeof(*faults));
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
PDH_status_0_t status0 = HAL_ReadREVPDHStatus0(hpdh->hcan, status);
PDH_status_1_t status1 = HAL_ReadREVPDHStatus1(hpdh->hcan, status);
PDH_status_2_t status2 = HAL_ReadREVPDHStatus2(hpdh->hcan, status);
PDH_status_3_t status3 = HAL_ReadREVPDHStatus3(hpdh->hcan, status);
PDH_status_4_t status4 = HAL_ReadREVPDHStatus4(hpdh->hcan, status);
faults->channel0BreakerFault = status0.channel_0_breaker_fault;
faults->channel1BreakerFault = status0.channel_1_breaker_fault;
faults->channel2BreakerFault = status0.channel_2_breaker_fault;
faults->channel3BreakerFault = status0.channel_3_breaker_fault;
faults->channel4BreakerFault = status1.channel_4_breaker_fault;
faults->channel5BreakerFault = status1.channel_5_breaker_fault;
faults->channel6BreakerFault = status1.channel_6_breaker_fault;
faults->channel7BreakerFault = status1.channel_7_breaker_fault;
faults->channel8BreakerFault = status2.channel_8_breaker_fault;
faults->channel9BreakerFault = status2.channel_9_breaker_fault;
faults->channel10BreakerFault = status2.channel_10_breaker_fault;
faults->channel11BreakerFault = status2.channel_11_breaker_fault;
faults->channel12BreakerFault = status3.channel_12_breaker_fault;
faults->channel13BreakerFault = status3.channel_13_breaker_fault;
faults->channel14BreakerFault = status3.channel_14_breaker_fault;
faults->channel15BreakerFault = status3.channel_15_breaker_fault;
faults->channel16BreakerFault = status3.channel_16_breaker_fault;
faults->channel17BreakerFault = status3.channel_17_breaker_fault;
faults->channel18BreakerFault = status3.channel_18_breaker_fault;
faults->channel19BreakerFault = status3.channel_19_breaker_fault;
faults->channel20BreakerFault = status3.channel_20_breaker_fault;
faults->channel21BreakerFault = status3.channel_21_breaker_fault;
faults->channel22BreakerFault = status3.channel_22_breaker_fault;
faults->channel23BreakerFault = status3.channel_23_breaker_fault;
faults->brownout = status4.brownout_fault;
faults->canWarning = status4.can_warning_fault;
faults->hardwareFault = status4.hardware_fault;
}
void HAL_GetREVPDHStickyFaults(HAL_REVPDHHandle handle,
HAL_PowerDistributionStickyFaults* stickyFaults,
int32_t* status) {
std::memset(stickyFaults, 0, sizeof(*stickyFaults));
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
PDH_status_4_t status4 = HAL_ReadREVPDHStatus4(hpdh->hcan, status);
stickyFaults->channel0BreakerFault = status4.sticky_ch0_breaker_fault;
stickyFaults->channel1BreakerFault = status4.sticky_ch1_breaker_fault;
stickyFaults->channel2BreakerFault = status4.sticky_ch2_breaker_fault;
stickyFaults->channel3BreakerFault = status4.sticky_ch3_breaker_fault;
stickyFaults->channel4BreakerFault = status4.sticky_ch4_breaker_fault;
stickyFaults->channel5BreakerFault = status4.sticky_ch5_breaker_fault;
stickyFaults->channel6BreakerFault = status4.sticky_ch6_breaker_fault;
stickyFaults->channel7BreakerFault = status4.sticky_ch7_breaker_fault;
stickyFaults->channel8BreakerFault = status4.sticky_ch8_breaker_fault;
stickyFaults->channel9BreakerFault = status4.sticky_ch9_breaker_fault;
stickyFaults->channel10BreakerFault = status4.sticky_ch10_breaker_fault;
stickyFaults->channel11BreakerFault = status4.sticky_ch11_breaker_fault;
stickyFaults->channel12BreakerFault = status4.sticky_ch12_breaker_fault;
stickyFaults->channel13BreakerFault = status4.sticky_ch13_breaker_fault;
stickyFaults->channel14BreakerFault = status4.sticky_ch14_breaker_fault;
stickyFaults->channel15BreakerFault = status4.sticky_ch15_breaker_fault;
stickyFaults->channel16BreakerFault = status4.sticky_ch16_breaker_fault;
stickyFaults->channel17BreakerFault = status4.sticky_ch17_breaker_fault;
stickyFaults->channel18BreakerFault = status4.sticky_ch18_breaker_fault;
stickyFaults->channel19BreakerFault = status4.sticky_ch19_breaker_fault;
stickyFaults->channel20BreakerFault = status4.sticky_ch20_breaker_fault;
stickyFaults->channel21BreakerFault = status4.sticky_ch21_breaker_fault;
stickyFaults->channel22BreakerFault = status4.sticky_ch22_breaker_fault;
stickyFaults->channel23BreakerFault = status4.sticky_ch23_breaker_fault;
stickyFaults->brownout = status4.sticky_brownout_fault;
stickyFaults->canWarning = status4.sticky_can_warning_fault;
stickyFaults->canBusOff = status4.sticky_can_bus_off_fault;
stickyFaults->hasReset = status4.sticky_has_reset_fault;
}
void HAL_ClearREVPDHStickyFaults(HAL_REVPDHHandle handle, int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
@@ -783,16 +636,4 @@ void HAL_REV_ClearPDHFaults(HAL_REVPDHHandle handle, int32_t* status) {
PDH_CLEAR_FAULTS_FRAME_API, status);
}
void HAL_REV_IdentifyPDH(HAL_REVPDHHandle handle, int32_t* status) {
auto hpdh = REVPDHHandles->Get(handle);
if (hpdh == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
uint8_t packedData[8] = {0};
HAL_WriteCANPacket(hpdh->hcan, packedData, PDH_IDENTIFY_LENGTH,
PDH_IDENTIFY_FRAME_API, status);
}
} // extern "C"

View File

@@ -6,6 +6,7 @@
#include <stdint.h>
#include "hal/PowerDistribution.h"
#include "hal/Types.h"
/**
@@ -14,14 +15,6 @@
* @{
*/
struct REV_PDH_Version {
uint32_t firmwareMajor;
uint32_t firmwareMinor;
uint32_t firmwareFix;
uint32_t hardwareRev;
uint32_t uniqueId;
};
#ifdef __cplusplus
extern "C" {
#endif
@@ -32,21 +25,21 @@ extern "C" {
* @param module the device CAN ID (1 .. 63)
* @return the created PDH handle
*/
HAL_REVPDHHandle HAL_REV_InitializePDH(int32_t module,
const char* allocationLocation,
int32_t* status);
HAL_REVPDHHandle HAL_InitializeREVPDH(int32_t module,
const char* allocationLocation,
int32_t* status);
/**
* Frees a PDH device handle.
*
* @param handle the previously created PDH handle
*/
void HAL_REV_FreePDH(HAL_REVPDHHandle handle);
void HAL_FreeREVPDH(HAL_REVPDHHandle handle);
/**
* Gets the module number for a pdh.
*/
int32_t HAL_REV_GetPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status);
int32_t HAL_GetREVPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status);
/**
* Checks if a PDH module number is valid.
@@ -56,34 +49,34 @@ int32_t HAL_REV_GetPDHModuleNumber(HAL_REVPDHHandle handle, int32_t* status);
* @param module module number (1 .. 63)
* @return 1 if the module number is valid; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHModuleNumber(int32_t module);
HAL_Bool HAL_CheckREVPDHModuleNumber(int32_t module);
/**
* Checks if a PDH channel number is valid.
*
* @param module channel number (0 .. HAL_REV_PDH_NUM_CHANNELS)
* @param module channel number (0 .. kNumREVPDHChannels)
* @return 1 if the channel number is valid; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHChannelNumber(int32_t channel);
HAL_Bool HAL_CheckREVPDHChannelNumber(int32_t channel);
/**
* Gets the current of a PDH channel in Amps.
*
* @param handle PDH handle
* @param channel the channel to retrieve the current of (0 ..
* HAL_REV_PDH_NUM_CHANNELS)
* kNumREVPDHChannels)
*
* @return the current of the PDH channel in Amps
*/
double HAL_REV_GetPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
int32_t* status);
double HAL_GetREVPDHChannelCurrent(HAL_REVPDHHandle handle, int32_t channel,
int32_t* status);
/**
* @param handle PDH handle
* @param currents array of currents
*/
void HAL_REV_GetPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
int32_t* status);
void HAL_GetREVPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
int32_t* status);
/**
* Gets the total current of the PDH in Amps, measured to the nearest even
@@ -93,7 +86,7 @@ void HAL_REV_GetPDHAllChannelCurrents(HAL_REVPDHHandle handle, double* currents,
*
* @return the total current of the PDH in Amps
*/
uint16_t HAL_REV_GetPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status);
uint16_t HAL_GetREVPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status);
/**
* Sets the state of the switchable channel on a PDH device.
@@ -102,8 +95,8 @@ uint16_t HAL_REV_GetPDHTotalCurrent(HAL_REVPDHHandle handle, int32_t* status);
* @param enabled 1 if the switchable channel should be enabled; 0
* otherwise
*/
void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
int32_t* status);
void HAL_SetREVPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
int32_t* status);
/**
* Gets the current state of the switchable channel on a PDH device.
@@ -114,174 +107,9 @@ void HAL_REV_SetPDHSwitchableChannel(HAL_REVPDHHandle handle, HAL_Bool enabled,
* @param handle PDH handle
* @return 1 if the switchable channel is enabled; 0 otherwise
*/
HAL_Bool HAL_REV_GetPDHSwitchableChannelState(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if a PDH channel is currently experiencing a brownout condition.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
* @param channel the channel to retrieve the brownout status of
*
* @return 1 if the channel is experiencing a brownout; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHChannelBrownout(HAL_REVPDHHandle handle,
int32_t channel, int32_t* status);
/**
* Gets the voltage being supplied to a PDH device.
*
* @param handle PDH handle
*
* @return the voltage at the input of the PDH in Volts
*/
double HAL_REV_GetPDHSupplyVoltage(HAL_REVPDHHandle handle, int32_t* status);
/**
* Checks if a PDH device is currently enabled.
*
* @param handle PDH handle
*
* @return 1 if the PDH is enabled; 0 otherwise
*/
HAL_Bool HAL_REV_IsPDHEnabled(HAL_REVPDHHandle handle, int32_t* status);
/**
* Checks if the input voltage on a PDH device is currently below the minimum
* voltage.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the PDH is experiencing a brownout; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHBrownout(HAL_REVPDHHandle handle, int32_t* status);
/**
* Checks if the CAN RX or TX error levels on a PDH device have exceeded the
* warning threshold.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has exceeded the warning threshold; 0
* otherwise
*/
HAL_Bool HAL_REV_CheckPDHCANWarning(HAL_REVPDHHandle handle, int32_t* status);
/**
* Checks if a PDH device is currently malfunctioning.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device is in a hardware fault state; 0
* otherwise
*/
HAL_Bool HAL_REV_CheckPDHHardwareFault(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if the input voltage on a PDH device has gone below the specified
* minimum voltage.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has had a brownout; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyBrownout(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if the CAN RX or TX error levels on a PDH device have exceeded the
* warning threshold.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has exceeded the CAN warning threshold;
* 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyCANWarning(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if the CAN bus on a PDH device has previously experienced a 'Bus Off'
* event.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has experienced a 'Bus Off' event; 0
* otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyCANBusOff(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if a PDH device has malfunctioned.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has had a malfunction; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyHardwareFault(HAL_REVPDHHandle handle,
HAL_Bool HAL_GetREVPDHSwitchableChannelState(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if the firmware on a PDH device has malfunctioned and reset during
* operation.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has had a malfunction and reset; 0
* otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyFirmwareFault(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Checks if a brownout has happened on channels 20-23 of a PDH device while it
* was enabled.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
* @param channel PDH channel to retrieve sticky brownout status (20 ..
* 23)
*
*
* @return 1 if the channel has had a brownout; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyChannelBrownout(HAL_REVPDHHandle handle,
int32_t channel,
int32_t* status);
/**
* Checks if a PDH device has reset.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*
* @return 1 if the device has reset; 0 otherwise
*/
HAL_Bool HAL_REV_CheckPDHStickyHasReset(HAL_REVPDHHandle handle,
int32_t* status);
/**
* Gets the firmware and hardware versions of a PDH device.
*
@@ -289,25 +117,46 @@ HAL_Bool HAL_REV_CheckPDHStickyHasReset(HAL_REVPDHHandle handle,
*
* @return version information
*/
REV_PDH_Version HAL_REV_GetPDHVersion(HAL_REVPDHHandle handle, int32_t* status);
void HAL_GetREVPDHVersion(HAL_REVPDHHandle handle,
HAL_PowerDistributionVersion* version,
int32_t* status);
/**
* Gets the voltage being supplied to a PDH device.
*
* @param handle PDH handle
*
* @return the voltage at the input of the PDH in Volts
*/
double HAL_GetREVPDHVoltage(HAL_REVPDHHandle handle, int32_t* status);
/**
* Gets the faults of a PDH device.
*
* @param handle PDH handle
*
* @return the faults of the PDH
*/
void HAL_GetREVPDHFaults(HAL_REVPDHHandle handle,
HAL_PowerDistributionFaults* faults, int32_t* status);
/**
* Gets the sticky faults of a PDH device.
*
* @param handle PDH handle
*
* @return the sticky faults of the PDH
*/
void HAL_GetREVPDHStickyFaults(HAL_REVPDHHandle handle,
HAL_PowerDistributionStickyFaults* stickyFaults,
int32_t* status);
/**
* Clears the sticky faults on a PDH device.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*/
void HAL_REV_ClearPDHFaults(HAL_REVPDHHandle handle, int32_t* status);
/**
* Identifies a PDH device by blinking its LED.
*
* NOTE: Not implemented in firmware as of 2021-04-23.
*
* @param handle PDH handle
*/
void HAL_REV_IdentifyPDH(HAL_REVPDHHandle handle, int32_t* status);
void HAL_ClearREVPDHStickyFaults(HAL_REVPDHHandle handle, int32_t* status);
#ifdef __cplusplus
} // extern "C"

View File

@@ -4,6 +4,8 @@
#include "hal/REVPH.h"
#include <thread>
#include <fmt/format.h>
#include "HALInitializer.h"
@@ -23,30 +25,34 @@ static constexpr HAL_CANDeviceType deviceType =
HAL_CANDeviceType::HAL_CAN_Dev_kPneumatics;
static constexpr int32_t kDefaultControlPeriod = 20;
// static constexpr uint8_t kDefaultSensorMask = (1 <<
// HAL_REV_PHSENSOR_DIGITAL);
static constexpr uint8_t kDefaultCompressorDuty = 255;
static constexpr uint8_t kDefaultPressureTarget = 120;
static constexpr uint8_t kDefaultPressureHysteresis = 60;
#define HAL_REV_MAX_PULSE_TIME 65534
#define HAL_REV_MAX_PRESSURE_TARGET 120
#define HAL_REV_MAX_PRESSURE_HYSTERESIS HAL_REV_MAX_PRESSURE_TARGET
#define HAL_REVPH_MAX_PULSE_TIME 65534
static constexpr uint32_t APIFromExtId(uint32_t extId) {
return (extId >> 6) & 0x3FF;
}
static constexpr uint32_t PH_STATUS_0_FRAME_API =
APIFromExtId(PH_STATUS_0_FRAME_ID);
static constexpr uint32_t PH_STATUS_1_FRAME_API =
APIFromExtId(PH_STATUS_1_FRAME_ID);
static constexpr uint32_t PH_SET_ALL_FRAME_API =
APIFromExtId(PH_SET_ALL_FRAME_ID);
static constexpr uint32_t PH_PULSE_ONCE_FRAME_API =
APIFromExtId(PH_PULSE_ONCE_FRAME_ID);
static constexpr uint32_t PH_COMPRESSOR_CONFIG_API =
APIFromExtId(PH_COMPRESSOR_CONFIG_FRAME_ID);
static constexpr uint32_t PH_STATUS0_FRAME_API =
APIFromExtId(PH_STATUS0_FRAME_ID);
static constexpr uint32_t PH_STATUS1_FRAME_API =
APIFromExtId(PH_STATUS1_FRAME_ID);
static constexpr uint32_t PH_CLEAR_FAULTS_FRAME_API =
APIFromExtId(PH_CLEAR_FAULTS_FRAME_ID);
static constexpr uint32_t PH_VERSION_FRAME_API =
APIFromExtId(PH_VERSION_FRAME_ID);
static constexpr int32_t kPHFrameStatus0Timeout = 50;
static constexpr int32_t kPHFrameStatus1Timeout = 50;
@@ -59,6 +65,7 @@ struct REV_PHObj {
wpi::mutex solenoidLock;
HAL_CANHandle hcan;
std::string previousAllocation;
HAL_REVPHVersion versionInfo;
};
} // namespace
@@ -75,38 +82,38 @@ void InitializeREVPH() {
}
} // namespace hal::init
static PH_status0_t HAL_REV_ReadPHStatus0(HAL_CANHandle hcan, int32_t* status) {
static PH_status_0_t HAL_ReadREVPHStatus0(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_status0_t result = {};
PH_status_0_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS0_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_0_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus0Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status0_unpack(&result, packedData, PH_STATUS0_LENGTH);
PH_status_0_unpack(&result, packedData, PH_STATUS_0_LENGTH);
return result;
}
static PH_status1_t HAL_REV_ReadPHStatus1(HAL_CANHandle hcan, int32_t* status) {
static PH_status_1_t HAL_ReadREVPHStatus1(HAL_CANHandle hcan, int32_t* status) {
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_status1_t result = {};
PH_status_1_t result = {};
HAL_ReadCANPacketTimeout(hcan, PH_STATUS1_FRAME_API, packedData, &length,
HAL_ReadCANPacketTimeout(hcan, PH_STATUS_1_FRAME_API, packedData, &length,
&timestamp, kPHFrameStatus1Timeout * 2, status);
if (*status != 0) {
return result;
}
PH_status1_unpack(&result, packedData, PH_STATUS1_LENGTH);
PH_status_1_unpack(&result, packedData, PH_STATUS_1_LENGTH);
return result;
}
@@ -117,9 +124,9 @@ enum REV_SolenoidState {
kSolenoidControlledViaPulse
};
static void HAL_REV_UpdateDesiredPHSolenoidState(REV_PHObj* hph,
int32_t solenoid,
REV_SolenoidState state) {
static void HAL_UpdateDesiredREVPHSolenoidState(REV_PHObj* hph,
int32_t solenoid,
REV_SolenoidState state) {
switch (solenoid) {
case 0:
hph->desiredSolenoidsState.channel_0 = state;
@@ -172,15 +179,15 @@ static void HAL_REV_UpdateDesiredPHSolenoidState(REV_PHObj* hph,
}
}
static void HAL_REV_SendSolenoidsState(REV_PHObj* hph, int32_t* status) {
static void HAL_SendREVPHSolenoidsState(REV_PHObj* hph, int32_t* status) {
uint8_t packedData[PH_SET_ALL_LENGTH] = {0};
PH_set_all_pack(packedData, &(hph->desiredSolenoidsState), PH_SET_ALL_LENGTH);
HAL_WriteCANPacketRepeating(hph->hcan, packedData, PH_SET_ALL_LENGTH,
PH_SET_ALL_FRAME_API, hph->controlPeriod, status);
}
static HAL_Bool HAL_REV_CheckPHPulseTime(int32_t time) {
return ((time > 0) && (time <= HAL_REV_MAX_PULSE_TIME)) ? 1 : 0;
static HAL_Bool HAL_CheckREVPHPulseTime(int32_t time) {
return ((time > 0) && (time <= HAL_REVPH_MAX_PULSE_TIME)) ? 1 : 0;
}
HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
@@ -217,9 +224,12 @@ HAL_REVPHHandle HAL_InitializeREVPH(int32_t module,
hph->previousAllocation = allocationLocation ? allocationLocation : "";
hph->hcan = hcan;
hph->controlPeriod = kDefaultControlPeriod;
std::memset(&hph->desiredSolenoidsState, 0,
sizeof(hph->desiredSolenoidsState));
std::memset(&hph->versionInfo, 0, sizeof(hph->versionInfo));
// Start closed-loop compressor control by starting solenoid state updates
HAL_REV_SendSolenoidsState(hph.get(), status);
HAL_SendREVPHSolenoidsState(hph.get(), status);
return handle;
}
@@ -249,7 +259,7 @@ HAL_Bool HAL_GetREVPHCompressor(HAL_REVPHHandle handle, int32_t* status) {
return false;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
if (*status != 0) {
return false;
@@ -331,7 +341,7 @@ HAL_REVPHCompressorConfigType HAL_GetREVPHCompressorConfig(
return HAL_REVPHCompressorConfigType_kDisabled;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
if (*status != 0) {
return HAL_REVPHCompressorConfigType_kDisabled;
@@ -347,7 +357,7 @@ HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status) {
return false;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
if (*status != 0) {
return false;
@@ -363,17 +373,17 @@ double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status) {
return 0;
}
PH_status1_t status1 = HAL_REV_ReadPHStatus1(ph->hcan, status);
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status1_compressor_current_decode(status1.compressor_current);
return PH_status_1_compressor_current_decode(status1.compressor_current);
}
double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
int32_t* status) {
double HAL_GetREVPHAnalogVoltage(HAL_REVPHHandle handle, int32_t channel,
int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
@@ -387,16 +397,138 @@ double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
return 0;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
if (*status != 0) {
return 0;
}
if (channel == 0) {
return PH_status0_analog_0_decode(status0.analog_0);
return PH_status_0_analog_0_decode(status0.analog_0);
}
return PH_status0_analog_1_decode(status0.analog_1);
return PH_status_0_analog_1_decode(status0.analog_1);
}
double HAL_GetREVPHVoltage(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status_1_v_bus_decode(status1.v_bus);
}
double HAL_GetREVPH5VVoltage(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status_1_supply_voltage_5_v_decode(status1.supply_voltage_5_v);
}
double HAL_GetREVPHSolenoidCurrent(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status_1_solenoid_current_decode(status1.solenoid_current);
}
double HAL_GetREVPHSolenoidVoltage(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return 0;
}
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
if (*status != 0) {
return 0;
}
return PH_status_1_solenoid_voltage_decode(status1.solenoid_voltage);
}
void HAL_GetREVPHVersion(HAL_REVPHHandle handle, HAL_REVPHVersion* version,
int32_t* status) {
std::memset(version, 0, sizeof(*version));
uint8_t packedData[8] = {0};
int32_t length = 0;
uint64_t timestamp = 0;
PH_version_t result = {};
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
if (ph->versionInfo.firmwareMajor > 0) {
version->firmwareMajor = ph->versionInfo.firmwareMajor;
version->firmwareMinor = ph->versionInfo.firmwareMinor;
version->firmwareFix = ph->versionInfo.firmwareFix;
version->hardwareMajor = ph->versionInfo.hardwareMajor;
version->hardwareMinor = ph->versionInfo.hardwareMinor;
version->uniqueId = ph->versionInfo.uniqueId;
*status = 0;
return;
}
HAL_WriteCANRTRFrame(ph->hcan, PH_VERSION_LENGTH, PH_VERSION_FRAME_API,
status);
if (*status != 0) {
return;
}
uint32_t timeoutMs = 100;
for (uint32_t i = 0; i <= timeoutMs; i++) {
HAL_ReadCANPacketNew(ph->hcan, PH_VERSION_FRAME_API, packedData, &length,
&timestamp, status);
if (*status == 0) {
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (*status != 0) {
return;
}
PH_version_unpack(&result, packedData, PH_VERSION_LENGTH);
version->firmwareMajor = result.firmware_year;
version->firmwareMinor = result.firmware_minor;
version->firmwareFix = result.firmware_fix;
version->hardwareMinor = result.hardware_minor;
version->hardwareMajor = result.hardware_major;
version->uniqueId = result.unique_id;
ph->versionInfo = *version;
}
int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
@@ -406,7 +538,7 @@ int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status) {
return 0;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
if (*status != 0) {
return 0;
@@ -446,11 +578,11 @@ void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
// The mask bit for the solenoid is set, so we update the solenoid state
REV_SolenoidState desiredSolenoidState =
values & (1 << solenoid) ? kSolenoidEnabled : kSolenoidDisabled;
HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), solenoid,
desiredSolenoidState);
HAL_UpdateDesiredREVPHSolenoidState(ph.get(), solenoid,
desiredSolenoidState);
}
}
HAL_REV_SendSolenoidsState(ph.get(), status);
HAL_SendREVPHSolenoidsState(ph.get(), status);
}
void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
@@ -469,7 +601,7 @@ void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
return;
}
if (!HAL_REV_CheckPHPulseTime(durMs)) {
if (!HAL_CheckREVPHPulseTime(durMs)) {
*status = PARAMETER_OUT_OF_RANGE;
hal::SetLastError(
status,
@@ -480,9 +612,9 @@ void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
{
std::scoped_lock lock{ph->solenoidLock};
HAL_REV_UpdateDesiredPHSolenoidState(ph.get(), index,
kSolenoidControlledViaPulse);
HAL_REV_SendSolenoidsState(ph.get(), status);
HAL_UpdateDesiredREVPHSolenoidState(ph.get(), index,
kSolenoidControlledViaPulse);
HAL_SendREVPHSolenoidsState(ph.get(), status);
}
if (*status != 0) {
@@ -553,58 +685,68 @@ void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
PH_PULSE_ONCE_FRAME_API, status);
}
HAL_REVPHFaults HAL_GetREVPHFaults(HAL_REVPHHandle handle, int32_t* status) {
HAL_REVPHFaults faults = {};
void HAL_GetREVPHFaults(HAL_REVPHHandle handle, HAL_REVPHFaults* faults,
int32_t* status) {
std::memset(faults, 0, sizeof(*faults));
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return faults;
return;
}
PH_status0_t status0 = HAL_REV_ReadPHStatus0(ph->hcan, status);
faults.channel0Fault = status0.channel_0_fault;
faults.channel1Fault = status0.channel_1_fault;
faults.channel2Fault = status0.channel_2_fault;
faults.channel3Fault = status0.channel_3_fault;
faults.channel4Fault = status0.channel_4_fault;
faults.channel5Fault = status0.channel_5_fault;
faults.channel6Fault = status0.channel_6_fault;
faults.channel7Fault = status0.channel_7_fault;
faults.channel8Fault = status0.channel_8_fault;
faults.channel9Fault = status0.channel_9_fault;
faults.channel10Fault = status0.channel_10_fault;
faults.channel11Fault = status0.channel_11_fault;
faults.channel12Fault = status0.channel_12_fault;
faults.channel13Fault = status0.channel_13_fault;
faults.channel14Fault = status0.channel_14_fault;
faults.channel15Fault = status0.channel_15_fault;
faults.compressorOverCurrent = status0.compressor_oc;
faults.compressorOpen = status0.compressor_open;
faults.solenoidOverCurrent = status0.solenoid_oc;
faults.brownout = status0.brownout;
faults.canWarning = status0.can_warning;
faults.hardwareFault = status0.hardware_fault;
return faults;
PH_status_0_t status0 = HAL_ReadREVPHStatus0(ph->hcan, status);
faults->channel0Fault = status0.channel_0_fault;
faults->channel1Fault = status0.channel_1_fault;
faults->channel2Fault = status0.channel_2_fault;
faults->channel3Fault = status0.channel_3_fault;
faults->channel4Fault = status0.channel_4_fault;
faults->channel5Fault = status0.channel_5_fault;
faults->channel6Fault = status0.channel_6_fault;
faults->channel7Fault = status0.channel_7_fault;
faults->channel8Fault = status0.channel_8_fault;
faults->channel9Fault = status0.channel_9_fault;
faults->channel10Fault = status0.channel_10_fault;
faults->channel11Fault = status0.channel_11_fault;
faults->channel12Fault = status0.channel_12_fault;
faults->channel13Fault = status0.channel_13_fault;
faults->channel14Fault = status0.channel_14_fault;
faults->channel15Fault = status0.channel_15_fault;
faults->compressorOverCurrent = status0.compressor_oc_fault;
faults->compressorOpen = status0.compressor_open_fault;
faults->solenoidOverCurrent = status0.solenoid_oc_fault;
faults->brownout = status0.brownout_fault;
faults->canWarning = status0.can_warning_fault;
faults->hardwareFault = status0.hardware_fault;
}
HAL_REVPHStickyFaults HAL_GetREVPHStickyFaults(HAL_REVPHHandle handle,
int32_t* status) {
HAL_REVPHStickyFaults stickyFaults = {};
void HAL_GetREVPHStickyFaults(HAL_REVPHHandle handle,
HAL_REVPHStickyFaults* stickyFaults,
int32_t* status) {
std::memset(stickyFaults, 0, sizeof(*stickyFaults));
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return stickyFaults;
return;
}
PH_status1_t status1 = HAL_REV_ReadPHStatus1(ph->hcan, status);
stickyFaults.compressorOverCurrent = status1.sticky_compressor_over_current;
stickyFaults.compressorOpen = status1.sticky_compressor_not_present;
stickyFaults.solenoidOverCurrent = status1.sticky_solenoid_over_current;
stickyFaults.brownout = status1.sticky_brownout;
stickyFaults.canWarning = status1.sticky_can_warning;
stickyFaults.canBusOff = status1.sticky_can_bus_off;
stickyFaults.hasReset = status1.sticky_has_reset;
return stickyFaults;
PH_status_1_t status1 = HAL_ReadREVPHStatus1(ph->hcan, status);
stickyFaults->compressorOverCurrent = status1.sticky_compressor_oc_fault;
stickyFaults->compressorOpen = status1.sticky_compressor_open_fault;
stickyFaults->solenoidOverCurrent = status1.sticky_solenoid_oc_fault;
stickyFaults->brownout = status1.sticky_brownout_fault;
stickyFaults->canWarning = status1.sticky_can_warning_fault;
stickyFaults->canBusOff = status1.sticky_can_bus_off_fault;
stickyFaults->hasReset = status1.sticky_has_reset_fault;
}
void HAL_ClearREVPHStickyFaults(HAL_REVPHHandle handle, int32_t* status) {
auto ph = REVPHHandles->Get(handle);
if (ph == nullptr) {
*status = HAL_HANDLE_ERROR;
return;
}
uint8_t packedData[8] = {0};
HAL_WriteCANPacket(ph->hcan, packedData, PH_CLEAR_FAULTS_LENGTH,
PH_CLEAR_FAULTS_FRAME_API, status);
}

View File

@@ -14,7 +14,6 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <string>
#include <thread>

View File

@@ -48,4 +48,6 @@ int32_t HALSIM_RegisterSimPeriodicAfterCallback(
void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {}
void HALSIM_CancelAllSimPeriodicCallbacks(void) {}
} // extern "C"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,7 @@ static JException canMessageNotFoundExCls;
static JException canMessageNotAllowedExCls;
static JException canNotInitializedExCls;
static JException uncleanStatusExCls;
static JClass powerDistributionVersionCls;
static JClass pwmConfigDataResultCls;
static JClass canStatusCls;
static JClass matchInfoDataCls;
@@ -53,15 +54,19 @@ static JClass accumulatorResultCls;
static JClass canDataCls;
static JClass halValueCls;
static JClass baseStoreCls;
static JClass revPHVersionCls;
static const JClassInit classes[] = {
{"edu/wpi/first/hal/PowerDistributionVersion",
&powerDistributionVersionCls},
{"edu/wpi/first/hal/PWMConfigDataResult", &pwmConfigDataResultCls},
{"edu/wpi/first/hal/can/CANStatus", &canStatusCls},
{"edu/wpi/first/hal/MatchInfoData", &matchInfoDataCls},
{"edu/wpi/first/hal/AccumulatorResult", &accumulatorResultCls},
{"edu/wpi/first/hal/CANData", &canDataCls},
{"edu/wpi/first/hal/HALValue", &halValueCls},
{"edu/wpi/first/hal/DMAJNISample$BaseStore", &baseStoreCls}};
{"edu/wpi/first/hal/DMAJNISample$BaseStore", &baseStoreCls},
{"edu/wpi/first/hal/REVPHVersion", &revPHVersionCls}};
static const JExceptionInit exceptions[] = {
{"java/lang/IllegalArgumentException", &illegalArgExCls},
@@ -238,6 +243,19 @@ jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
static_cast<jint>(deadbandMinPwm), static_cast<jint>(minPwm));
}
jobject CreateREVPHVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor, uint32_t firmwareFix,
uint32_t hardwareMinor, uint32_t hardwareMajor,
uint32_t uniqueId) {
static jmethodID constructor =
env->GetMethodID(revPHVersionCls, "<init>", "(IIIIII)V");
return env->NewObject(
revPHVersionCls, constructor, static_cast<jint>(firmwareMajor),
static_cast<jint>(firmwareMinor), static_cast<jint>(firmwareFix),
static_cast<jint>(hardwareMinor), static_cast<jint>(hardwareMajor),
static_cast<jint>(uniqueId));
}
void SetCanStatusObject(JNIEnv* env, jobject canStatus,
float percentBusUtilization, uint32_t busOffCount,
uint32_t txFullCount, uint32_t receiveErrorCount,
@@ -318,6 +336,21 @@ jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index) {
return env->NewObject(baseStoreCls, ctor, valueType, index);
}
jobject CreatePowerDistributionVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor,
uint32_t firmwareFix,
uint32_t hardwareMinor,
uint32_t hardwareMajor,
uint32_t uniqueId) {
static jmethodID constructor =
env->GetMethodID(powerDistributionVersionCls, "<init>", "(IIIIII)V");
return env->NewObject(
powerDistributionVersionCls, constructor,
static_cast<jint>(firmwareMajor), static_cast<jint>(firmwareMinor),
static_cast<jint>(firmwareFix), static_cast<jint>(hardwareMinor),
static_cast<jint>(hardwareMajor), static_cast<jint>(uniqueId));
}
JavaVM* GetJVM() {
return jvm;
}

View File

@@ -59,6 +59,11 @@ jobject CreatePWMConfigDataResult(JNIEnv* env, int32_t maxPwm,
int32_t deadbandMaxPwm, int32_t centerPwm,
int32_t deadbandMinPwm, int32_t minPwm);
jobject CreateREVPHVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor, uint32_t firmwareFix,
uint32_t hardwareMinor, uint32_t hardwareMajor,
uint32_t uniqueId);
void SetCanStatusObject(JNIEnv* env, jobject canStatus,
float percentBusUtilization, uint32_t busOffCount,
uint32_t txFullCount, uint32_t receiveErrorCount,
@@ -77,6 +82,13 @@ jobject CreateHALValue(JNIEnv* env, const HAL_Value& value);
jobject CreateDMABaseStore(JNIEnv* env, jint valueType, jint index);
jobject CreatePowerDistributionVersion(JNIEnv* env, uint32_t firmwareMajor,
uint32_t firmwareMinor,
uint32_t firmwareFix,
uint32_t hardwareMinor,
uint32_t hardwareMajor,
uint32_t uniqueId);
JavaVM* GetJVM();
} // namespace hal

View File

@@ -362,4 +362,63 @@ Java_edu_wpi_first_hal_PowerDistributionJNI_getSwitchableChannelNoError
return state;
}
/*
* Class: edu_wpi_first_hal_PowerDistributionJNI
* Method: getStickyFaultsNative
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PowerDistributionJNI_getStickyFaultsNative
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_PowerDistributionStickyFaults halFaults;
std::memset(&halFaults, 0, sizeof(halFaults));
HAL_GetPowerDistributionStickyFaults(handle, &halFaults, &status);
CheckStatus(env, status, false);
jint faults;
static_assert(sizeof(faults) == sizeof(halFaults));
std::memcpy(&faults, &halFaults, sizeof(faults));
return faults;
}
/*
* Class: edu_wpi_first_hal_PowerDistributionJNI
* Method: getFaultsNative
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_PowerDistributionJNI_getFaultsNative
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_PowerDistributionFaults halFaults;
std::memset(&halFaults, 0, sizeof(halFaults));
HAL_GetPowerDistributionFaults(handle, &halFaults, &status);
CheckStatus(env, status, false);
jint faults;
static_assert(sizeof(faults) == sizeof(halFaults));
std::memcpy(&faults, &halFaults, sizeof(faults));
return faults;
}
/*
* Class: edu_wpi_first_hal_PowerDistributionJNI
* Method: getVersion
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL
Java_edu_wpi_first_hal_PowerDistributionJNI_getVersion
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_PowerDistributionVersion version;
std::memset(&version, 0, sizeof(version));
HAL_GetPowerDistributionVersion(handle, &version, &status);
CheckStatus(env, status, false);
return CreatePowerDistributionVersion(
env, version.firmwareMajor, version.firmwareMinor, version.firmwareFix,
version.hardwareMinor, version.hardwareMajor, version.uniqueId);
}
} // extern "C"

View File

@@ -196,15 +196,15 @@ Java_edu_wpi_first_hal_REVPHJNI_getPressureSwitch
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getAnalogPressure
* Method: getAnalogVoltage
* Signature: (II)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getAnalogPressure
Java_edu_wpi_first_hal_REVPHJNI_getAnalogVoltage
(JNIEnv* env, jclass, jint handle, jint channel)
{
int32_t status = 0;
auto result = HAL_GetREVPHAnalogPressure(handle, channel, &status);
auto result = HAL_GetREVPHAnalogVoltage(handle, channel, &status);
CheckStatus(env, status, false);
return result;
}
@@ -267,4 +267,137 @@ Java_edu_wpi_first_hal_REVPHJNI_fireOneShot
CheckStatus(env, status, false);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: clearStickyFaults
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_first_hal_REVPHJNI_clearStickyFaults
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_ClearREVPHStickyFaults(handle, &status);
CheckStatus(env, status, false);
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getInputVoltage
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getInputVoltage
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto voltage = HAL_GetREVPHVoltage(handle, &status);
CheckStatus(env, status, false);
return voltage;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: get5VVoltage
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_get5VVoltage
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto voltage = HAL_GetREVPH5VVoltage(handle, &status);
CheckStatus(env, status, false);
return voltage;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getSolenoidCurrent
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getSolenoidCurrent
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto voltage = HAL_GetREVPHSolenoidCurrent(handle, &status);
CheckStatus(env, status, false);
return voltage;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getSolenoidVoltage
* Signature: (I)D
*/
JNIEXPORT jdouble JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getSolenoidVoltage
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
auto voltage = HAL_GetREVPHSolenoidVoltage(handle, &status);
CheckStatus(env, status, false);
return voltage;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getStickyFaultsNative
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getStickyFaultsNative
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_REVPHStickyFaults halFaults;
std::memset(&halFaults, 0, sizeof(halFaults));
HAL_GetREVPHStickyFaults(handle, &halFaults, &status);
CheckStatus(env, status, false);
jint faults;
static_assert(sizeof(faults) == sizeof(halFaults));
std::memcpy(&faults, &halFaults, sizeof(faults));
return faults;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getFaultsNative
* Signature: (I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getFaultsNative
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_REVPHFaults halFaults;
std::memset(&halFaults, 0, sizeof(halFaults));
HAL_GetREVPHFaults(handle, &halFaults, &status);
CheckStatus(env, status, false);
jint faults;
static_assert(sizeof(faults) == sizeof(halFaults));
std::memcpy(&faults, &halFaults, sizeof(faults));
return faults;
}
/*
* Class: edu_wpi_first_hal_REVPHJNI
* Method: getVersion
* Signature: (I)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL
Java_edu_wpi_first_hal_REVPHJNI_getVersion
(JNIEnv* env, jclass, jint handle)
{
int32_t status = 0;
HAL_REVPHVersion version;
std::memset(&version, 0, sizeof(version));
HAL_GetREVPHVersion(handle, &version, &status);
CheckStatus(env, status, false);
return CreateREVPHVersion(env, version.firmwareMajor, version.firmwareMinor,
version.firmwareFix, version.hardwareMinor,
version.hardwareMajor, version.uniqueId);
}
} // extern "C"

View File

@@ -218,6 +218,89 @@ void HAL_SetPowerDistributionSwitchableChannel(
HAL_Bool HAL_GetPowerDistributionSwitchableChannel(
HAL_PowerDistributionHandle handle, int32_t* status);
struct HAL_PowerDistributionVersion {
uint32_t firmwareMajor;
uint32_t firmwareMinor;
uint32_t firmwareFix;
uint32_t hardwareMinor;
uint32_t hardwareMajor;
uint32_t uniqueId;
};
struct HAL_PowerDistributionFaults {
uint32_t channel0BreakerFault : 1;
uint32_t channel1BreakerFault : 1;
uint32_t channel2BreakerFault : 1;
uint32_t channel3BreakerFault : 1;
uint32_t channel4BreakerFault : 1;
uint32_t channel5BreakerFault : 1;
uint32_t channel6BreakerFault : 1;
uint32_t channel7BreakerFault : 1;
uint32_t channel8BreakerFault : 1;
uint32_t channel9BreakerFault : 1;
uint32_t channel10BreakerFault : 1;
uint32_t channel11BreakerFault : 1;
uint32_t channel12BreakerFault : 1;
uint32_t channel13BreakerFault : 1;
uint32_t channel14BreakerFault : 1;
uint32_t channel15BreakerFault : 1;
uint32_t channel16BreakerFault : 1;
uint32_t channel17BreakerFault : 1;
uint32_t channel18BreakerFault : 1;
uint32_t channel19BreakerFault : 1;
uint32_t channel20BreakerFault : 1;
uint32_t channel21BreakerFault : 1;
uint32_t channel22BreakerFault : 1;
uint32_t channel23BreakerFault : 1;
uint32_t brownout : 1;
uint32_t canWarning : 1;
uint32_t hardwareFault : 1;
};
/**
* Storage for REV PDH Sticky Faults
*/
struct HAL_PowerDistributionStickyFaults {
uint32_t channel0BreakerFault : 1;
uint32_t channel1BreakerFault : 1;
uint32_t channel2BreakerFault : 1;
uint32_t channel3BreakerFault : 1;
uint32_t channel4BreakerFault : 1;
uint32_t channel5BreakerFault : 1;
uint32_t channel6BreakerFault : 1;
uint32_t channel7BreakerFault : 1;
uint32_t channel8BreakerFault : 1;
uint32_t channel9BreakerFault : 1;
uint32_t channel10BreakerFault : 1;
uint32_t channel11BreakerFault : 1;
uint32_t channel12BreakerFault : 1;
uint32_t channel13BreakerFault : 1;
uint32_t channel14BreakerFault : 1;
uint32_t channel15BreakerFault : 1;
uint32_t channel16BreakerFault : 1;
uint32_t channel17BreakerFault : 1;
uint32_t channel18BreakerFault : 1;
uint32_t channel19BreakerFault : 1;
uint32_t channel20BreakerFault : 1;
uint32_t channel21BreakerFault : 1;
uint32_t channel22BreakerFault : 1;
uint32_t channel23BreakerFault : 1;
uint32_t brownout : 1;
uint32_t canWarning : 1;
uint32_t canBusOff : 1;
uint32_t hasReset : 1;
};
void HAL_GetPowerDistributionVersion(HAL_PowerDistributionHandle handle,
HAL_PowerDistributionVersion* version,
int32_t* status);
void HAL_GetPowerDistributionFaults(HAL_PowerDistributionHandle handle,
HAL_PowerDistributionFaults* faults,
int32_t* status);
void HAL_GetPowerDistributionStickyFaults(
HAL_PowerDistributionHandle handle,
HAL_PowerDistributionStickyFaults* stickyFaults, int32_t* status);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@@ -24,6 +24,18 @@ HAL_ENUM(HAL_REVPHCompressorConfigType){
HAL_REVPHCompressorConfigType_kHybrid = 3,
};
/**
* Storage for REV PH Version
*/
struct HAL_REVPHVersion {
uint32_t firmwareMajor;
uint32_t firmwareMinor;
uint32_t firmwareFix;
uint32_t hardwareMinor;
uint32_t hardwareMajor;
uint32_t uniqueId;
};
/**
* Storage for compressor config
*/
@@ -108,8 +120,14 @@ HAL_REVPHCompressorConfigType HAL_GetREVPHCompressorConfig(
HAL_REVPHHandle handle, int32_t* status);
HAL_Bool HAL_GetREVPHPressureSwitch(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHCompressorCurrent(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHAnalogPressure(HAL_REVPHHandle handle, int32_t channel,
int32_t* status);
double HAL_GetREVPHAnalogVoltage(HAL_REVPHHandle handle, int32_t channel,
int32_t* status);
double HAL_GetREVPHVoltage(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPH5VVoltage(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHSolenoidCurrent(HAL_REVPHHandle handle, int32_t* status);
double HAL_GetREVPHSolenoidVoltage(HAL_REVPHHandle handle, int32_t* status);
void HAL_GetREVPHVersion(HAL_REVPHHandle handle, HAL_REVPHVersion* version,
int32_t* status);
int32_t HAL_GetREVPHSolenoids(HAL_REVPHHandle handle, int32_t* status);
void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
@@ -118,10 +136,14 @@ void HAL_SetREVPHSolenoids(HAL_REVPHHandle handle, int32_t mask, int32_t values,
void HAL_FireREVPHOneShot(HAL_REVPHHandle handle, int32_t index, int32_t durMs,
int32_t* status);
HAL_REVPHFaults HAL_GetREVPHFaults(HAL_REVPHHandle handle, int32_t* status);
void HAL_GetREVPHFaults(HAL_REVPHHandle handle, HAL_REVPHFaults* faults,
int32_t* status);
HAL_REVPHStickyFaults HAL_GetREVPHStickyFaults(HAL_REVPHHandle handle,
int32_t* status);
void HAL_GetREVPHStickyFaults(HAL_REVPHHandle handle,
HAL_REVPHStickyFaults* stickyFaults,
int32_t* status);
void HAL_ClearREVPHStickyFaults(HAL_REVPHHandle handle, int32_t* status);
#ifdef __cplusplus
} // extern "C"

View File

@@ -74,6 +74,11 @@ typedef int32_t HAL_Bool;
#ifdef __cplusplus
#define HAL_ENUM(name) enum name : int32_t
#elif defined(__clang__)
#define HAL_ENUM(name) \
enum name : int32_t; \
typedef enum name name; \
enum name : int32_t
#else
#define HAL_ENUM(name) \
typedef int32_t name; \

View File

@@ -36,4 +36,6 @@ int32_t HALSIM_RegisterSimPeriodicAfterCallback(
HALSIM_SimPeriodicCallback callback, void* param);
void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid);
void HALSIM_CancelAllSimPeriodicCallbacks(void);
} // extern "C"

View File

@@ -409,6 +409,11 @@ void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {
gSimPeriodicAfter.Cancel(uid);
}
void HALSIM_CancelAllSimPeriodicCallbacks(void) {
gSimPeriodicBefore.Reset();
gSimPeriodicAfter.Reset();
}
int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
const char* feature) {
return 0; // Do nothing for now

View File

@@ -320,7 +320,7 @@ int32_t HALSIM_GetNotifierInfo(struct HALSIM_NotifierInfo* arr, int32_t size) {
static_cast<int>(getHandleIndex(handle)));
} else {
std::strncpy(arr[num].name, notifier->name.c_str(),
sizeof(arr[num].name));
sizeof(arr[num].name) - 1);
arr[num].name[sizeof(arr[num].name) - 1] = '\0';
}
arr[num].timeout = notifier->waitTime;

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