Compare commits
185 Commits
v2022.1.1-
...
v2022.4.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d66555e42f | ||
|
|
9f52d8a3b1 | ||
|
|
757ea91932 | ||
|
|
02a804f1c5 | ||
|
|
9b500df0d9 | ||
|
|
5a89575b3a | ||
|
|
b8c4d7527b | ||
|
|
ac5d46cfa7 | ||
|
|
bc9e96e86f | ||
|
|
f88c435dd0 | ||
|
|
e4b91005cf | ||
|
|
a260bfd83b | ||
|
|
18e262a100 | ||
|
|
4bd1f526ab | ||
|
|
27847d7eb2 | ||
|
|
b2a8d3f0f3 | ||
|
|
49adac9564 | ||
|
|
a19d1133b1 | ||
|
|
dde91717e4 | ||
|
|
e9050afd67 | ||
|
|
165d2837cf | ||
|
|
ac7549edca | ||
|
|
4d96bc72e0 | ||
|
|
3411eee20f | ||
|
|
74de97eeca | ||
|
|
4e3cc25012 | ||
|
|
90c1db393e | ||
|
|
2f43274aa4 | ||
|
|
aeca09db09 | ||
|
|
c107f22c67 | ||
|
|
68fe51e8da | ||
|
|
8d08d67cf1 | ||
|
|
4f1782f66e | ||
|
|
3f77725cd3 | ||
|
|
5635f33a32 | ||
|
|
bca4b7111b | ||
|
|
6a6366b0d6 | ||
|
|
16bf2c70c5 | ||
|
|
4b3edb742c | ||
|
|
fcf23fc9e9 | ||
|
|
af5ef510c5 | ||
|
|
05401e2b81 | ||
|
|
9fde0110b6 | ||
|
|
b03f8ddb2e | ||
|
|
a26df2a022 | ||
|
|
d68d6674e8 | ||
|
|
a8f0f6bb90 | ||
|
|
dd9c92d5bf | ||
|
|
84df14dd70 | ||
|
|
560094ad92 | ||
|
|
7ea1be9c01 | ||
|
|
700f13bffd | ||
|
|
b6aa7c1aa9 | ||
|
|
eb4d183e48 | ||
|
|
77e4e81e1e | ||
|
|
88f5cb6eb0 | ||
|
|
efae552f3e | ||
|
|
46b277421a | ||
|
|
42908126b9 | ||
|
|
a467392cbd | ||
|
|
78d0bcf49d | ||
|
|
02a0ced9b0 | ||
|
|
4ccfe1c9f2 | ||
|
|
830c0c5c2f | ||
|
|
5548a37465 | ||
|
|
2f9a600de2 | ||
|
|
559db11a20 | ||
|
|
76c78e295b | ||
|
|
debbd5ff4b | ||
|
|
841174f302 | ||
|
|
8c55844f91 | ||
|
|
0b990bf0f5 | ||
|
|
104d7e2abc | ||
|
|
5ba69e1af1 | ||
|
|
f3a0b5c7d7 | ||
|
|
7f4265facc | ||
|
|
63d1fb3bed | ||
|
|
36af6d25a5 | ||
|
|
8f387f7255 | ||
|
|
792e735e08 | ||
|
|
3b76de83eb | ||
|
|
ad9f738cfa | ||
|
|
49455199e5 | ||
|
|
64426502ea | ||
|
|
8cc112d196 | ||
|
|
e78cd49861 | ||
|
|
cfb4f756d6 | ||
|
|
ba0908216c | ||
|
|
a3a0334fad | ||
|
|
cf7460c3a8 | ||
|
|
db0fbb6448 | ||
|
|
8ac45f20bb | ||
|
|
b3707cca0b | ||
|
|
a69ee3ece9 | ||
|
|
750d9a30c9 | ||
|
|
41c5b2b5ac | ||
|
|
6cf3f9b28e | ||
|
|
269cf03472 | ||
|
|
5ccfc4adbd | ||
|
|
b6f44f98be | ||
|
|
0dca57e9ec | ||
|
|
22c4da152e | ||
|
|
05d66f862d | ||
|
|
b09f5b2cf2 | ||
|
|
a2510aaa0e | ||
|
|
947f589916 | ||
|
|
bbd8980a20 | ||
|
|
831052f118 | ||
|
|
c137569f91 | ||
|
|
dae61226fa | ||
|
|
3ad4594a88 | ||
|
|
112acb9a62 | ||
|
|
ecee224e81 | ||
|
|
a3645dea34 | ||
|
|
7c09f44898 | ||
|
|
f401ea9aae | ||
|
|
bf8517f1e6 | ||
|
|
528087e308 | ||
|
|
1f59ff72f9 | ||
|
|
315be873c4 | ||
|
|
b8d019cdb4 | ||
|
|
102f23bbdb | ||
|
|
b85c24a79c | ||
|
|
eee29daaf9 | ||
|
|
aa9dfabde2 | ||
|
|
5999a26fba | ||
|
|
1e82595ffb | ||
|
|
e373fa476b | ||
|
|
dceb5364f4 | ||
|
|
baacbc8e24 | ||
|
|
84b15f0883 | ||
|
|
c0da9d2d35 | ||
|
|
0fe0be2733 | ||
|
|
eafa947338 | ||
|
|
9d13ae8d01 | ||
|
|
2a64e4bae5 | ||
|
|
c3fd20db59 | ||
|
|
6f91f37cd0 | ||
|
|
5158730b81 | ||
|
|
2ad2d2ca96 | ||
|
|
b5fd29774f | ||
|
|
9f8f330e96 | ||
|
|
1ad3b1b333 | ||
|
|
dfc24425c3 | ||
|
|
c02577bb51 | ||
|
|
c9e6a96a61 | ||
|
|
9778626f34 | ||
|
|
34b2d0dae1 | ||
|
|
59a7528fd6 | ||
|
|
11d9859ef1 | ||
|
|
e44ed752ad | ||
|
|
52b2dd5b89 | ||
|
|
c46636f218 | ||
|
|
dc531462e1 | ||
|
|
92ba98621c | ||
|
|
d41d051f1b | ||
|
|
c5ae0effac | ||
|
|
b3974c6ed3 | ||
|
|
589a00e379 | ||
|
|
8d9836ca02 | ||
|
|
8b5bf8632e | ||
|
|
1846114491 | ||
|
|
2c461c794e | ||
|
|
109363daa4 | ||
|
|
41d26bee8d | ||
|
|
7269a170fb | ||
|
|
441f2ed9b0 | ||
|
|
15275433d4 | ||
|
|
1ac02d2f58 | ||
|
|
8ee6257e92 | ||
|
|
d81ef2bc5c | ||
|
|
acb64dff97 | ||
|
|
3f6cf76a8c | ||
|
|
3ef2dab465 | ||
|
|
a5a56dd067 | ||
|
|
04957a6d30 | ||
|
|
5da54888f8 | ||
|
|
6c93365b0f | ||
|
|
1c4a8bfb66 | ||
|
|
d51a1d3b3d | ||
|
|
aced2e7da6 | ||
|
|
fa1ceca83a | ||
|
|
0ea05d34e6 | ||
|
|
09db4f672b | ||
|
|
4ba80a3a8c |
4
.github/workflows/cmake.yml
vendored
@@ -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
|
||||
|
||||
6
.github/workflows/gradle.yml
vendored
@@ -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 }}"
|
||||
|
||||
@@ -11,6 +11,7 @@ cppSrcFileInclude {
|
||||
|
||||
modifiableFileExclude {
|
||||
\.patch$
|
||||
gradlew
|
||||
}
|
||||
|
||||
generatedFileExclude {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"enableCppIntellisense": true,
|
||||
"currentLanguage": "cpp",
|
||||
"projectYear": "2021",
|
||||
"projectYear": "intellisense",
|
||||
"teamNumber": 0
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.+
|
||||
|
||||
@@ -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.
|
||||
|
||||
14
build.gradle
@@ -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'
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ repositories {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation "edu.wpi.first:native-utils:2022.3.1"
|
||||
implementation "edu.wpi.first:native-utils:2022.7.1"
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
116
cmake/modules/FindLIBSSH.cmake
Normal 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()
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
29
datalogtool/CMakeLists.txt
Normal 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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
datalogtool/src/main/generate/WPILibVersion.cpp.in
Normal 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}";
|
||||
}
|
||||
156
datalogtool/src/main/native/cpp/App.cpp
Normal 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();
|
||||
}
|
||||
11
datalogtool/src/main/native/cpp/App.h
Normal 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);
|
||||
72
datalogtool/src/main/native/cpp/DataLogThread.cpp
Normal 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;
|
||||
}
|
||||
71
datalogtool/src/main/native/cpp/DataLogThread.h
Normal 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;
|
||||
};
|
||||
393
datalogtool/src/main/native/cpp/Downloader.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
datalogtool/src/main/native/cpp/Downloader.h
Normal 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;
|
||||
};
|
||||
655
datalogtool/src/main/native/cpp/Exporter.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
15
datalogtool/src/main/native/cpp/Exporter.h
Normal 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;
|
||||
215
datalogtool/src/main/native/cpp/Sftp.cpp
Normal 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)};
|
||||
}
|
||||
144
datalogtool/src/main/native/cpp/Sftp.h
Normal 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
|
||||
25
datalogtool/src/main/native/cpp/main.cpp
Normal 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;
|
||||
}
|
||||
BIN
datalogtool/src/main/native/mac/datalogtool.icns
Normal file
BIN
datalogtool/src/main/native/resources/dlt-128.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
datalogtool/src/main/native/resources/dlt-16.png
Normal file
|
After Width: | Height: | Size: 609 B |
BIN
datalogtool/src/main/native/resources/dlt-256.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
datalogtool/src/main/native/resources/dlt-32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
datalogtool/src/main/native/resources/dlt-48.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
datalogtool/src/main/native/resources/dlt-512.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
datalogtool/src/main/native/resources/dlt-64.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
datalogtool/src/main/native/win/datalogtool.ico
Normal file
|
After Width: | Height: | Size: 361 KiB |
1
datalogtool/src/main/native/win/datalogtool.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON "datalogtool.ico"
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
12
fieldImages/src/main/native/include/fields/2022-rapidreact.h
Normal 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
|
||||
|
After Width: | Height: | Size: 1.8 MiB |
@@ -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"
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
52
glass/src/app/native/cpp/camerasupport.cpp
Normal 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
|
||||
9
glass/src/app/native/cpp/camerasupport.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
@@ -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" "$@"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
123
hal/src/main/java/edu/wpi/first/hal/PowerDistributionFaults.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
104
hal/src/main/java/edu/wpi/first/hal/REVPHFaults.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
44
hal/src/main/java/edu/wpi/first/hal/REVPHStickyFaults.java
Normal 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;
|
||||
}
|
||||
}
|
||||
51
hal/src/main/java/edu/wpi/first/hal/REVPHVersion.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
×tamp, 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,
|
||||
×tamp, 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,
|
||||
×tamp, 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,
|
||||
×tamp, 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,
|
||||
×tamp, 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, ×tamp, 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,
|
||||
×tamp, 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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
×tamp, 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,
|
||||
×tamp, 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,
|
||||
×tamp, 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);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
@@ -48,4 +48,6 @@ int32_t HALSIM_RegisterSimPeriodicAfterCallback(
|
||||
|
||||
void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {}
|
||||
|
||||
void HALSIM_CancelAllSimPeriodicCallbacks(void) {}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||