mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-29 02:21:44 +00:00
Compare commits
37 Commits
v2019.1.1-
...
v2019.1.1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d188a429 | ||
|
|
563d5334c9 | ||
|
|
193b0a222c | ||
|
|
76f5d153fa | ||
|
|
19caeca990 | ||
|
|
0abae17653 | ||
|
|
81d10bc656 | ||
|
|
b51b86525d | ||
|
|
ace37c517e | ||
|
|
ac751d3224 | ||
|
|
7c9a3c4d77 | ||
|
|
8be693f55d | ||
|
|
622ae29dff | ||
|
|
e7c98feca2 | ||
|
|
28087424ec | ||
|
|
b6830638df | ||
|
|
fb557f49ea | ||
|
|
746f950a0b | ||
|
|
9a38a3e188 | ||
|
|
2e3e3a47b9 | ||
|
|
e27d6d7bb8 | ||
|
|
1dec0393a1 | ||
|
|
d03b020326 | ||
|
|
71e29b1d91 | ||
|
|
f0b0965f9b | ||
|
|
f774e47c80 | ||
|
|
761933a164 | ||
|
|
99e0f08a6f | ||
|
|
e89d5eb692 | ||
|
|
2501e11886 | ||
|
|
9174f23f36 | ||
|
|
9f6544fa87 | ||
|
|
9a1af132bf | ||
|
|
a8aacd3657 | ||
|
|
8ff81f5a2a | ||
|
|
349e273ecc | ||
|
|
0a2ab4f0d7 |
@@ -7,6 +7,8 @@ resources:
|
||||
containers:
|
||||
- container: wpilib2019
|
||||
image: wpilib/roborio-cross-ubuntu:2019-18.04
|
||||
- container: raspbian
|
||||
image: wpilib/raspbian-cross-ubuntu:18.04
|
||||
|
||||
jobs:
|
||||
- job: Linux_Arm
|
||||
@@ -28,6 +30,25 @@ jobs:
|
||||
# checkStyleRunAnalysis: true
|
||||
# pmdRunAnalysis: true
|
||||
|
||||
- job: Linux_Raspbian
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: raspbian
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PonlyRaspbian'
|
||||
# checkStyleRunAnalysis: true
|
||||
# pmdRunAnalysis: true
|
||||
|
||||
- job: Linux
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
12
build.gradle
12
build.gradle
@@ -1,9 +1,9 @@
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '2.2'
|
||||
id 'edu.wpi.first.NativeUtils' version '1.7.7'
|
||||
id 'edu.wpi.first.GradleJni' version '0.3.0'
|
||||
id 'edu.wpi.first.GradleVsCode' version '0.4.2'
|
||||
id 'edu.wpi.first.NativeUtils' version '2.0.1'
|
||||
id 'edu.wpi.first.GradleJni' version '0.3.1'
|
||||
id 'edu.wpi.first.GradleVsCode' version '0.6.1'
|
||||
id 'idea'
|
||||
id 'com.gradle.build-scan' version '1.15.1'
|
||||
id 'net.ltgt.errorprone' version '0.6' apply false
|
||||
@@ -77,6 +77,12 @@ subprojects {
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
def subproj = it
|
||||
|
||||
plugins.withType(NativeComponentPlugin) {
|
||||
subproj.apply plugin: MultiBuilds
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/java/javastyle.gradle"
|
||||
|
||||
repositories {
|
||||
|
||||
95
buildSrc/src/main/groovy/MultiBuilds.groovy
Normal file
95
buildSrc/src/main/groovy/MultiBuilds.groovy
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.language.base.internal.ProjectLayout;
|
||||
import org.gradle.language.base.plugins.ComponentModelBasePlugin;
|
||||
import org.gradle.language.nativeplatform.tasks.AbstractNativeSourceCompileTask;
|
||||
import org.gradle.model.ModelMap;
|
||||
import org.gradle.model.Mutate;
|
||||
import org.gradle.nativeplatform.test.googletest.GoogleTestTestSuiteBinarySpec;
|
||||
import org.gradle.model.RuleSource;
|
||||
import org.gradle.model.Validate;
|
||||
import org.gradle.nativeplatform.NativeExecutableBinarySpec
|
||||
import org.gradle.nativeplatform.NativeBinarySpec;
|
||||
import org.gradle.nativeplatform.NativeComponentSpec;
|
||||
import org.gradle.nativeplatform.NativeLibrarySpec;
|
||||
import org.gradle.nativeplatform.SharedLibraryBinarySpec;
|
||||
import org.gradle.nativeplatform.StaticLibraryBinarySpec;
|
||||
import org.gradle.nativeplatform.platform.internal.NativePlatformInternal;
|
||||
import org.gradle.nativeplatform.toolchain.NativeToolChain;
|
||||
import org.gradle.nativeplatform.toolchain.NativeToolChainRegistry;
|
||||
import org.gradle.nativeplatform.toolchain.internal.PlatformToolProvider;
|
||||
import org.gradle.nativeplatform.toolchain.internal.ToolType;
|
||||
import org.gradle.nativeplatform.toolchain.internal.gcc.AbstractGccCompatibleToolChain;
|
||||
import org.gradle.nativeplatform.toolchain.internal.msvcpp.VisualCppToolChain;
|
||||
import org.gradle.nativeplatform.toolchain.internal.tools.ToolRegistry;
|
||||
import org.gradle.platform.base.BinarySpec;
|
||||
import org.gradle.platform.base.ComponentSpec;
|
||||
import org.gradle.platform.base.ComponentSpecContainer;
|
||||
import org.gradle.platform.base.BinaryContainer;
|
||||
import org.gradle.platform.base.ComponentType;
|
||||
import org.gradle.platform.base.TypeBuilder;
|
||||
import org.gradle.nativeplatform.tasks.ObjectFilesToBinary;
|
||||
import groovy.transform.CompileStatic;
|
||||
import groovy.transform.CompileDynamic
|
||||
import org.gradle.nativeplatform.BuildTypeContainer
|
||||
|
||||
@CompileStatic
|
||||
class MultiBuilds implements Plugin<Project> {
|
||||
@CompileStatic
|
||||
public void apply(Project project) {
|
||||
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
static class Rules extends RuleSource {
|
||||
@Mutate
|
||||
void setupBuildTypes(BuildTypeContainer buildTypes, ProjectLayout projectLayout) {
|
||||
def project = (Project) projectLayout.projectIdentifier
|
||||
if (project.hasProperty('releaseBuild')) {
|
||||
buildTypes.create('debug')
|
||||
} else {
|
||||
buildTypes.create('release')
|
||||
}
|
||||
}
|
||||
|
||||
@CompileDynamic
|
||||
private static void setBuildableFalseDynamically(NativeBinarySpec binary) {
|
||||
binary.buildable = false
|
||||
}
|
||||
|
||||
@Mutate
|
||||
@CompileStatic
|
||||
void disableReleaseGoogleTest(BinaryContainer binaries, ProjectLayout projectLayout) {
|
||||
def project = (Project) projectLayout.projectIdentifier
|
||||
if (project.hasProperty('testRelease')) {
|
||||
return
|
||||
}
|
||||
binaries.withType(GoogleTestTestSuiteBinarySpec) { oSpec ->
|
||||
GoogleTestTestSuiteBinarySpec spec = (GoogleTestTestSuiteBinarySpec) oSpec
|
||||
if (spec.buildType.name == 'release') {
|
||||
Rules.setBuildableFalseDynamically(spec)
|
||||
}
|
||||
}
|
||||
// def crossCompileConfigs = []
|
||||
// for (BuildConfig config : configs) {
|
||||
// if (!BuildConfigRulesBase.isCrossCompile(config)) {
|
||||
// continue
|
||||
// }
|
||||
// crossCompileConfigs << config.architecture
|
||||
// }
|
||||
// if (!crossCompileConfigs.empty) {
|
||||
// binaries.withType(GoogleTestTestSuiteBinarySpec) { oSpec ->
|
||||
// GoogleTestTestSuiteBinarySpec spec = (GoogleTestTestSuiteBinarySpec) oSpec
|
||||
// if (crossCompileConfigs.contains(spec.targetPlatform.architecture.name)) {
|
||||
// setBuildableFalseDynamically(spec)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
components.each { component ->
|
||||
if (component.name == "${nativeName}Base") {
|
||||
base = (NativeLibrarySpec) component
|
||||
} else if (component.name == "${nativeName}" || component.name == "${nativeName}JNI") {
|
||||
} else if (component.name == "${nativeName}") {
|
||||
subs << component
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,8 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
}
|
||||
def tmpBaseBin = (NativeBinarySpec) oTmpBaseBin
|
||||
if (tmpBaseBin.targetPlatform.operatingSystem.name == binary.targetPlatform.operatingSystem.name &&
|
||||
tmpBaseBin.targetPlatform.architecture.name == binary.targetPlatform.architecture.name) {
|
||||
tmpBaseBin.targetPlatform.architecture.name == binary.targetPlatform.architecture.name &&
|
||||
tmpBaseBin.buildType == binary.buildType) {
|
||||
baseBin = tmpBaseBin
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ endif()
|
||||
file(GLOB_RECURSE
|
||||
cameraserver_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(cameraserver ${cameraserver_native_src})
|
||||
set_target_properties(cameraserver PROPERTIES DEBUG_POSTFIX "d")
|
||||
target_include_directories(cameraserver PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cameraserver>)
|
||||
|
||||
@@ -85,9 +85,7 @@ public final class CameraServer {
|
||||
}
|
||||
}
|
||||
case kCv:
|
||||
// FIXME: Should be "cv:", but LabVIEW dashboard requires "usb:".
|
||||
// https://github.com/wpilibsuite/allwpilib/issues/407
|
||||
return "usb:";
|
||||
return "cv:";
|
||||
default:
|
||||
return "unknown:";
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ static wpi::StringRef MakeSourceValue(CS_Source source,
|
||||
CS_Status status = 0;
|
||||
buf.clear();
|
||||
switch (cs::GetSourceKind(source, &status)) {
|
||||
#ifdef __linux__
|
||||
case cs::VideoSource::kUsb: {
|
||||
wpi::StringRef prefix{"usb:"};
|
||||
buf.append(prefix.begin(), prefix.end());
|
||||
@@ -63,7 +62,6 @@ static wpi::StringRef MakeSourceValue(CS_Source source,
|
||||
buf.append(path.begin(), path.end());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case cs::VideoSource::kHttp: {
|
||||
wpi::StringRef prefix{"ip:"};
|
||||
buf.append(prefix.begin(), prefix.end());
|
||||
@@ -72,9 +70,7 @@ static wpi::StringRef MakeSourceValue(CS_Source source,
|
||||
break;
|
||||
}
|
||||
case cs::VideoSource::kCv:
|
||||
// FIXME: Should be "cv:", but LabVIEW dashboard requires "usb:".
|
||||
// https://github.com/wpilibsuite/allwpilib/issues/407
|
||||
return "usb:";
|
||||
return "cv:";
|
||||
default:
|
||||
return "unknown:";
|
||||
}
|
||||
@@ -457,7 +453,6 @@ CameraServer::CameraServer() : m_impl(new Impl) {}
|
||||
|
||||
CameraServer::~CameraServer() {}
|
||||
|
||||
#ifdef __linux__
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture() {
|
||||
cs::UsbCamera camera = StartAutomaticCapture(m_impl->m_defaultUsbDevice++);
|
||||
auto csShared = GetCameraServerShared();
|
||||
@@ -490,7 +485,6 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
#endif
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
|
||||
@@ -36,8 +36,6 @@ class CameraServer {
|
||||
*/
|
||||
static CameraServer* GetInstance();
|
||||
|
||||
#ifdef __linux__
|
||||
// USBCamera does not work on anything except Linux.
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
*
|
||||
@@ -77,7 +75,6 @@ class CameraServer {
|
||||
*/
|
||||
cs::UsbCamera StartAutomaticCapture(const wpi::Twine& name,
|
||||
const wpi::Twine& path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard from
|
||||
|
||||
@@ -19,6 +19,9 @@ licenseUpdateExclude {
|
||||
includeGuardRoots {
|
||||
cscore/src/main/native/cpp/
|
||||
cscore/src/main/native/include/
|
||||
cscore/src/main/native/linux/
|
||||
cscore/src/main/native/osx/
|
||||
cscore/src/main/native/windows/
|
||||
cscore/src/main/test/native/cpp/
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,57 @@ include(SubDirList)
|
||||
|
||||
find_package( OpenCV REQUIRED )
|
||||
|
||||
file(GLOB
|
||||
cscore_native_src src/main/native/cpp/*.cpp)
|
||||
file(GLOB cscore_linux_src src/main/native/linux/*.cpp)
|
||||
file(GLOB cscore_osx_src src/main/native/osx/*.cpp)
|
||||
file(GLOB cscore_windows_src src/main/native/windows/*.cpp)
|
||||
|
||||
add_library(cscore ${cscore_native_src})
|
||||
set_target_properties(cscore PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
if(NOT MSVC)
|
||||
if (APPLE)
|
||||
target_sources(cscore PRIVATE ${cscore_osx_src})
|
||||
else()
|
||||
target_sources(cscore PRIVATE ${cscore_linux_src})
|
||||
endif()
|
||||
target_compile_options(cscore PRIVATE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE)
|
||||
else()
|
||||
target_sources(cscore PRIVATE ${cscore_windows_src})
|
||||
target_compile_options(cscore PUBLIC -DNOMINMAX)
|
||||
target_compile_options(cscore PRIVATE -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_include_directories(cscore PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cscore>)
|
||||
target_include_directories(cscore PRIVATE src/main/native/cpp)
|
||||
target_link_libraries(cscore PUBLIC wpiutil ${OpenCV_LIBS})
|
||||
|
||||
set_property(TARGET cscore PROPERTY FOLDER "libraries")
|
||||
|
||||
install(TARGETS cscore EXPORT cscore DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cscore")
|
||||
|
||||
if (MSVC)
|
||||
set (cscore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cscore_config_dir share/cscore)
|
||||
endif()
|
||||
|
||||
install(FILES cscore-config.cmake DESTINATION ${cscore_config_dir})
|
||||
install(EXPORT cscore DESTINATION ${cscore_config_dir})
|
||||
|
||||
SUBDIR_LIST(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
|
||||
foreach(example ${cscore_examples})
|
||||
file(GLOB cscore_example_src examples/${example}/*.cpp)
|
||||
if(cscore_example_src)
|
||||
add_executable(cscore_${example} ${cscore_example_src})
|
||||
target_link_libraries(cscore_${example} cscore)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Java bindings
|
||||
if (NOT WITHOUT_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
@@ -50,49 +101,23 @@ if (NOT WITHOUT_JAVA)
|
||||
|
||||
set_property(TARGET cscore_jar PROPERTY FOLDER "java")
|
||||
|
||||
endif()
|
||||
add_library(cscorejni ${cscore_jni_src})
|
||||
target_link_libraries(cscorejni PUBLIC cscore wpiutil ${OpenCV_LIBS})
|
||||
|
||||
file(GLOB
|
||||
cscore_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(cscore ${cscore_native_src} ${cscore_jni_src})
|
||||
target_include_directories(cscore PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cscore>)
|
||||
target_link_libraries(cscore PUBLIC wpiutil ${OpenCV_LIBS})
|
||||
set_property(TARGET cscorejni PROPERTY FOLDER "libraries")
|
||||
|
||||
set_property(TARGET cscore PROPERTY FOLDER "libraries")
|
||||
|
||||
if (NOT WITHOUT_JAVA)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
target_include_directories(cscore PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(cscore PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
target_include_directories(cscorejni PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(cscorejni PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
else()
|
||||
target_link_libraries(cscore PRIVATE cscore_jni_headers)
|
||||
target_link_libraries(cscorejni PRIVATE cscore_jni_headers)
|
||||
endif()
|
||||
add_dependencies(cscore cscore_jar)
|
||||
endif()
|
||||
add_dependencies(cscorejni cscore_jar)
|
||||
|
||||
install(TARGETS cscore EXPORT cscore DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cscore")
|
||||
|
||||
if (NOT WITHOUT_JAVA AND MSVC)
|
||||
install(TARGETS cscore RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set (cscore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cscore_config_dir share/cscore)
|
||||
endif()
|
||||
|
||||
install(FILES cscore-config.cmake DESTINATION ${cscore_config_dir})
|
||||
install(EXPORT cscore DESTINATION ${cscore_config_dir})
|
||||
|
||||
SUBDIR_LIST(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
|
||||
foreach(example ${cscore_examples})
|
||||
file(GLOB cscore_example_src examples/${example}/*.cpp)
|
||||
if(cscore_example_src)
|
||||
add_executable(cscore_${example} ${cscore_example_src})
|
||||
target_link_libraries(cscore_${example} cscore)
|
||||
if (MSVC)
|
||||
install(TARGETS cscorejni RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
install(TARGETS cscorejni EXPORT cscorejni DESTINATION "${main_lib_dest}")
|
||||
|
||||
endif()
|
||||
|
||||
@@ -31,6 +31,39 @@ ext {
|
||||
srcDirs 'src/main/native/include'
|
||||
}
|
||||
}
|
||||
cscoreMacCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/osx'
|
||||
include '**/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDirs 'src/main/native/include', 'src/main/native/cpp'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (it.targetPlatform.operatingSystem.name == 'linux') {
|
||||
it.sources {
|
||||
cscoreLinuxCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/linux'
|
||||
include '**/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDirs 'src/main/native/include', 'src/main/native/cpp'
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (it.targetPlatform.operatingSystem.name == 'windows') {
|
||||
it.sources {
|
||||
cscoreWindowsCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/windows'
|
||||
include '**/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDirs 'src/main/native/include', 'src/main/native/cpp'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,17 +71,15 @@ ext {
|
||||
|
||||
def examplesMap = [:];
|
||||
|
||||
if (OperatingSystem.current().isLinux()) {
|
||||
File examplesTree = file("$projectDir/examples")
|
||||
examplesTree.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File current, String name) {
|
||||
return new File(current, name).isDirectory();
|
||||
}
|
||||
}).each {
|
||||
sharedCvConfigs.put(it, [])
|
||||
examplesMap.put(it, [])
|
||||
File examplesTree = file("$projectDir/examples")
|
||||
examplesTree.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File current, String name) {
|
||||
return new File(current, name).isDirectory();
|
||||
}
|
||||
}).each {
|
||||
sharedCvConfigs.put(it, [])
|
||||
examplesMap.put(it, [])
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/opencv.gradle"
|
||||
@@ -69,30 +100,11 @@ model {
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure']
|
||||
}
|
||||
cscoreJNI(ExportsConfig) {
|
||||
x86SymbolFilter = { symbols ->
|
||||
def retList = []
|
||||
symbols.each { symbol ->
|
||||
if (symbol.startsWith('CS_') || symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
|
||||
retList << symbol
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
x64SymbolFilter = { symbols ->
|
||||
def retList = []
|
||||
symbols.each { symbol ->
|
||||
if (symbol.startsWith('CS_') || symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
|
||||
retList << symbol
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
}
|
||||
}
|
||||
components {
|
||||
examplesMap.each { key, value ->
|
||||
"${key}"(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
binaries.all {
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
lib library: 'cscore', linkage: 'shared'
|
||||
|
||||
@@ -24,7 +24,7 @@ public class CameraServerJNI {
|
||||
static {
|
||||
if (!libraryLoaded) {
|
||||
try {
|
||||
loader = new RuntimeLoader<>("cscore", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
|
||||
loader = new RuntimeLoader<>("cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
|
||||
loader.loadLibrary();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "c_util.h"
|
||||
@@ -20,14 +21,17 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name) : SinkImpl{name} {
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {
|
||||
m_active = true;
|
||||
// m_thread = std::thread(&CvSinkImpl::ThreadMain, this);
|
||||
}
|
||||
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name,
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name} {}
|
||||
: SinkImpl{name, logger, notifier, telemetry} {}
|
||||
|
||||
CvSinkImpl::~CvSinkImpl() { Stop(); }
|
||||
|
||||
@@ -119,24 +123,24 @@ void CvSinkImpl::ThreadMain() {
|
||||
namespace cs {
|
||||
|
||||
CS_Sink CreateCvSink(const wpi::Twine& name, CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name);
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_CV, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSink(
|
||||
CS_SINK_CV, std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
|
||||
inst.telemetry));
|
||||
}
|
||||
|
||||
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name, processFrame);
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_CV, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSink(
|
||||
CS_SINK_CV, std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
|
||||
inst.telemetry, processFrame));
|
||||
}
|
||||
|
||||
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -145,7 +149,7 @@ void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -155,7 +159,7 @@ uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -164,7 +168,7 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
}
|
||||
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -174,7 +178,7 @@ std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -183,7 +187,7 @@ wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
|
||||
@@ -8,20 +8,17 @@
|
||||
#ifndef CSCORE_CVSINKIMPL_H_
|
||||
#define CSCORE_CVSINKIMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/NetworkAcceptor.h>
|
||||
#include <wpi/NetworkStream.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/raw_istream.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
#include <wpi/raw_socket_ostream.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "SinkImpl.h"
|
||||
|
||||
namespace cs {
|
||||
@@ -30,8 +27,10 @@ class SourceImpl;
|
||||
|
||||
class CvSinkImpl : public SinkImpl {
|
||||
public:
|
||||
explicit CvSinkImpl(const wpi::Twine& name);
|
||||
CvSinkImpl(const wpi::Twine& name,
|
||||
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry);
|
||||
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
~CvSinkImpl() override;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "c_util.h"
|
||||
@@ -21,15 +22,21 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, const VideoMode& mode)
|
||||
: SourceImpl{name} {
|
||||
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const VideoMode& mode)
|
||||
: SourceImpl{name, logger, notifier, telemetry} {
|
||||
m_mode = mode;
|
||||
m_videoModes.push_back(m_mode);
|
||||
}
|
||||
|
||||
CvSourceImpl::~CvSourceImpl() {}
|
||||
|
||||
void CvSourceImpl::Start() {}
|
||||
void CvSourceImpl::Start() {
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
|
||||
bool CvSourceImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
|
||||
{
|
||||
@@ -37,7 +44,7 @@ bool CvSourceImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
|
||||
m_mode = mode;
|
||||
m_videoModes[0] = mode;
|
||||
}
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, mode);
|
||||
m_notifier.NotifySourceVideoMode(*this, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,8 +112,8 @@ int CvSourceImpl::CreateProperty(const wpi::Twine& name, CS_PropertyKind kind,
|
||||
prop.defaultValue = defaultValue;
|
||||
value = prop.value;
|
||||
});
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, ndx, kind, value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
|
||||
kind, value, wpi::Twine{});
|
||||
return ndx;
|
||||
}
|
||||
|
||||
@@ -132,29 +139,23 @@ void CvSourceImpl::SetEnumPropertyChoices(int property,
|
||||
return;
|
||||
}
|
||||
prop->enumChoices = choices;
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED, prop->name, property,
|
||||
CS_PROP_ENUM, prop->value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop->name, property, CS_PROP_ENUM,
|
||||
prop->value, wpi::Twine{});
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Source CreateCvSource(const wpi::Twine& name, const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
auto source = std::make_shared<CvSourceImpl>(name, mode);
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_CV, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
// Generate initial events here so they come after the source created event
|
||||
source->Start(); // causes a property event
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CONNECTED);
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
notifier.NotifySourceVideoMode(*source, mode);
|
||||
return handle;
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSource(CS_SOURCE_CV, std::make_shared<CvSourceImpl>(
|
||||
name, inst.logger, inst.notifier,
|
||||
inst.telemetry, mode));
|
||||
}
|
||||
|
||||
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -164,7 +165,7 @@ void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
|
||||
|
||||
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -173,7 +174,7 @@ void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
}
|
||||
|
||||
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -183,7 +184,7 @@ void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
|
||||
void SetSourceDescription(CS_Source source, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -195,7 +196,7 @@ CS_Property CreateSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
CS_PropertyKind kind, int minimum, int maximum,
|
||||
int step, int defaultValue, int value,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
@@ -210,7 +211,7 @@ CS_Property CreateSourcePropertyCallback(
|
||||
CS_Source source, const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
@@ -224,7 +225,7 @@ CS_Property CreateSourcePropertyCallback(
|
||||
void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -237,7 +238,7 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
auto data2 = Sources::GetInstance().Get(Handle{i, Handle::kSource});
|
||||
auto data2 = Instance::GetInstance().GetSource(Handle{i, Handle::kSource});
|
||||
if (!data2 || data->source.get() != data2->source.get()) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
|
||||
@@ -14,16 +14,21 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class CvSourceImpl : public SourceImpl {
|
||||
public:
|
||||
CvSourceImpl(const wpi::Twine& name, const VideoMode& mode);
|
||||
CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const VideoMode& mode);
|
||||
~CvSourceImpl() override;
|
||||
|
||||
void Start();
|
||||
void Start() override;
|
||||
|
||||
bool SetVideoMode(const VideoMode& mode, CS_Status* status) override;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
@@ -450,9 +451,11 @@ Image* Frame::GetImageImpl(int width, int height,
|
||||
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality))
|
||||
return cur;
|
||||
|
||||
DEBUG4("converting image from "
|
||||
<< cur->width << "x" << cur->height << " type " << cur->pixelFormat
|
||||
<< " to " << width << "x" << height << " type " << pixelFormat);
|
||||
WPI_DEBUG4(Instance::GetInstance().logger,
|
||||
"converting image from " << cur->width << "x" << cur->height
|
||||
<< " type " << cur->pixelFormat << " to "
|
||||
<< width << "x" << height << " type "
|
||||
<< pixelFormat);
|
||||
|
||||
// If the source image is a JPEG, we need to decode it before we can do
|
||||
// anything else with it. Note that if the destination format is JPEG, we
|
||||
|
||||
@@ -8,20 +8,10 @@
|
||||
#ifndef CSCORE_HANDLE_H_
|
||||
#define CSCORE_HANDLE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/StringRef.h>
|
||||
|
||||
#include "UnlimitedHandleResource.h"
|
||||
#include "cscore_c.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SinkImpl;
|
||||
class SourceImpl;
|
||||
|
||||
// Handle data layout:
|
||||
// Bits 0-15: Handle index
|
||||
// Bits 16-23: Parent index (property only)
|
||||
@@ -74,59 +64,6 @@ class Handle {
|
||||
CS_Handle m_handle;
|
||||
};
|
||||
|
||||
struct SourceData {
|
||||
SourceData(CS_SourceKind kind_, std::shared_ptr<SourceImpl> source_)
|
||||
: kind{kind_}, refCount{0}, source{source_} {}
|
||||
|
||||
CS_SourceKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::shared_ptr<SourceImpl> source;
|
||||
};
|
||||
|
||||
class Sources
|
||||
: public UnlimitedHandleResource<Handle, SourceData, Handle::kSource> {
|
||||
public:
|
||||
static Sources& GetInstance() {
|
||||
static Sources instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> Find(
|
||||
const SourceImpl& source) {
|
||||
return FindIf(
|
||||
[&](const SourceData& data) { return data.source.get() == &source; });
|
||||
}
|
||||
|
||||
private:
|
||||
Sources() = default;
|
||||
};
|
||||
|
||||
struct SinkData {
|
||||
explicit SinkData(CS_SinkKind kind_, std::shared_ptr<SinkImpl> sink_)
|
||||
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
|
||||
|
||||
CS_SinkKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::atomic<CS_Source> sourceHandle;
|
||||
std::shared_ptr<SinkImpl> sink;
|
||||
};
|
||||
|
||||
class Sinks : public UnlimitedHandleResource<Handle, SinkData, Handle::kSink> {
|
||||
public:
|
||||
static Sinks& GetInstance() {
|
||||
static Sinks instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> Find(const SinkImpl& sink) {
|
||||
return FindIf(
|
||||
[&](const SinkData& data) { return data.sink.get() == &sink; });
|
||||
}
|
||||
|
||||
private:
|
||||
Sinks() = default;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_HANDLE_H_
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
@@ -21,8 +22,10 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
HttpCameraImpl::HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind)
|
||||
: SourceImpl{name}, m_kind{kind} {}
|
||||
HttpCameraImpl::HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
|
||||
wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry)
|
||||
: SourceImpl{name, logger, notifier, telemetry}, m_kind{kind} {}
|
||||
|
||||
HttpCameraImpl::~HttpCameraImpl() {
|
||||
m_active = false;
|
||||
@@ -53,15 +56,6 @@ void HttpCameraImpl::Start() {
|
||||
m_settingsThread = std::thread(&HttpCameraImpl::SettingsThreadMain, this);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static inline void DoFdSet(int fd, fd_set* set, int* nfds) {
|
||||
if (fd >= 0) {
|
||||
FD_SET(fd, set);
|
||||
if ((fd + 1) > *nfds) *nfds = fd + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void HttpCameraImpl::StreamThreadMain() {
|
||||
while (m_active) {
|
||||
SetConnected(false);
|
||||
@@ -115,8 +109,8 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
auto stream = wpi::TCPConnector::connect(req.host.c_str(), req.port,
|
||||
Logger::GetInstance(), 1);
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return nullptr;
|
||||
|
||||
@@ -277,8 +271,8 @@ void HttpCameraImpl::SettingsThreadMain() {
|
||||
|
||||
void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
|
||||
// Try to connect
|
||||
auto stream = wpi::TCPConnector::connect(req.host.c_str(), req.port,
|
||||
Logger::GetInstance(), 1);
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return;
|
||||
|
||||
@@ -341,9 +335,9 @@ void HttpCameraImpl::CreateProperty(const wpi::Twine& name,
|
||||
name, httpParam, viaSettings, kind, minimum, maximum, step, defaultValue,
|
||||
value));
|
||||
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, m_propertyData.size() + 1, kind,
|
||||
value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
|
||||
m_propertyData.size() + 1, kind, value,
|
||||
wpi::Twine{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -359,12 +353,12 @@ void HttpCameraImpl::CreateEnumProperty(
|
||||
enumChoices.clear();
|
||||
for (const auto& choice : choices) enumChoices.emplace_back(choice);
|
||||
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, m_propertyData.size() + 1,
|
||||
CS_PROP_ENUM, value, wpi::Twine{});
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED, name,
|
||||
m_propertyData.size() + 1, CS_PROP_ENUM, value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
|
||||
m_propertyData.size() + 1, CS_PROP_ENUM,
|
||||
value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
name, m_propertyData.size() + 1, CS_PROP_ENUM,
|
||||
value, wpi::Twine{});
|
||||
}
|
||||
|
||||
std::unique_ptr<PropertyImpl> HttpCameraImpl::CreateEmptyProperty(
|
||||
@@ -475,41 +469,38 @@ namespace cs {
|
||||
|
||||
CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
|
||||
CS_HttpCameraKind kind, CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
std::shared_ptr<HttpCameraImpl> source;
|
||||
switch (kind) {
|
||||
case CS_HTTP_AXIS:
|
||||
source = std::make_shared<AxisCameraImpl>(name);
|
||||
source = std::make_shared<AxisCameraImpl>(name, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
break;
|
||||
default:
|
||||
source = std::make_shared<HttpCameraImpl>(name, kind);
|
||||
source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
break;
|
||||
}
|
||||
if (!source->SetUrls(url.str(), status)) return 0;
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_HTTP, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
source->Start();
|
||||
return handle;
|
||||
return inst.CreateSource(CS_SOURCE_HTTP, source);
|
||||
}
|
||||
|
||||
CS_Source CreateHttpCamera(const wpi::Twine& name,
|
||||
wpi::ArrayRef<std::string> urls,
|
||||
CS_HttpCameraKind kind, CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
if (urls.empty()) {
|
||||
*status = CS_EMPTY_VALUE;
|
||||
return 0;
|
||||
}
|
||||
auto source = std::make_shared<HttpCameraImpl>(name, kind);
|
||||
auto source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
if (!source->SetUrls(urls, status)) return 0;
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_HTTP, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
source->Start();
|
||||
return handle;
|
||||
return inst.CreateSource(CS_SOURCE_HTTP, source);
|
||||
}
|
||||
|
||||
CS_HttpCameraKind GetHttpCameraKind(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_HTTP_UNKNOWN;
|
||||
@@ -523,7 +514,7 @@ void SetHttpCameraUrls(CS_Source source, wpi::ArrayRef<std::string> urls,
|
||||
*status = CS_EMPTY_VALUE;
|
||||
return;
|
||||
}
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -533,7 +524,7 @@ void SetHttpCameraUrls(CS_Source source, wpi::ArrayRef<std::string> urls,
|
||||
|
||||
std::vector<std::string> GetHttpCameraUrls(CS_Source source,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<std::string>{};
|
||||
|
||||
@@ -30,10 +30,11 @@ namespace cs {
|
||||
|
||||
class HttpCameraImpl : public SourceImpl {
|
||||
public:
|
||||
HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind);
|
||||
HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
|
||||
wpi::Logger& logger, Notifier& notifier, Telemetry& telemetry);
|
||||
~HttpCameraImpl() override;
|
||||
|
||||
void Start();
|
||||
void Start() override;
|
||||
|
||||
// Property functions
|
||||
void SetProperty(int property, int value, CS_Status* status) override;
|
||||
@@ -140,8 +141,9 @@ class HttpCameraImpl : public SourceImpl {
|
||||
|
||||
class AxisCameraImpl : public HttpCameraImpl {
|
||||
public:
|
||||
explicit AxisCameraImpl(const wpi::Twine& name)
|
||||
: HttpCameraImpl{name, CS_HTTP_AXIS} {}
|
||||
AxisCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: HttpCameraImpl{name, CS_HTTP_AXIS, logger, notifier, telemetry} {}
|
||||
#if 0
|
||||
void SetProperty(int property, int value, CS_Status* status) override;
|
||||
void SetStringProperty(int property, const wpi::Twine& value,
|
||||
|
||||
97
cscore/src/main/native/cpp/Instance.cpp
Normal file
97
cscore/src/main/native/cpp/Instance.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Instance.h"
|
||||
|
||||
#include <wpi/Path.h>
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
using namespace cs;
|
||||
|
||||
static void def_log_func(unsigned int level, const char* file,
|
||||
unsigned int line, const char* msg) {
|
||||
wpi::SmallString<128> buf;
|
||||
wpi::raw_svector_ostream oss(buf);
|
||||
if (level == 20) {
|
||||
oss << "CS: " << msg << '\n';
|
||||
wpi::errs() << oss.str();
|
||||
return;
|
||||
}
|
||||
|
||||
wpi::StringRef levelmsg;
|
||||
if (level >= 50)
|
||||
levelmsg = "CRITICAL: ";
|
||||
else if (level >= 40)
|
||||
levelmsg = "ERROR: ";
|
||||
else if (level >= 30)
|
||||
levelmsg = "WARNING: ";
|
||||
else
|
||||
return;
|
||||
oss << "CS: " << levelmsg << msg << " (" << wpi::sys::path::filename(file)
|
||||
<< ':' << line << ")\n";
|
||||
wpi::errs() << oss.str();
|
||||
}
|
||||
|
||||
Instance::Instance() : telemetry(notifier), networkListener(logger, notifier) {
|
||||
SetDefaultLogger();
|
||||
}
|
||||
|
||||
Instance::~Instance() {}
|
||||
|
||||
Instance& Instance::GetInstance() {
|
||||
static Instance* inst = new Instance;
|
||||
return *inst;
|
||||
}
|
||||
|
||||
void Instance::Shutdown() {
|
||||
eventLoop.Stop();
|
||||
m_sinks.FreeAll();
|
||||
m_sources.FreeAll();
|
||||
networkListener.Stop();
|
||||
telemetry.Stop();
|
||||
notifier.Stop();
|
||||
}
|
||||
|
||||
void Instance::SetDefaultLogger() { logger.SetLogger(def_log_func); }
|
||||
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> Instance::FindSource(
|
||||
const SourceImpl& source) {
|
||||
return m_sources.FindIf(
|
||||
[&](const SourceData& data) { return data.source.get() == &source; });
|
||||
}
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> Instance::FindSink(
|
||||
const SinkImpl& sink) {
|
||||
return m_sinks.FindIf(
|
||||
[&](const SinkData& data) { return data.sink.get() == &sink; });
|
||||
}
|
||||
|
||||
CS_Source Instance::CreateSource(CS_SourceKind kind,
|
||||
std::shared_ptr<SourceImpl> source) {
|
||||
auto handle = m_sources.Allocate(kind, source);
|
||||
notifier.NotifySource(source->GetName(), handle, CS_SOURCE_CREATED);
|
||||
source->Start();
|
||||
return handle;
|
||||
}
|
||||
|
||||
CS_Sink Instance::CreateSink(CS_SinkKind kind, std::shared_ptr<SinkImpl> sink) {
|
||||
auto handle = m_sinks.Allocate(kind, sink);
|
||||
notifier.NotifySink(sink->GetName(), handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Instance::DestroySource(CS_Source handle) {
|
||||
if (auto data = m_sources.Free(handle))
|
||||
notifier.NotifySource(data->source->GetName(), handle, CS_SOURCE_DESTROYED);
|
||||
}
|
||||
|
||||
void Instance::DestroySink(CS_Sink handle) {
|
||||
if (auto data = m_sinks.Free(handle))
|
||||
notifier.NotifySink(data->sink->GetName(), handle, CS_SINK_DESTROYED);
|
||||
}
|
||||
115
cscore/src/main/native/cpp/Instance.h
Normal file
115
cscore/src/main/native/cpp/Instance.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CSCORE_INSTANCE_H_
|
||||
#define CSCORE_INSTANCE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/EventLoopRunner.h>
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
#include "Log.h"
|
||||
#include "NetworkListener.h"
|
||||
#include "Notifier.h"
|
||||
#include "SinkImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "Telemetry.h"
|
||||
#include "UnlimitedHandleResource.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
struct SourceData {
|
||||
SourceData(CS_SourceKind kind_, std::shared_ptr<SourceImpl> source_)
|
||||
: kind{kind_}, refCount{0}, source{source_} {}
|
||||
|
||||
CS_SourceKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::shared_ptr<SourceImpl> source;
|
||||
};
|
||||
|
||||
struct SinkData {
|
||||
explicit SinkData(CS_SinkKind kind_, std::shared_ptr<SinkImpl> sink_)
|
||||
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
|
||||
|
||||
CS_SinkKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::atomic<CS_Source> sourceHandle;
|
||||
std::shared_ptr<SinkImpl> sink;
|
||||
};
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
Instance(const Instance&) = delete;
|
||||
Instance& operator=(const Instance&) = delete;
|
||||
~Instance();
|
||||
|
||||
static Instance& GetInstance();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
wpi::Logger logger;
|
||||
Notifier notifier;
|
||||
Telemetry telemetry;
|
||||
NetworkListener networkListener;
|
||||
|
||||
private:
|
||||
UnlimitedHandleResource<Handle, SourceData, Handle::kSource> m_sources;
|
||||
UnlimitedHandleResource<Handle, SinkData, Handle::kSink> m_sinks;
|
||||
|
||||
public:
|
||||
wpi::EventLoopRunner eventLoop;
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> FindSink(const SinkImpl& sink);
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> FindSource(
|
||||
const SourceImpl& source);
|
||||
|
||||
void SetDefaultLogger();
|
||||
|
||||
std::shared_ptr<SourceData> GetSource(CS_Source handle) {
|
||||
return m_sources.Get(handle);
|
||||
}
|
||||
|
||||
std::shared_ptr<SinkData> GetSink(CS_Sink handle) {
|
||||
return m_sinks.Get(handle);
|
||||
}
|
||||
|
||||
CS_Source CreateSource(CS_SourceKind kind,
|
||||
std::shared_ptr<SourceImpl> source);
|
||||
|
||||
CS_Sink CreateSink(CS_SinkKind kind, std::shared_ptr<SinkImpl> sink);
|
||||
|
||||
void DestroySource(CS_Source handle);
|
||||
void DestroySink(CS_Sink handle);
|
||||
|
||||
wpi::ArrayRef<CS_Source> EnumerateSourceHandles(
|
||||
wpi::SmallVectorImpl<CS_Source>& vec) {
|
||||
return m_sources.GetAll(vec);
|
||||
}
|
||||
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSinkHandles(
|
||||
wpi::SmallVectorImpl<CS_Sink>& vec) {
|
||||
return m_sinks.GetAll(vec);
|
||||
}
|
||||
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSourceSinks(
|
||||
CS_Source source, wpi::SmallVectorImpl<CS_Sink>& vec) {
|
||||
vec.clear();
|
||||
m_sinks.ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
|
||||
if (source == data.sourceHandle.load()) vec.push_back(sinkHandle);
|
||||
});
|
||||
return vec;
|
||||
}
|
||||
|
||||
private:
|
||||
Instance();
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_INSTANCE_H_
|
||||
@@ -1,45 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include <wpi/Path.h>
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
using namespace cs;
|
||||
|
||||
static void def_log_func(unsigned int level, const char* file,
|
||||
unsigned int line, const char* msg) {
|
||||
wpi::SmallString<128> buf;
|
||||
wpi::raw_svector_ostream oss(buf);
|
||||
if (level == 20) {
|
||||
oss << "CS: " << msg << '\n';
|
||||
wpi::errs() << oss.str();
|
||||
return;
|
||||
}
|
||||
|
||||
wpi::StringRef levelmsg;
|
||||
if (level >= 50)
|
||||
levelmsg = "CRITICAL: ";
|
||||
else if (level >= 40)
|
||||
levelmsg = "ERROR: ";
|
||||
else if (level >= 30)
|
||||
levelmsg = "WARNING: ";
|
||||
else
|
||||
return;
|
||||
oss << "CS: " << levelmsg << msg << " (" << wpi::sys::path::filename(file)
|
||||
<< ':' << line << ")\n";
|
||||
wpi::errs() << oss.str();
|
||||
}
|
||||
|
||||
Logger::Logger() { SetDefaultLogger(); }
|
||||
|
||||
Logger::~Logger() {}
|
||||
|
||||
void Logger::SetDefaultLogger() { SetLogger(def_log_func); }
|
||||
@@ -10,34 +10,18 @@
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Logger : public wpi::Logger {
|
||||
public:
|
||||
static Logger& GetInstance() {
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
~Logger();
|
||||
|
||||
void SetDefaultLogger();
|
||||
|
||||
private:
|
||||
Logger();
|
||||
};
|
||||
|
||||
#define LOG(level, x) WPI_LOG(cs::Logger::GetInstance(), level, x)
|
||||
#define LOG(level, x) WPI_LOG(m_logger, level, x)
|
||||
|
||||
#undef ERROR
|
||||
#define ERROR(x) WPI_ERROR(cs::Logger::GetInstance(), x)
|
||||
#define WARNING(x) WPI_WARNING(cs::Logger::GetInstance(), x)
|
||||
#define INFO(x) WPI_INFO(cs::Logger::GetInstance(), x)
|
||||
#define ERROR(x) WPI_ERROR(m_logger, x)
|
||||
#define WARNING(x) WPI_WARNING(m_logger, x)
|
||||
#define INFO(x) WPI_INFO(m_logger, x)
|
||||
|
||||
#define DEBUG(x) WPI_DEBUG(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG1(x) WPI_DEBUG1(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG2(x) WPI_DEBUG2(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG3(x) WPI_DEBUG3(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG4(x) WPI_DEBUG4(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG(x) WPI_DEBUG(m_logger, x)
|
||||
#define DEBUG1(x) WPI_DEBUG1(m_logger, x)
|
||||
#define DEBUG2(x) WPI_DEBUG2(m_logger, x)
|
||||
#define DEBUG3(x) WPI_DEBUG3(m_logger, x)
|
||||
#define DEBUG4(x) WPI_DEBUG4(m_logger, x)
|
||||
|
||||
#define SERROR(x) ERROR(GetName() << ": " << x)
|
||||
#define SWARNING(x) WARNING(GetName() << ": " << x)
|
||||
@@ -49,6 +33,4 @@ class Logger : public wpi::Logger {
|
||||
#define SDEBUG3(x) DEBUG3(GetName() << ": " << x)
|
||||
#define SDEBUG4(x) DEBUG4(GetName() << ": " << x)
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_LOG_H_
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <wpi/raw_socket_ostream.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
@@ -73,7 +74,8 @@ static const char* endRootPage = "</div></body></html>";
|
||||
|
||||
class MjpegServerImpl::ConnThread : public wpi::SafeThread {
|
||||
public:
|
||||
explicit ConnThread(const wpi::Twine& name) : m_name(name.str()) {}
|
||||
explicit ConnThread(const wpi::Twine& name, wpi::Logger& logger)
|
||||
: m_name(name.str()), m_logger(logger) {}
|
||||
|
||||
void Main();
|
||||
|
||||
@@ -97,6 +99,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
wpi::Logger& m_logger;
|
||||
|
||||
wpi::StringRef GetName() { return m_name; }
|
||||
|
||||
@@ -548,10 +551,11 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
|
||||
os.flush();
|
||||
}
|
||||
|
||||
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name,
|
||||
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor> acceptor)
|
||||
: SinkImpl{name},
|
||||
: SinkImpl{name, logger, notifier, telemetry},
|
||||
m_listenAddress(listenAddress.str()),
|
||||
m_port(port),
|
||||
m_acceptor{std::move(acceptor)} {
|
||||
@@ -865,7 +869,7 @@ void MjpegServerImpl::ServerThreadMain() {
|
||||
}
|
||||
|
||||
// Start it if not already started
|
||||
it->Start(GetName());
|
||||
it->Start(GetName(), m_logger);
|
||||
|
||||
auto nstreams =
|
||||
std::count_if(m_connThreads.begin(), m_connThreads.end(),
|
||||
@@ -909,20 +913,20 @@ namespace cs {
|
||||
CS_Sink CreateMjpegServer(const wpi::Twine& name,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
wpi::SmallString<128> listenAddressBuf;
|
||||
auto sink = std::make_shared<MjpegServerImpl>(
|
||||
name, listenAddress, port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
|
||||
port,
|
||||
listenAddress.toNullTerminatedStringRef(listenAddressBuf).data(),
|
||||
Logger::GetInstance())));
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_MJPEG, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
return inst.CreateSink(
|
||||
CS_SINK_MJPEG,
|
||||
std::make_shared<MjpegServerImpl>(
|
||||
name, inst.logger, inst.notifier, inst.telemetry, listenAddress, port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
|
||||
port,
|
||||
listenAddress.toNullTerminatedStringRef(listenAddressBuf).data(),
|
||||
inst.logger))));
|
||||
}
|
||||
|
||||
std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_MJPEG) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -931,7 +935,7 @@ std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {
|
||||
}
|
||||
|
||||
int GetMjpegServerPort(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_MJPEG) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
|
||||
@@ -31,8 +31,10 @@ class SourceImpl;
|
||||
|
||||
class MjpegServerImpl : public SinkImpl {
|
||||
public:
|
||||
MjpegServerImpl(const wpi::Twine& name, const wpi::Twine& listenAddress,
|
||||
int port, std::unique_ptr<wpi::NetworkAcceptor> acceptor);
|
||||
MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor> acceptor);
|
||||
~MjpegServerImpl() override;
|
||||
|
||||
void Stop();
|
||||
|
||||
@@ -8,26 +8,25 @@
|
||||
#ifndef CSCORE_NETWORKLISTENER_H_
|
||||
#define CSCORE_NETWORKLISTENER_H_
|
||||
|
||||
#include <wpi/SafeThread.h>
|
||||
#include <memory>
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
|
||||
class NetworkListener {
|
||||
public:
|
||||
static NetworkListener& GetInstance() {
|
||||
static NetworkListener instance;
|
||||
return instance;
|
||||
}
|
||||
NetworkListener(wpi::Logger& logger, Notifier& notifier);
|
||||
~NetworkListener();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
NetworkListener() = default;
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "SinkImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
@@ -157,7 +158,7 @@ void Notifier::NotifySource(const wpi::Twine& name, CS_Source source,
|
||||
}
|
||||
|
||||
void Notifier::NotifySource(const SourceImpl& source, CS_EventKind kind) {
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
NotifySource(source.GetName(), handleData.first, kind);
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ void Notifier::NotifySourceVideoMode(const SourceImpl& source,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
thr->m_notifications.emplace(source.GetName(), handleData.first, mode);
|
||||
thr->m_cond.notify_one();
|
||||
@@ -179,7 +180,7 @@ void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
thr->m_notifications.emplace(
|
||||
propertyName, handleData.first, static_cast<RawEvent::Kind>(kind),
|
||||
@@ -198,7 +199,7 @@ void Notifier::NotifySink(const wpi::Twine& name, CS_Sink sink,
|
||||
}
|
||||
|
||||
void Notifier::NotifySink(const SinkImpl& sink, CS_EventKind kind) {
|
||||
auto handleData = Sinks::GetInstance().Find(sink);
|
||||
auto handleData = Instance::GetInstance().FindSink(sink);
|
||||
NotifySink(sink.GetName(), handleData.first, kind);
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ void Notifier::NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sinks::GetInstance().Find(sink);
|
||||
auto handleData = Instance::GetInstance().FindSink(sink);
|
||||
|
||||
thr->m_notifications.emplace(
|
||||
propertyName, handleData.first, static_cast<RawEvent::Kind>(kind),
|
||||
|
||||
@@ -23,10 +23,7 @@ class Notifier {
|
||||
friend class NotifierTest;
|
||||
|
||||
public:
|
||||
static Notifier& GetInstance() {
|
||||
static Notifier instance;
|
||||
return instance;
|
||||
}
|
||||
Notifier();
|
||||
~Notifier();
|
||||
|
||||
void Start();
|
||||
@@ -62,8 +59,6 @@ class Notifier {
|
||||
void NotifyTelemetryUpdated();
|
||||
|
||||
private:
|
||||
Notifier();
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
|
||||
|
||||
@@ -7,12 +7,18 @@
|
||||
|
||||
#include "SinkImpl.h"
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Notifier.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
SinkImpl::SinkImpl(const wpi::Twine& name) : m_name{name.str()} {}
|
||||
SinkImpl::SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: m_logger(logger),
|
||||
m_notifier(notifier),
|
||||
m_telemetry(telemetry),
|
||||
m_name{name.str()} {}
|
||||
|
||||
SinkImpl::~SinkImpl() {
|
||||
if (m_source) {
|
||||
@@ -37,7 +43,7 @@ void SinkImpl::Enable() {
|
||||
++m_enabledCount;
|
||||
if (m_enabledCount == 1) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_ENABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +52,7 @@ void SinkImpl::Disable() {
|
||||
--m_enabledCount;
|
||||
if (m_enabledCount == 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_DISABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +61,11 @@ void SinkImpl::SetEnabled(bool enabled) {
|
||||
if (enabled && m_enabledCount == 0) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
m_enabledCount = 1;
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_ENABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
} else if (!enabled && m_enabledCount > 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
m_enabledCount = 0;
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_DISABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,15 +103,14 @@ wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
|
||||
}
|
||||
|
||||
void SinkImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind, prop.value,
|
||||
wpi::Twine{});
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
|
||||
void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
@@ -119,10 +124,11 @@ void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
prop->SetValue(value);
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached)
|
||||
Notifier::GetInstance().NotifySinkProperty(
|
||||
*this, CS_SINK_PROPERTY_VALUE_UPDATED, prop->name, property,
|
||||
prop->propKind, prop->value, prop->valueStr);
|
||||
if (m_properties_cached) {
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_VALUE_UPDATED,
|
||||
prop->name, property, prop->propKind,
|
||||
prop->value, prop->valueStr);
|
||||
}
|
||||
}
|
||||
|
||||
void SinkImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/mutex.h>
|
||||
@@ -20,10 +21,13 @@
|
||||
namespace cs {
|
||||
|
||||
class Frame;
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class SinkImpl : public PropertyContainer {
|
||||
public:
|
||||
explicit SinkImpl(const wpi::Twine& name);
|
||||
explicit SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry);
|
||||
virtual ~SinkImpl();
|
||||
SinkImpl(const SinkImpl& queue) = delete;
|
||||
SinkImpl& operator=(const SinkImpl& queue) = delete;
|
||||
@@ -55,6 +59,11 @@ class SinkImpl : public PropertyContainer {
|
||||
|
||||
virtual void SetSourceImpl(std::shared_ptr<SourceImpl> source);
|
||||
|
||||
protected:
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
Telemetry& m_telemetry;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
|
||||
@@ -21,7 +21,12 @@ using namespace cs;
|
||||
|
||||
static constexpr size_t kMaxImagesAvail = 32;
|
||||
|
||||
SourceImpl::SourceImpl(const wpi::Twine& name) : m_name{name.str()} {
|
||||
SourceImpl::SourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: m_logger(logger),
|
||||
m_notifier(notifier),
|
||||
m_telemetry(telemetry),
|
||||
m_name{name.str()} {
|
||||
m_frame = Frame{*this, wpi::StringRef{}, 0};
|
||||
}
|
||||
|
||||
@@ -53,9 +58,9 @@ wpi::StringRef SourceImpl::GetDescription(
|
||||
void SourceImpl::SetConnected(bool connected) {
|
||||
bool wasConnected = m_connected.exchange(connected);
|
||||
if (wasConnected && !connected)
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_DISCONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_DISCONNECTED);
|
||||
else if (!wasConnected && connected)
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
}
|
||||
|
||||
uint64_t SourceImpl::GetCurFrameTime() {
|
||||
@@ -215,9 +220,8 @@ void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
|
||||
|
||||
void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time) {
|
||||
// Update telemetry
|
||||
Telemetry::GetInstance().RecordSourceFrames(*this, 1);
|
||||
Telemetry::GetInstance().RecordSourceBytes(*this,
|
||||
static_cast<int>(image->size()));
|
||||
m_telemetry.RecordSourceFrames(*this, 1);
|
||||
m_telemetry.RecordSourceBytes(*this, static_cast<int>(image->size()));
|
||||
|
||||
// Update frame
|
||||
{
|
||||
@@ -241,15 +245,14 @@ void SourceImpl::PutError(const wpi::Twine& msg, Frame::Time time) {
|
||||
}
|
||||
|
||||
void SourceImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
|
||||
void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
@@ -263,10 +266,11 @@ void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
prop->SetValue(value);
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached)
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_VALUE_UPDATED, prop->name, property,
|
||||
prop->propKind, prop->value, prop->valueStr);
|
||||
if (m_properties_cached) {
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_VALUE_UPDATED,
|
||||
prop->name, property, prop->propKind,
|
||||
prop->value, prop->valueStr);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
|
||||
|
||||
@@ -15,27 +15,35 @@
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Handle.h"
|
||||
#include "Image.h"
|
||||
#include "PropertyContainer.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class SourceImpl : public PropertyContainer {
|
||||
friend class Frame;
|
||||
|
||||
public:
|
||||
explicit SourceImpl(const wpi::Twine& name);
|
||||
SourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry);
|
||||
virtual ~SourceImpl();
|
||||
SourceImpl(const SourceImpl& oth) = delete;
|
||||
SourceImpl& operator=(const SourceImpl& oth) = delete;
|
||||
|
||||
virtual void Start() = 0;
|
||||
|
||||
wpi::StringRef GetName() const { return m_name; }
|
||||
|
||||
void SetDescription(const wpi::Twine& description);
|
||||
@@ -146,6 +154,10 @@ class SourceImpl : public PropertyContainer {
|
||||
// Current video mode
|
||||
mutable VideoMode m_mode;
|
||||
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
Telemetry& m_telemetry;
|
||||
|
||||
private:
|
||||
void ReleaseImage(std::unique_ptr<Image> image);
|
||||
std::unique_ptr<Frame::Impl> AllocFrameImpl();
|
||||
|
||||
@@ -14,15 +14,20 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Notifier.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class Telemetry::Thread : public wpi::SafeThread {
|
||||
public:
|
||||
explicit Thread(Notifier& notifier) : m_notifier(notifier) {}
|
||||
|
||||
void Main();
|
||||
|
||||
Notifier& m_notifier;
|
||||
wpi::DenseMap<std::pair<CS_Handle, int>, int64_t> m_user;
|
||||
wpi::DenseMap<std::pair<CS_Handle, int>, int64_t> m_current;
|
||||
double m_period = 0.0;
|
||||
@@ -41,11 +46,9 @@ int64_t Telemetry::Thread::GetValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
return it->getSecond();
|
||||
}
|
||||
|
||||
Telemetry::Telemetry() {}
|
||||
|
||||
Telemetry::~Telemetry() {}
|
||||
|
||||
void Telemetry::Start() { m_owner.Start(); }
|
||||
void Telemetry::Start() { m_owner.Start(m_notifier); }
|
||||
|
||||
void Telemetry::Stop() { m_owner.Stop(); }
|
||||
|
||||
@@ -74,7 +77,7 @@ void Telemetry::Thread::Main() {
|
||||
prevTime = curTime;
|
||||
|
||||
// notify
|
||||
Notifier::GetInstance().NotifyTelemetryUpdated();
|
||||
m_notifier.NotifyTelemetryUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +120,7 @@ double Telemetry::GetAverageValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_BYTES_RECEIVED))] +=
|
||||
quantity;
|
||||
@@ -126,7 +129,7 @@ void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
void Telemetry::RecordSourceFrames(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_FRAMES_RECEIVED))] +=
|
||||
quantity;
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class SourceImpl;
|
||||
|
||||
class Telemetry {
|
||||
friend class TelemetryTest;
|
||||
|
||||
public:
|
||||
static Telemetry& GetInstance() {
|
||||
static Telemetry instance;
|
||||
return instance;
|
||||
}
|
||||
explicit Telemetry(Notifier& notifier) : m_notifier(notifier) {}
|
||||
~Telemetry();
|
||||
|
||||
void Start();
|
||||
@@ -41,7 +39,7 @@ class Telemetry {
|
||||
void RecordSourceFrames(const SourceImpl& source, int quantity);
|
||||
|
||||
private:
|
||||
Telemetry();
|
||||
Notifier& m_notifier;
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
|
||||
@@ -50,11 +50,13 @@ class UnlimitedHandleResource {
|
||||
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
|
||||
void Free(THandle handle);
|
||||
std::shared_ptr<TStruct> Free(THandle handle);
|
||||
|
||||
template <typename T>
|
||||
wpi::ArrayRef<T> GetAll(wpi::SmallVectorImpl<T>& vec);
|
||||
|
||||
std::vector<std::shared_ptr<TStruct>> FreeAll();
|
||||
|
||||
// @param func functor with (THandle, const TStruct&) parameters
|
||||
template <typename F>
|
||||
void ForEach(F func);
|
||||
@@ -121,14 +123,17 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Get(
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
inline void UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Free(
|
||||
inline std::shared_ptr<TStruct>
|
||||
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Free(
|
||||
THandle handle) {
|
||||
auto index =
|
||||
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
|
||||
if (index < 0) return;
|
||||
if (index < 0) return nullptr;
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
if (index >= static_cast<int>(m_structures.size())) return;
|
||||
if (index >= static_cast<int>(m_structures.size())) return nullptr;
|
||||
auto rv = std::move(m_structures[index]);
|
||||
m_structures[index].reset();
|
||||
return rv;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
@@ -140,6 +145,15 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::GetAll(
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
inline std::vector<std::shared_ptr<TStruct>>
|
||||
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FreeAll() {
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
auto rv = std::move(m_structures);
|
||||
m_structures.clear();
|
||||
return rv;
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
template <typename F>
|
||||
inline void
|
||||
@@ -163,20 +177,6 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FindIf(F func) {
|
||||
return std::make_pair(0, nullptr);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue,
|
||||
typename TMutex = wpi::mutex>
|
||||
class StaticUnlimitedHandleResource
|
||||
: public UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex> {
|
||||
public:
|
||||
static StaticUnlimitedHandleResource& GetInstance() {
|
||||
static StaticUnlimitedHandleResource instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
StaticUnlimitedHandleResource() = default;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_UNLIMITEDHANDLERESOURCE_H_
|
||||
|
||||
52
cscore/src/main/native/cpp/UsbCameraImplCommon.cpp
Normal file
52
cscore/src/main/native/cpp/UsbCameraImplCommon.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_c.h" // NOLINT(build/include_order)
|
||||
|
||||
#include "c_util.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
extern "C" {
|
||||
|
||||
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) {
|
||||
return cs::CreateUsbCameraDev(name, dev, status);
|
||||
}
|
||||
|
||||
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
|
||||
CS_Status* status) {
|
||||
return cs::CreateUsbCameraPath(name, path, status);
|
||||
}
|
||||
|
||||
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
return ConvertToC(cs::GetUsbCameraPath(source, status));
|
||||
}
|
||||
|
||||
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
|
||||
auto cameras = cs::EnumerateUsbCameras(status);
|
||||
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
|
||||
wpi::CheckedMalloc(cameras.size() * sizeof(CS_UsbCameraInfo)));
|
||||
*count = cameras.size();
|
||||
for (size_t i = 0; i < cameras.size(); ++i) {
|
||||
out[i].dev = cameras[i].dev;
|
||||
out[i].path = ConvertToC(cameras[i].path);
|
||||
out[i].name = ConvertToC(cameras[i].name);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CS_FreeEnumeratedUsbCameras(CS_UsbCameraInfo* cameras, int count) {
|
||||
if (!cameras) return;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::free(cameras[i].path);
|
||||
std::free(cameras[i].name);
|
||||
}
|
||||
std::free(cameras);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -348,6 +348,8 @@ void CS_SetDefaultLogger(unsigned int min_level) {
|
||||
cs::SetDefaultLogger(min_level);
|
||||
}
|
||||
|
||||
void CS_Shutdown(void) { cs::Shutdown(); }
|
||||
|
||||
CS_Source* CS_EnumerateSources(int* count, CS_Status* status) {
|
||||
wpi::SmallVector<CS_Source, 32> buf;
|
||||
auto handles = cs::EnumerateSourceHandles(buf, status);
|
||||
|
||||
@@ -7,16 +7,11 @@
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/hostname.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "NetworkListener.h"
|
||||
#include "Notifier.h"
|
||||
@@ -33,7 +28,7 @@ static std::shared_ptr<PropertyContainer> GetPropertyContainer(
|
||||
Handle handle{propertyHandle};
|
||||
if (handle.IsType(Handle::kProperty)) {
|
||||
int i = handle.GetParentIndex();
|
||||
auto data = Sources::GetInstance().Get(Handle{i, Handle::kSource});
|
||||
auto data = Instance::GetInstance().GetSource(Handle{i, Handle::kSource});
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
@@ -41,7 +36,7 @@ static std::shared_ptr<PropertyContainer> GetPropertyContainer(
|
||||
container = data->source;
|
||||
} else if (handle.IsType(Handle::kSinkProperty)) {
|
||||
int i = handle.GetParentIndex();
|
||||
auto data = Sinks::GetInstance().Get(Handle{i, Handle::kSink});
|
||||
auto data = Instance::GetInstance().GetSink(Handle{i, Handle::kSink});
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
@@ -165,7 +160,7 @@ std::vector<std::string> GetEnumPropertyChoices(CS_Property property,
|
||||
//
|
||||
|
||||
CS_SourceKind GetSourceKind(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_SOURCE_UNKNOWN;
|
||||
@@ -174,7 +169,7 @@ CS_SourceKind GetSourceKind(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
std::string GetSourceName(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -184,7 +179,7 @@ std::string GetSourceName(CS_Source source, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSourceName(CS_Source source, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -193,7 +188,7 @@ wpi::StringRef GetSourceName(CS_Source source, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
std::string GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -205,7 +200,7 @@ std::string GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
wpi::StringRef GetSourceDescription(CS_Source source,
|
||||
wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -214,7 +209,7 @@ wpi::StringRef GetSourceDescription(CS_Source source,
|
||||
}
|
||||
|
||||
uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -225,7 +220,7 @@ uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
void SetSourceConnectionStrategy(CS_Source source,
|
||||
CS_ConnectionStrategy strategy,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -234,7 +229,7 @@ void SetSourceConnectionStrategy(CS_Source source,
|
||||
}
|
||||
|
||||
bool IsSourceConnected(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -243,7 +238,7 @@ bool IsSourceConnected(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
bool IsSourceEnabled(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -253,7 +248,7 @@ bool IsSourceEnabled(CS_Source source, CS_Status* status) {
|
||||
|
||||
CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -269,7 +264,7 @@ CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
wpi::ArrayRef<CS_Property> EnumerateSourceProperties(
|
||||
CS_Source source, wpi::SmallVectorImpl<CS_Property>& vec,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -282,7 +277,7 @@ wpi::ArrayRef<CS_Property> EnumerateSourceProperties(
|
||||
}
|
||||
|
||||
VideoMode GetSourceVideoMode(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return VideoMode{};
|
||||
@@ -292,7 +287,7 @@ VideoMode GetSourceVideoMode(CS_Source source, CS_Status* status) {
|
||||
|
||||
bool SetSourceVideoMode(CS_Source source, const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -302,7 +297,7 @@ bool SetSourceVideoMode(CS_Source source, const VideoMode& mode,
|
||||
|
||||
bool SetSourcePixelFormat(CS_Source source, VideoMode::PixelFormat pixelFormat,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -312,7 +307,7 @@ bool SetSourcePixelFormat(CS_Source source, VideoMode::PixelFormat pixelFormat,
|
||||
|
||||
bool SetSourceResolution(CS_Source source, int width, int height,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -321,7 +316,7 @@ bool SetSourceResolution(CS_Source source, int width, int height,
|
||||
}
|
||||
|
||||
bool SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -331,7 +326,7 @@ bool SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
|
||||
|
||||
std::vector<VideoMode> EnumerateSourceVideoModes(CS_Source source,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<VideoMode>{};
|
||||
@@ -342,21 +337,18 @@ std::vector<VideoMode> EnumerateSourceVideoModes(CS_Source source,
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSourceSinks(CS_Source source,
|
||||
wpi::SmallVectorImpl<CS_Sink>& vec,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::ArrayRef<CS_Sink>{};
|
||||
}
|
||||
vec.clear();
|
||||
Sinks::GetInstance().ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
|
||||
if (source == data.sourceHandle.load()) vec.push_back(sinkHandle);
|
||||
});
|
||||
return vec;
|
||||
return inst.EnumerateSourceSinks(source, vec);
|
||||
}
|
||||
|
||||
CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return 0;
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -367,17 +359,13 @@ CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
|
||||
void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return;
|
||||
auto& inst = Sources::GetInstance();
|
||||
auto data = inst.Get(source);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) {
|
||||
Notifier::GetInstance().NotifySource(data->source->GetName(), source,
|
||||
CS_SOURCE_DESTROYED);
|
||||
inst.Free(source);
|
||||
}
|
||||
if (data->refCount-- == 0) inst.DestroySource(source);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -385,7 +373,7 @@ void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
//
|
||||
|
||||
void SetCameraBrightness(CS_Source source, int brightness, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -394,7 +382,7 @@ void SetCameraBrightness(CS_Source source, int brightness, CS_Status* status) {
|
||||
}
|
||||
|
||||
int GetCameraBrightness(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -403,7 +391,7 @@ int GetCameraBrightness(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraWhiteBalanceAuto(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -412,7 +400,7 @@ void SetCameraWhiteBalanceAuto(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraWhiteBalanceHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -422,7 +410,7 @@ void SetCameraWhiteBalanceHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
|
||||
void SetCameraWhiteBalanceManual(CS_Source source, int value,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -431,7 +419,7 @@ void SetCameraWhiteBalanceManual(CS_Source source, int value,
|
||||
}
|
||||
|
||||
void SetCameraExposureAuto(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -440,7 +428,7 @@ void SetCameraExposureAuto(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraExposureHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -449,7 +437,7 @@ void SetCameraExposureHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraExposureManual(CS_Source source, int value, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -462,7 +450,7 @@ void SetCameraExposureManual(CS_Source source, int value, CS_Status* status) {
|
||||
//
|
||||
|
||||
CS_SinkKind GetSinkKind(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_SINK_UNKNOWN;
|
||||
@@ -471,7 +459,7 @@ CS_SinkKind GetSinkKind(CS_Sink sink, CS_Status* status) {
|
||||
}
|
||||
|
||||
std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -481,7 +469,7 @@ std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -490,7 +478,7 @@ wpi::StringRef GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -501,7 +489,7 @@ std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkDescription(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -511,7 +499,7 @@ wpi::StringRef GetSinkDescription(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
|
||||
CS_Property GetSinkProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -526,7 +514,7 @@ CS_Property GetSinkProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
|
||||
wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
|
||||
CS_Sink sink, wpi::SmallVectorImpl<CS_Property>& vec, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -538,7 +526,7 @@ wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
|
||||
}
|
||||
|
||||
void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -546,7 +534,7 @@ void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
if (source == 0) {
|
||||
data->sink->SetSource(nullptr);
|
||||
} else {
|
||||
auto sourceData = Sources::GetInstance().Get(source);
|
||||
auto sourceData = Instance::GetInstance().GetSource(source);
|
||||
if (!sourceData) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -554,12 +542,12 @@ void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
data->sink->SetSource(sourceData->source);
|
||||
}
|
||||
data->sourceHandle.store(source);
|
||||
Notifier::GetInstance().NotifySinkSourceChanged(data->sink->GetName(), sink,
|
||||
source);
|
||||
Instance::GetInstance().notifier.NotifySinkSourceChanged(
|
||||
data->sink->GetName(), sink, source);
|
||||
}
|
||||
|
||||
CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -569,7 +557,7 @@ CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -579,7 +567,7 @@ CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
|
||||
CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return 0;
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -590,17 +578,13 @@ CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return;
|
||||
auto& inst = Sinks::GetInstance();
|
||||
auto data = inst.Get(sink);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) {
|
||||
Notifier::GetInstance().NotifySink(data->sink->GetName(), sink,
|
||||
CS_SINK_DESTROYED);
|
||||
inst.Free(sink);
|
||||
}
|
||||
if (data->refCount-- == 0) inst.DestroySink(sink);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -608,22 +592,22 @@ void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
//
|
||||
|
||||
void SetListenerOnStart(std::function<void()> onStart) {
|
||||
Notifier::GetInstance().SetOnStart(onStart);
|
||||
Instance::GetInstance().notifier.SetOnStart(onStart);
|
||||
}
|
||||
|
||||
void SetListenerOnExit(std::function<void()> onExit) {
|
||||
Notifier::GetInstance().SetOnExit(onExit);
|
||||
Instance::GetInstance().notifier.SetOnExit(onExit);
|
||||
}
|
||||
|
||||
CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
int eventMask, bool immediateNotify,
|
||||
CS_Status* status) {
|
||||
int uid = Notifier::GetInstance().AddListener(callback, eventMask);
|
||||
auto& inst = Instance::GetInstance();
|
||||
int uid = inst.notifier.AddListener(callback, eventMask);
|
||||
if ((eventMask & CS_NETWORK_INTERFACES_CHANGED) != 0) {
|
||||
// start network interface event listener
|
||||
NetworkListener::GetInstance().Start();
|
||||
if (immediateNotify)
|
||||
Notifier::GetInstance().NotifyNetworkInterfacesChanged();
|
||||
inst.networkListener.Start();
|
||||
if (immediateNotify) inst.notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
if (immediateNotify) {
|
||||
// TODO
|
||||
@@ -637,7 +621,7 @@ void RemoveListener(CS_Listener handle, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
Notifier::GetInstance().RemoveListener(uid);
|
||||
Instance::GetInstance().notifier.RemoveListener(uid);
|
||||
}
|
||||
|
||||
bool NotifierDestroyed() { return Notifier::destroyed(); }
|
||||
@@ -646,86 +630,60 @@ bool NotifierDestroyed() { return Notifier::destroyed(); }
|
||||
// Telemetry Functions
|
||||
//
|
||||
void SetTelemetryPeriod(double seconds) {
|
||||
Telemetry::GetInstance().Start();
|
||||
Telemetry::GetInstance().SetPeriod(seconds);
|
||||
auto& inst = Instance::GetInstance();
|
||||
inst.telemetry.Start();
|
||||
inst.telemetry.SetPeriod(seconds);
|
||||
}
|
||||
|
||||
double GetTelemetryElapsedTime() {
|
||||
return Telemetry::GetInstance().GetElapsedTime();
|
||||
return Instance::GetInstance().telemetry.GetElapsedTime();
|
||||
}
|
||||
|
||||
int64_t GetTelemetryValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
CS_Status* status) {
|
||||
return Telemetry::GetInstance().GetValue(handle, kind, status);
|
||||
return Instance::GetInstance().telemetry.GetValue(handle, kind, status);
|
||||
}
|
||||
|
||||
double GetTelemetryAverageValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
CS_Status* status) {
|
||||
return Telemetry::GetInstance().GetAverageValue(handle, kind, status);
|
||||
return Instance::GetInstance().telemetry.GetAverageValue(handle, kind,
|
||||
status);
|
||||
}
|
||||
|
||||
//
|
||||
// Logging Functions
|
||||
//
|
||||
void SetLogger(LogFunc func, unsigned int min_level) {
|
||||
Logger& logger = Logger::GetInstance();
|
||||
auto& logger = Instance::GetInstance().logger;
|
||||
logger.SetLogger(func);
|
||||
logger.set_min_level(min_level);
|
||||
}
|
||||
|
||||
void SetDefaultLogger(unsigned int min_level) {
|
||||
Logger& logger = Logger::GetInstance();
|
||||
logger.SetDefaultLogger();
|
||||
logger.set_min_level(min_level);
|
||||
auto& inst = Instance::GetInstance();
|
||||
inst.SetDefaultLogger();
|
||||
inst.logger.set_min_level(min_level);
|
||||
}
|
||||
|
||||
//
|
||||
// Shutdown Function
|
||||
//
|
||||
void Shutdown() { Instance::GetInstance().Shutdown(); }
|
||||
|
||||
//
|
||||
// Utility Functions
|
||||
//
|
||||
|
||||
wpi::ArrayRef<CS_Source> EnumerateSourceHandles(
|
||||
wpi::SmallVectorImpl<CS_Source>& vec, CS_Status* status) {
|
||||
return Sources::GetInstance().GetAll(vec);
|
||||
return Instance::GetInstance().EnumerateSourceHandles(vec);
|
||||
}
|
||||
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSinkHandles(wpi::SmallVectorImpl<CS_Sink>& vec,
|
||||
CS_Status* status) {
|
||||
return Sinks::GetInstance().GetAll(vec);
|
||||
return Instance::GetInstance().EnumerateSinkHandles(vec);
|
||||
}
|
||||
|
||||
std::string GetHostname() {
|
||||
#ifdef __linux__
|
||||
char name[256];
|
||||
if (::gethostname(name, sizeof(name)) != 0) return "";
|
||||
name[255] = '\0'; // Per POSIX, may not be null terminated if too long
|
||||
return name;
|
||||
#else
|
||||
return ""; // TODO
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::string> GetNetworkInterfaces() {
|
||||
#ifdef __linux__
|
||||
struct ifaddrs* ifa;
|
||||
if (::getifaddrs(&ifa) != 0) return std::vector<std::string>{};
|
||||
|
||||
std::vector<std::string> rv;
|
||||
char buf[256];
|
||||
for (struct ifaddrs* i = ifa; i; i = i->ifa_next) {
|
||||
if (!i->ifa_addr) continue; // no address
|
||||
if (i->ifa_addr->sa_family != AF_INET) continue; // only return IPv4
|
||||
struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(i->ifa_addr);
|
||||
const char* addr =
|
||||
::inet_ntop(addr_in->sin_family, &addr_in->sin_addr, buf, sizeof(buf));
|
||||
if (!addr) continue; // error converting address
|
||||
rv.emplace_back(addr);
|
||||
}
|
||||
|
||||
::freeifaddrs(ifa);
|
||||
return rv;
|
||||
#else
|
||||
return std::vector<std::string>{}; // TODO
|
||||
#endif
|
||||
}
|
||||
std::string GetHostname() { return wpi::GetHostname(); }
|
||||
|
||||
} // namespace cs
|
||||
|
||||
@@ -87,6 +87,8 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
cs::Shutdown();
|
||||
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
return;
|
||||
@@ -181,7 +183,6 @@ static inline bool CheckStatus(JNIEnv* env, CS_Status status) {
|
||||
return status == CS_OK;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static jobject MakeJObject(JNIEnv* env, const cs::UsbCameraInfo& info) {
|
||||
static jmethodID constructor = env->GetMethodID(
|
||||
usbCameraInfoCls, "<init>", "(ILjava/lang/String;Ljava/lang/String;)V");
|
||||
@@ -190,7 +191,6 @@ static jobject MakeJObject(JNIEnv* env, const cs::UsbCameraInfo& info) {
|
||||
return env->NewObject(usbCameraInfoCls, constructor,
|
||||
static_cast<jint>(info.dev), path.obj(), name.obj());
|
||||
}
|
||||
#endif
|
||||
|
||||
static jobject MakeJObject(JNIEnv* env, const cs::VideoMode& videoMode) {
|
||||
static jmethodID constructor =
|
||||
@@ -406,10 +406,6 @@ JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraDev
|
||||
(JNIEnv* env, jclass, jstring name, jint dev)
|
||||
{
|
||||
#ifndef __linux__
|
||||
unsupportedEx.Throw(env, "USB is not supported yet");
|
||||
return 0;
|
||||
#else
|
||||
if (!name) {
|
||||
nullPointerEx.Throw(env, "name cannot be null");
|
||||
return 0;
|
||||
@@ -418,7 +414,6 @@ Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraDev
|
||||
auto val = cs::CreateUsbCameraDev(JStringRef{env, name}.str(), dev, &status);
|
||||
CheckStatus(env, status);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -430,10 +425,6 @@ JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraPath
|
||||
(JNIEnv* env, jclass, jstring name, jstring path)
|
||||
{
|
||||
#ifndef __linux__
|
||||
unsupportedEx.Throw(env, "USB is not supported yet");
|
||||
return 0;
|
||||
#else
|
||||
if (!name) {
|
||||
nullPointerEx.Throw(env, "name cannot be null");
|
||||
return 0;
|
||||
@@ -447,7 +438,6 @@ Java_edu_wpi_cscore_CameraServerJNI_createUsbCameraPath
|
||||
JStringRef{env, path}.str(), &status);
|
||||
CheckStatus(env, status);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -949,15 +939,10 @@ JNIEXPORT jstring JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_getUsbCameraPath
|
||||
(JNIEnv* env, jclass, jint source)
|
||||
{
|
||||
#ifndef __linux__
|
||||
unsupportedEx.Throw(env, "USB is not supported yet");
|
||||
return 0;
|
||||
#else
|
||||
CS_Status status = 0;
|
||||
auto str = cs::GetUsbCameraPath(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
return MakeJString(env, str);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1582,10 +1567,6 @@ JNIEXPORT jobjectArray JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras
|
||||
(JNIEnv* env, jclass)
|
||||
{
|
||||
#ifndef __linux__
|
||||
unsupportedEx.Throw(env, "USB is not supported yet");
|
||||
return 0;
|
||||
#else
|
||||
CS_Status status = 0;
|
||||
auto arr = cs::EnumerateUsbCameras(&status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
@@ -1597,7 +1578,6 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras
|
||||
env->SetObjectArrayElement(jarr, i, jelem);
|
||||
}
|
||||
return jarr;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -440,6 +440,13 @@ void CS_SetLogger(CS_LogFunc func, unsigned int min_level);
|
||||
void CS_SetDefaultLogger(unsigned int min_level);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cscore_shutdown_cfunc Library Shutdown Function
|
||||
* @{
|
||||
*/
|
||||
void CS_Shutdown(void);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cscore_utility_cfunc Utility Functions
|
||||
* @{
|
||||
|
||||
@@ -377,6 +377,13 @@ void SetLogger(LogFunc func, unsigned int min_level);
|
||||
void SetDefaultLogger(unsigned int min_level);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cscore_shutdown_func Library Shutdown Function
|
||||
* @{
|
||||
*/
|
||||
void Shutdown();
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup cscore_utility_func Utility Functions
|
||||
* @{
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "NetworkListener.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <sys/eventfd.h>
|
||||
@@ -18,42 +17,55 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#endif
|
||||
|
||||
#include <wpi/SafeThread.h>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class NetworkListener::Thread : public wpi::SafeThread {
|
||||
class NetworkListener::Impl {
|
||||
public:
|
||||
void Main();
|
||||
Impl(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_logger(logger), m_notifier(notifier) {}
|
||||
|
||||
#ifdef __linux__
|
||||
int m_command_fd = -1;
|
||||
#endif
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
|
||||
class Thread : public wpi::SafeThread {
|
||||
public:
|
||||
Thread(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_logger(logger), m_notifier(notifier) {}
|
||||
void Main();
|
||||
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
int m_command_fd = -1;
|
||||
};
|
||||
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
};
|
||||
|
||||
NetworkListener::NetworkListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_impl(std::make_unique<Impl>(logger, notifier)) {}
|
||||
|
||||
NetworkListener::~NetworkListener() { Stop(); }
|
||||
|
||||
void NetworkListener::Start() {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) m_owner.Start();
|
||||
m_impl->m_owner.Start(m_impl->m_logger, m_impl->m_notifier);
|
||||
}
|
||||
|
||||
void NetworkListener::Stop() {
|
||||
// Wake up thread
|
||||
if (auto thr = m_owner.GetThread()) {
|
||||
if (auto thr = m_impl->m_owner.GetThread()) {
|
||||
thr->m_active = false;
|
||||
#ifdef __linux__
|
||||
if (thr->m_command_fd >= 0) eventfd_write(thr->m_command_fd, 1);
|
||||
#endif
|
||||
}
|
||||
m_owner.Stop();
|
||||
m_impl->m_owner.Stop();
|
||||
}
|
||||
|
||||
void NetworkListener::Thread::Main() {
|
||||
#ifdef __linux__
|
||||
void NetworkListener::Impl::Thread::Main() {
|
||||
// Create event socket so we can be shut down
|
||||
m_command_fd = ::eventfd(0, 0);
|
||||
if (m_command_fd < 0) {
|
||||
@@ -125,12 +137,11 @@ void NetworkListener::Thread::Main() {
|
||||
if (nh->nlmsg_type == NLMSG_DONE) break;
|
||||
if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK ||
|
||||
nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
|
||||
Notifier::GetInstance().NotifyNetworkInterfacesChanged();
|
||||
m_notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
::close(sd);
|
||||
::close(m_command_fd);
|
||||
m_command_fd = -1;
|
||||
#endif
|
||||
}
|
||||
37
cscore/src/main/native/linux/NetworkUtil.cpp
Normal file
37
cscore/src/main/native/linux/NetworkUtil.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_cpp.h" // NOLINT(build/include_order)
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
std::vector<std::string> GetNetworkInterfaces() {
|
||||
struct ifaddrs* ifa;
|
||||
if (::getifaddrs(&ifa) != 0) return std::vector<std::string>{};
|
||||
|
||||
std::vector<std::string> rv;
|
||||
char buf[256];
|
||||
for (struct ifaddrs* i = ifa; i; i = i->ifa_next) {
|
||||
if (!i->ifa_addr) continue; // no address
|
||||
if (i->ifa_addr->sa_family != AF_INET) continue; // only return IPv4
|
||||
struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(i->ifa_addr);
|
||||
const char* addr =
|
||||
::inet_ntop(addr_in->sin_family, &addr_in->sin_addr, buf, sizeof(buf));
|
||||
if (!addr) continue; // error converting address
|
||||
rv.emplace_back(addr);
|
||||
}
|
||||
|
||||
::freeifaddrs(ifa);
|
||||
return rv;
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
@@ -8,9 +8,7 @@
|
||||
#ifndef CSCORE_USBCAMERABUFFER_H_
|
||||
#define CSCORE_USBCAMERABUFFER_H_
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -29,7 +27,6 @@ class UsbCameraBuffer {
|
||||
UsbCameraBuffer(const UsbCameraBuffer&) = delete;
|
||||
UsbCameraBuffer& operator=(const UsbCameraBuffer&) = delete;
|
||||
|
||||
#ifdef __linux__
|
||||
UsbCameraBuffer(int fd, size_t length, off_t offset) noexcept
|
||||
: m_length{length} {
|
||||
m_data =
|
||||
@@ -43,7 +40,6 @@ class UsbCameraBuffer {
|
||||
~UsbCameraBuffer() {
|
||||
if (m_data) munmap(m_data, m_length);
|
||||
}
|
||||
#endif
|
||||
|
||||
friend void swap(UsbCameraBuffer& first, UsbCameraBuffer& second) noexcept {
|
||||
using std::swap;
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "UsbCameraImpl.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
@@ -22,8 +21,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32)
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -33,18 +30,16 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "Telemetry.h"
|
||||
#include "UsbUtil.h"
|
||||
#include "c_util.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static constexpr char const* kPropWbAuto = "white_balance_temperature_auto";
|
||||
static constexpr char const* kPropWbValue = "white_balance_temperature";
|
||||
static constexpr char const* kPropExAuto = "exposure_auto";
|
||||
@@ -215,14 +210,17 @@ static std::string GetDescriptionImpl(const char* cpath) {
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, const wpi::Twine& path)
|
||||
: SourceImpl{name},
|
||||
UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& path)
|
||||
: SourceImpl{name, logger, notifier, telemetry},
|
||||
m_path{path.str()},
|
||||
m_fd{-1},
|
||||
m_command_fd{eventfd(0, 0)},
|
||||
m_active{true} {
|
||||
SetDescription(GetDescriptionImpl(m_path.c_str()));
|
||||
SetQuirks();
|
||||
|
||||
CreateProperty(kPropConnectVerbose, [] {
|
||||
return std::make_unique<UsbCameraProperty>(kPropConnectVerbose,
|
||||
kPropConnectVerboseId,
|
||||
@@ -646,7 +644,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
DeviceConnect();
|
||||
}
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, newMode);
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
} else if (newMode.fps != m_mode.fps) {
|
||||
m_mode = newMode;
|
||||
@@ -656,7 +654,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
if (wasStreaming) DeviceStreamOff();
|
||||
DeviceSetFPS();
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, newMode);
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
@@ -892,7 +890,7 @@ void UsbCameraImpl::DeviceCacheMode() {
|
||||
if (formatChanged) DeviceSetMode();
|
||||
if (fpsChanged) DeviceSetFPS();
|
||||
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, m_mode);
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheProperty(
|
||||
@@ -1074,7 +1072,7 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
m_videoModes.swap(modes);
|
||||
}
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
}
|
||||
|
||||
CS_StatusValue UsbCameraImpl::SendAndWait(Message&& msg) const {
|
||||
@@ -1265,17 +1263,14 @@ CS_Source CreateUsbCameraDev(const wpi::Twine& name, int dev,
|
||||
|
||||
CS_Source CreateUsbCameraPath(const wpi::Twine& name, const wpi::Twine& path,
|
||||
CS_Status* status) {
|
||||
auto source = std::make_shared<UsbCameraImpl>(name, path);
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_USB, source);
|
||||
Notifier::GetInstance().NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
// Start thread after the source created event to ensure other events
|
||||
// come after it.
|
||||
source->Start();
|
||||
return handle;
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSource(CS_SOURCE_USB, std::make_shared<UsbCameraImpl>(
|
||||
name, inst.logger, inst.notifier,
|
||||
inst.telemetry, path));
|
||||
}
|
||||
|
||||
std::string GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_USB) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -1306,7 +1301,7 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
closedir(dp);
|
||||
} else {
|
||||
// *status = ;
|
||||
ERROR("Could not open /dev");
|
||||
WPI_ERROR(Instance::GetInstance().logger, "Could not open /dev");
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -1320,73 +1315,3 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
extern "C" {
|
||||
|
||||
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) {
|
||||
return cs::CreateUsbCameraDev(name, dev, status);
|
||||
}
|
||||
|
||||
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
|
||||
CS_Status* status) {
|
||||
return cs::CreateUsbCameraPath(name, path, status);
|
||||
}
|
||||
|
||||
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
return ConvertToC(cs::GetUsbCameraPath(source, status));
|
||||
}
|
||||
|
||||
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
|
||||
auto cameras = cs::EnumerateUsbCameras(status);
|
||||
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
|
||||
wpi::CheckedMalloc(cameras.size() * sizeof(CS_UsbCameraInfo)));
|
||||
*count = cameras.size();
|
||||
for (size_t i = 0; i < cameras.size(); ++i) {
|
||||
out[i].dev = cameras[i].dev;
|
||||
out[i].path = ConvertToC(cameras[i].path);
|
||||
out[i].name = ConvertToC(cameras[i].name);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CS_FreeEnumeratedUsbCameras(CS_UsbCameraInfo* cameras, int count) {
|
||||
if (!cameras) return;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::free(cameras[i].path);
|
||||
std::free(cameras[i].name);
|
||||
}
|
||||
std::free(cameras);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#else
|
||||
|
||||
extern "C" {
|
||||
|
||||
CS_Source CS_CreateUsbCameraDev(const char* name, int dev, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_Source CS_CreateUsbCameraPath(const char* name, const char* path,
|
||||
CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CS_FreeEnumeratedUsbCameras(CS_UsbCameraInfo* cameras, int count) {}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // __linux__
|
||||
@@ -8,9 +8,7 @@
|
||||
#ifndef CSCORE_USBCAMERAIMPL_H_
|
||||
#define CSCORE_USBCAMERAIMPL_H_
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/videodev2.h>
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
@@ -33,12 +31,16 @@
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class UsbCameraImpl : public SourceImpl {
|
||||
public:
|
||||
UsbCameraImpl(const wpi::Twine& name, const wpi::Twine& path);
|
||||
UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const wpi::Twine& path);
|
||||
~UsbCameraImpl() override;
|
||||
|
||||
void Start();
|
||||
void Start() override;
|
||||
|
||||
// Property functions
|
||||
void SetProperty(int property, int value, CS_Status* status) override;
|
||||
@@ -145,24 +147,18 @@ class UsbCameraImpl : public SourceImpl {
|
||||
bool m_modeSetResolution{false};
|
||||
bool m_modeSetFPS{false};
|
||||
int m_connectVerbose{1};
|
||||
#ifdef __linux__
|
||||
unsigned m_capabilities = 0;
|
||||
#endif
|
||||
// Number of buffers to ask OS for
|
||||
static constexpr int kNumBuffers = 4;
|
||||
#ifdef __linux__
|
||||
std::array<UsbCameraBuffer, kNumBuffers> m_buffers;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Path never changes, so not protected by mutex.
|
||||
//
|
||||
std::string m_path;
|
||||
|
||||
#ifdef __linux__
|
||||
std::atomic_int m_fd;
|
||||
std::atomic_int m_command_fd; // for command eventfd
|
||||
#endif
|
||||
|
||||
std::atomic_bool m_active; // set to false to terminate thread
|
||||
std::thread m_cameraThread;
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
|
||||
unsigned ctrl_class = V4L2_CTRL_ID2CLASS(id);
|
||||
if (type == V4L2_CTRL_TYPE_INTEGER64 || V4L2_CTRL_DRIVER_PRIV(id) ||
|
||||
@@ -322,5 +320,3 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd,
|
||||
|
||||
return rv >= 0;
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
@@ -8,9 +8,7 @@
|
||||
#ifndef CSCORE_USBCAMERAPROPERTY_H_
|
||||
#define CSCORE_USBCAMERAPROPERTY_H_
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/videodev2.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -50,7 +48,6 @@ class UsbCameraProperty : public PropertyImpl {
|
||||
maximum = 100;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#ifdef VIDIOC_QUERY_EXT_CTRL
|
||||
explicit UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl);
|
||||
#endif
|
||||
@@ -62,7 +59,6 @@ class UsbCameraProperty : public PropertyImpl {
|
||||
bool DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd) const;
|
||||
bool DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd, int newValue,
|
||||
const wpi::Twine& newValueStr) const;
|
||||
#endif
|
||||
|
||||
// If this is a device (rather than software) property
|
||||
bool device{true};
|
||||
@@ -8,23 +8,19 @@
|
||||
#include "UsbUtil.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <libgen.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <wpi/Format.h>
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/raw_istream.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
static wpi::StringRef GetUsbNameFromFile(int vendor, int product,
|
||||
wpi::SmallVectorImpl<char>& buf) {
|
||||
int fd = open("/var/lib/usbutils/usb.ids", O_RDONLY);
|
||||
@@ -155,12 +151,11 @@ int CheckedIoctl(int fd, unsigned long req, void* data, // NOLINT(runtime/int)
|
||||
if (!quiet && retval < 0) {
|
||||
wpi::SmallString<64> localfile{file};
|
||||
localfile.push_back('\0');
|
||||
ERROR("ioctl " << name << " failed at " << basename(localfile.data()) << ":"
|
||||
<< line << ": " << std::strerror(errno));
|
||||
WPI_ERROR(Instance::GetInstance().logger,
|
||||
"ioctl " << name << " failed at " << basename(localfile.data())
|
||||
<< ":" << line << ": " << std::strerror(errno));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace cs
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
namespace cs {
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
wpi::StringRef GetUsbNameFromId(int vendor, int product,
|
||||
wpi::SmallVectorImpl<char>& buf);
|
||||
|
||||
@@ -28,8 +26,6 @@ int CheckedIoctl(int fd, unsigned long req, void* data, // NOLINT(runtime/int)
|
||||
#define TryIoctl(fd, req, data) \
|
||||
CheckedIoctl(fd, req, data, #req, __FILE__, __LINE__, true)
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_USBUTIL_H_
|
||||
20
cscore/src/main/native/osx/NetworkListener.cpp
Normal file
20
cscore/src/main/native/osx/NetworkListener.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "NetworkListener.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class NetworkListener::Impl {};
|
||||
|
||||
NetworkListener::NetworkListener(wpi::Logger& logger, Notifier& notifier) {}
|
||||
|
||||
NetworkListener::~NetworkListener() {}
|
||||
|
||||
void NetworkListener::Start() {}
|
||||
|
||||
void NetworkListener::Stop() {}
|
||||
16
cscore/src/main/native/osx/NetworkUtil.cpp
Normal file
16
cscore/src/main/native/osx/NetworkUtil.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
std::vector<std::string> GetNetworkInterfaces() {
|
||||
return std::vector<std::string>{}; // TODO
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
34
cscore/src/main/native/osx/UsbCameraImpl.cpp
Normal file
34
cscore/src/main/native/osx/UsbCameraImpl.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Source CreateUsbCameraDev(const wpi::Twine& name, int dev,
|
||||
CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_Source CreateUsbCameraPath(const wpi::Twine& name, const wpi::Twine& path,
|
||||
CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<UsbCameraInfo>{};
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
20
cscore/src/main/native/windows/NetworkListener.cpp
Normal file
20
cscore/src/main/native/windows/NetworkListener.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "NetworkListener.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class NetworkListener::Impl {};
|
||||
|
||||
NetworkListener::NetworkListener(wpi::Logger& logger, Notifier& notifier) {}
|
||||
|
||||
NetworkListener::~NetworkListener() {}
|
||||
|
||||
void NetworkListener::Start() {}
|
||||
|
||||
void NetworkListener::Stop() {}
|
||||
16
cscore/src/main/native/windows/NetworkUtil.cpp
Normal file
16
cscore/src/main/native/windows/NetworkUtil.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
std::vector<std::string> GetNetworkInterfaces() {
|
||||
return std::vector<std::string>{}; // TODO
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
34
cscore/src/main/native/windows/UsbCameraImpl.cpp
Normal file
34
cscore/src/main/native/windows/UsbCameraImpl.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Source CreateUsbCameraDev(const wpi::Twine& name, int dev,
|
||||
CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_Source CreateUsbCameraPath(const wpi::Twine& name, const wpi::Twine& path,
|
||||
CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<UsbCameraInfo>{};
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
@@ -100,6 +100,7 @@ task generateJavaDocs(type: Javadoc) {
|
||||
options.links("https://docs.oracle.com/javase/8/docs/api/")
|
||||
options.addStringOption "tag", "pre:a:Pre-Condition"
|
||||
options.addStringOption('Xdoclint:accessibility,html,missing,reference,syntax')
|
||||
options.addBooleanOption('html5', true)
|
||||
dependsOn project(':wpilibj').generateJavaVersion
|
||||
dependsOn project(':hal').generateUsageReporting
|
||||
source project(':hal').sourceSets.main.java
|
||||
|
||||
@@ -22,6 +22,47 @@ endforeach()
|
||||
string(REPLACE ";" "\n" usage_reporting_types_cpp "${usage_reporting_types_cpp}")
|
||||
string(REPLACE ";" "\n" usage_reporting_instances_cpp "${usage_reporting_instances_cpp}")
|
||||
|
||||
file(GLOB
|
||||
hal_shared_native_src src/main/native/cpp/cpp/*.cpp
|
||||
hal_shared_native_src src/main/native/cpp/handles/*.cpp
|
||||
hal_sim_native_src src/main/native/sim/*.cpp
|
||||
hal_sim_native_src src/main/native/sim/MockData/*.cpp)
|
||||
add_library(hal ${hal_shared_native_src})
|
||||
set_target_properties(hal PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
if(USE_EXTERNAL_HAL)
|
||||
include(${EXTERNAL_HAL_FILE})
|
||||
else()
|
||||
target_sources(hal PRIVATE ${hal_sim_native_src} ${hal_sim_jni_src})
|
||||
endif()
|
||||
|
||||
configure_file(src/generate/FRCUsageReporting.h.in gen/hal/FRCUsageReporting.h)
|
||||
|
||||
set_target_properties(hal PROPERTIES OUTPUT_NAME "wpiHal")
|
||||
|
||||
target_include_directories(hal PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/hal>)
|
||||
|
||||
target_include_directories(hal PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/gen>
|
||||
$<INSTALL_INTERFACE:${include_dest}/hal>)
|
||||
target_link_libraries(hal PUBLIC wpiutil)
|
||||
|
||||
set_property(TARGET hal PROPERTY FOLDER "libraries")
|
||||
|
||||
install(TARGETS hal EXPORT hal DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/hal")
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen DESTINATION "${include_dest}/hal")
|
||||
|
||||
if (MSVC)
|
||||
set (hal_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (hal_config_dir share/hal)
|
||||
endif()
|
||||
|
||||
install(FILES hal-config.cmake DESTINATION ${hal_config_dir})
|
||||
install(EXPORT hal DESTINATION ${hal_config_dir})
|
||||
|
||||
# Java bindings
|
||||
if (NOT WITHOUT_JAVA)
|
||||
@@ -53,59 +94,32 @@ if (NOT WITHOUT_JAVA)
|
||||
|
||||
set_property(TARGET hal_jar PROPERTY FOLDER "java")
|
||||
|
||||
endif()
|
||||
add_library(haljni ${hal_shared_jni_src})
|
||||
|
||||
file(GLOB
|
||||
hal_shared_native_src src/main/native/cpp/cpp/*.cpp
|
||||
hal_shared_native_src src/main/native/cpp/handles/*.cpp
|
||||
hal_sim_native_src src/main/native/sim/*.cpp
|
||||
hal_sim_native_src src/main/native/sim/MockData/*.cpp)
|
||||
add_library(hal ${hal_shared_native_src} ${hal_shared_jni_src})
|
||||
|
||||
if(USE_EXTERNAL_HAL)
|
||||
include(${EXTERNAL_HAL_FILE})
|
||||
else()
|
||||
target_sources(hal PRIVATE ${hal_sim_native_src} ${hal_sim_jni_src})
|
||||
endif()
|
||||
|
||||
configure_file(src/generate/FRCUsageReporting.h.in gen/hal/FRCUsageReporting.h)
|
||||
|
||||
set_target_properties(hal PROPERTIES OUTPUT_NAME "wpiHal")
|
||||
|
||||
target_include_directories(hal PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/hal>)
|
||||
|
||||
target_include_directories(hal PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/gen>
|
||||
$<INSTALL_INTERFACE:${include_dest}/hal>)
|
||||
target_link_libraries(hal PUBLIC wpiutil)
|
||||
|
||||
set_property(TARGET hal PROPERTY FOLDER "libraries")
|
||||
|
||||
if (NOT WITHOUT_JAVA)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
target_include_directories(hal PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(hal PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
if(USE_EXTERNAL_HAL)
|
||||
include(${EXTERNAL_HAL_FILE})
|
||||
else()
|
||||
target_link_libraries(hal PRIVATE hal_jni_headers)
|
||||
target_sources(haljni PRIVATE ${hal_sim_jni_src})
|
||||
endif()
|
||||
add_dependencies(hal hal_jar)
|
||||
|
||||
set_target_properties(haljni PROPERTIES OUTPUT_NAME "wpiHaljni")
|
||||
|
||||
target_link_libraries(haljni PUBLIC hal wpiutil)
|
||||
|
||||
set_property(TARGET haljni PROPERTY FOLDER "libraries")
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
target_include_directories(haljni PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(haljni PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
else()
|
||||
target_link_libraries(haljni PRIVATE hal_jni_headers)
|
||||
endif()
|
||||
add_dependencies(haljni hal_jar)
|
||||
|
||||
if (MSVC)
|
||||
install(TARGETS haljni RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
install(TARGETS haljni EXPORT haljni DESTINATION "${main_lib_dest}")
|
||||
|
||||
endif()
|
||||
|
||||
install(TARGETS hal EXPORT hal DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/hal")
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/gen DESTINATION "${include_dest}/hal")
|
||||
|
||||
if (NOT WITHOUT_JAVA AND MSVC)
|
||||
install(TARGETS hal RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set (hal_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (hal_config_dir share/hal)
|
||||
endif()
|
||||
|
||||
install(FILES hal-config.cmake DESTINATION ${hal_config_dir})
|
||||
install(EXPORT hal DESTINATION ${hal_config_dir})
|
||||
|
||||
@@ -51,11 +51,50 @@ ext {
|
||||
binary.lib project: ':hal', library: 'hal', linkage: shared
|
||||
}
|
||||
|
||||
addHalJniDependency = { binary->
|
||||
binary.tasks.withType(AbstractNativeSourceCompileTask) {
|
||||
it.dependsOn generateUsageReporting
|
||||
}
|
||||
binary.lib project: ':hal', library: 'halJNIShared', linkage: 'shared'
|
||||
}
|
||||
|
||||
nativeName = 'hal'
|
||||
setBaseName = 'wpiHal'
|
||||
devMain = 'DevMain'
|
||||
niLibraries = true
|
||||
generatedHeaders = "$buildDir/generated/headers"
|
||||
jniSplitSetup = {
|
||||
it.tasks.withType(AbstractNativeSourceCompileTask) {
|
||||
it.dependsOn generateUsageReporting
|
||||
}
|
||||
if (it.targetPlatform.architecture.name == 'athena') {
|
||||
it.sources {
|
||||
athenaJniCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs = ["${rootDir}/shared/singlelib", "$buildDir/generated/cpp"]
|
||||
include '**/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDir 'src/main/native/include'
|
||||
srcDir generatedHeaders
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
it.sources {
|
||||
simJniCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/sim'
|
||||
include '**/jni/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDir 'src/main/native/include'
|
||||
srcDir generatedHeaders
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
splitSetup = {
|
||||
it.tasks.withType(AbstractNativeSourceCompileTask) {
|
||||
it.dependsOn generateUsageReporting
|
||||
@@ -64,8 +103,9 @@ ext {
|
||||
it.sources {
|
||||
athenaCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs = ['src/main/native/athena', "$buildDir/generated/cpp"]
|
||||
srcDirs = ['src/main/native/athena']
|
||||
include '**/*.cpp'
|
||||
exclude '**/jni/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDir 'src/main/native/include'
|
||||
@@ -79,6 +119,7 @@ ext {
|
||||
source {
|
||||
srcDirs 'src/main/native/sim'
|
||||
include '**/*.cpp'
|
||||
exclude '**/jni/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDir 'src/main/native/include'
|
||||
@@ -138,25 +179,5 @@ model {
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure']
|
||||
}
|
||||
halJNI(ExportsConfig) {
|
||||
x86SymbolFilter = { symbols ->
|
||||
def retList = []
|
||||
symbols.each { symbol ->
|
||||
if (symbol.startsWith('HAL_') || symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
|
||||
retList << symbol
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
x64SymbolFilter = { symbols ->
|
||||
def retList = []
|
||||
symbols.each { symbol ->
|
||||
if (symbol.startsWith('HAL_') || symbol.startsWith('Java_') || symbol.startsWith('JNI_')) {
|
||||
retList << symbol
|
||||
}
|
||||
}
|
||||
return retList
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public class JNIWrapper {
|
||||
static {
|
||||
if (!libraryLoaded) {
|
||||
try {
|
||||
loader = new RuntimeLoader<>("wpiHal", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
|
||||
loader = new RuntimeLoader<>("wpiHaljni", RuntimeLoader.getDefaultExtractionRoot(), JNIWrapper.class);
|
||||
loader.loadLibrary();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "AnalogInternal.h"
|
||||
#include "HALInitializer.h"
|
||||
#include "hal/AnalogAccumulator.h"
|
||||
@@ -169,6 +171,8 @@ void HAL_CalibrateAnalogGyro(HAL_GyroHandle handle, int32_t* status) {
|
||||
|
||||
HAL_InitAccumulator(gyro->handle, status);
|
||||
if (*status != 0) return;
|
||||
wpi::outs() << "Calibrating analog gyro for " << kCalibrationSampleTime
|
||||
<< " seconds." << '\n';
|
||||
Wait(kCalibrationSampleTime);
|
||||
|
||||
int64_t value;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "HALInitializer.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "hal/AnalogAccumulator.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/handles/HandlesInternal.h"
|
||||
|
||||
namespace hal {
|
||||
|
||||
@@ -53,9 +53,6 @@ static wpi::mutex m_controlWordMutex;
|
||||
|
||||
// Message and Data variables
|
||||
static wpi::mutex msgMutex;
|
||||
static wpi::condition_variable* newDSDataAvailableCond;
|
||||
static wpi::mutex newDSDataAvailableMutex;
|
||||
static int newDSDataAvailableCounter{0};
|
||||
|
||||
static void InitializeDriverStationCaches() {
|
||||
m_joystickAxes = std::make_unique<HAL_JoystickAxes[]>(kJoystickPorts);
|
||||
@@ -229,16 +226,23 @@ class DriverStationThread : public wpi::SafeThread {
|
||||
if (!m_active) break;
|
||||
m_notify = false;
|
||||
|
||||
lock.unlock();
|
||||
UpdateDriverStationDataCaches();
|
||||
lock.lock();
|
||||
|
||||
std::lock_guard<wpi::mutex> lock(newDSDataAvailableMutex);
|
||||
// Nofify all threads
|
||||
// Notify all threads
|
||||
newDSDataAvailableCounter++;
|
||||
newDSDataAvailableCond->notify_all();
|
||||
newDSDataAvailableCond.notify_all();
|
||||
}
|
||||
|
||||
// Notify waiters on thread exit
|
||||
newDSDataAvailableCounter++;
|
||||
newDSDataAvailableCond.notify_all();
|
||||
}
|
||||
|
||||
bool m_notify = false;
|
||||
wpi::condition_variable newDSDataAvailableCond;
|
||||
int newDSDataAvailableCounter{0};
|
||||
};
|
||||
|
||||
class DriverStationThreadOwner
|
||||
@@ -256,10 +260,7 @@ static std::unique_ptr<DriverStationThreadOwner> dsThread = nullptr;
|
||||
|
||||
namespace hal {
|
||||
namespace init {
|
||||
void InitializeFRCDriverStation() {
|
||||
static wpi::condition_variable nddaC;
|
||||
newDSDataAvailableCond = &nddaC;
|
||||
}
|
||||
void InitializeFRCDriverStation() {}
|
||||
} // namespace init
|
||||
} // namespace hal
|
||||
|
||||
@@ -447,11 +448,10 @@ HAL_Bool HAL_IsNewControlData(void) {
|
||||
// 20ms rate occurs once every 2.7 years of DS connected runtime, so not
|
||||
// worth the cycles to check.
|
||||
thread_local int lastCount{-1};
|
||||
int currentCount = 0;
|
||||
{
|
||||
std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
|
||||
currentCount = newDSDataAvailableCounter;
|
||||
}
|
||||
if (!dsThread) return false;
|
||||
auto thr = dsThread->GetThread();
|
||||
if (!thr) return false;
|
||||
int currentCount = thr->newDSDataAvailableCounter;
|
||||
if (lastCount == currentCount) return false;
|
||||
lastCount = currentCount;
|
||||
return true;
|
||||
@@ -471,16 +471,19 @@ HAL_Bool HAL_WaitForDSDataTimeout(double timeout) {
|
||||
auto timeoutTime =
|
||||
std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
|
||||
|
||||
std::unique_lock<wpi::mutex> lock(newDSDataAvailableMutex);
|
||||
int currentCount = newDSDataAvailableCounter;
|
||||
while (newDSDataAvailableCounter == currentCount) {
|
||||
if (!dsThread) return false;
|
||||
auto thr = dsThread->GetThread();
|
||||
if (!thr) return false;
|
||||
int currentCount = thr->newDSDataAvailableCounter;
|
||||
while (thr->newDSDataAvailableCounter == currentCount) {
|
||||
if (timeout > 0) {
|
||||
auto timedOut = newDSDataAvailableCond->wait_until(lock, timeoutTime);
|
||||
auto timedOut =
|
||||
thr->newDSDataAvailableCond.wait_until(thr.GetLock(), timeoutTime);
|
||||
if (timedOut == std::cv_status::timeout) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
newDSDataAvailableCond->wait(lock);
|
||||
thr->newDSDataAvailableCond.wait(thr.GetLock());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -308,16 +308,16 @@ static bool killExistingProgram(int timeout, int mode) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
|
||||
if (kill(pid, 0) == 0) {
|
||||
// still not successfull
|
||||
if (mode == 0) {
|
||||
wpi::outs() << "FRC pid " << pid << " did not die within " << timeout
|
||||
<< "ms. Aborting\n";
|
||||
return 0; // just fail
|
||||
} else if (mode == 1) { // kill -9 it
|
||||
kill(pid, SIGKILL);
|
||||
} else {
|
||||
wpi::outs() << "WARNING: FRC pid " << pid << " did not die within "
|
||||
<< timeout << "ms.\n";
|
||||
wpi::outs() << "FRC pid " << pid << " did not die within " << timeout
|
||||
<< "ms. Force killing with kill -9\n";
|
||||
// Force kill -9
|
||||
auto forceKill = kill(pid, SIGKILL);
|
||||
if (forceKill != 0) {
|
||||
auto errorMsg = std::strerror(forceKill);
|
||||
wpi::outs() << "Kill -9 error: " << errorMsg << "\n";
|
||||
}
|
||||
// Give a bit of time for the kill to take place
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ int32_t HAL_GetThreadPriority(NativeThreadHandle handle, HAL_Bool* isRealTime,
|
||||
int32_t* status) {
|
||||
sched_param sch;
|
||||
int policy;
|
||||
int success = pthread_getschedparam(*handle, &policy, &sch);
|
||||
int success = pthread_getschedparam(
|
||||
*reinterpret_cast<const pthread_t*>(handle), &policy, &sch);
|
||||
if (success == 0) {
|
||||
*status = 0;
|
||||
} else {
|
||||
@@ -66,13 +67,15 @@ HAL_Bool HAL_SetThreadPriority(NativeThreadHandle handle, HAL_Bool realTime,
|
||||
|
||||
sched_param sch;
|
||||
int policy;
|
||||
pthread_getschedparam(*handle, &policy, &sch);
|
||||
pthread_getschedparam(*reinterpret_cast<const pthread_t*>(handle), &policy,
|
||||
&sch);
|
||||
if (scheduler == SCHED_FIFO || scheduler == SCHED_RR)
|
||||
sch.sched_priority = priority;
|
||||
else
|
||||
// Only need to set 0 priority for non RT thread
|
||||
sch.sched_priority = 0;
|
||||
if (pthread_setschedparam(*handle, scheduler, &sch)) {
|
||||
if (pthread_setschedparam(*reinterpret_cast<const pthread_t*>(handle),
|
||||
scheduler, &sch)) {
|
||||
*status = HAL_THREAD_PRIORITY_ERROR;
|
||||
return false;
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/CANAPITypes.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
@@ -17,43 +18,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* The CAN device type.
|
||||
*
|
||||
* Teams should use HAL_CAN_Dev_kMiscellaneous
|
||||
*/
|
||||
HAL_ENUM(HAL_CANDeviceType) {
|
||||
HAL_CAN_Dev_kBroadcast = 0,
|
||||
HAL_CAN_Dev_kRobotController = 1,
|
||||
HAL_CAN_Dev_kMotorController = 2,
|
||||
HAL_CAN_Dev_kRelayController = 3,
|
||||
HAL_CAN_Dev_kGyroSensor = 4,
|
||||
HAL_CAN_Dev_kAccelerometer = 5,
|
||||
HAL_CAN_Dev_kUltrasonicSensor = 6,
|
||||
HAL_CAN_Dev_kGearToothSensor = 7,
|
||||
HAL_CAN_Dev_kPowerDistribution = 8,
|
||||
HAL_CAN_Dev_kPneumatics = 9,
|
||||
HAL_CAN_Dev_kMiscellaneous = 10,
|
||||
HAL_CAN_Dev_kFirmwareUpdate = 31
|
||||
};
|
||||
|
||||
/**
|
||||
* The CAN manufacturer ID.
|
||||
*
|
||||
* Teams should use HAL_CAN_Man_kTeamUse.
|
||||
*/
|
||||
HAL_ENUM(HAL_CANManufacturer) {
|
||||
HAL_CAN_Man_kBroadcast = 0,
|
||||
HAL_CAN_Man_kNI = 1,
|
||||
HAL_CAN_Man_kLM = 2,
|
||||
HAL_CAN_Man_kDEKA = 3,
|
||||
HAL_CAN_Man_kCTRE = 4,
|
||||
HAL_CAN_Man_kMS = 7,
|
||||
HAL_CAN_Man_kTeamUse = 8,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
56
hal/src/main/native/include/hal/CANAPITypes.h
Normal file
56
hal/src/main/native/include/hal/CANAPITypes.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_canapi CAN API Functions
|
||||
* @ingroup hal_capi
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* The CAN device type.
|
||||
*
|
||||
* Teams should use HAL_CAN_Dev_kMiscellaneous
|
||||
*/
|
||||
HAL_ENUM(HAL_CANDeviceType) {
|
||||
HAL_CAN_Dev_kBroadcast = 0,
|
||||
HAL_CAN_Dev_kRobotController = 1,
|
||||
HAL_CAN_Dev_kMotorController = 2,
|
||||
HAL_CAN_Dev_kRelayController = 3,
|
||||
HAL_CAN_Dev_kGyroSensor = 4,
|
||||
HAL_CAN_Dev_kAccelerometer = 5,
|
||||
HAL_CAN_Dev_kUltrasonicSensor = 6,
|
||||
HAL_CAN_Dev_kGearToothSensor = 7,
|
||||
HAL_CAN_Dev_kPowerDistribution = 8,
|
||||
HAL_CAN_Dev_kPneumatics = 9,
|
||||
HAL_CAN_Dev_kMiscellaneous = 10,
|
||||
HAL_CAN_Dev_kFirmwareUpdate = 31
|
||||
};
|
||||
|
||||
/**
|
||||
* The CAN manufacturer ID.
|
||||
*
|
||||
* Teams should use HAL_CAN_Man_kTeamUse.
|
||||
*/
|
||||
HAL_ENUM(HAL_CANManufacturer) {
|
||||
HAL_CAN_Man_kBroadcast = 0,
|
||||
HAL_CAN_Man_kNI = 1,
|
||||
HAL_CAN_Man_kLM = 2,
|
||||
HAL_CAN_Man_kDEKA = 3,
|
||||
HAL_CAN_Man_kCTRE = 4,
|
||||
HAL_CAN_Man_kMS = 7,
|
||||
HAL_CAN_Man_kTeamUse = 8,
|
||||
};
|
||||
// clang-format on
|
||||
/** @} */
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/DriverStationTypes.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
@@ -17,97 +18,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define HAL_IO_CONFIG_DATA_SIZE 32
|
||||
#define HAL_SYS_STATUS_DATA_SIZE 44
|
||||
#define HAL_USER_STATUS_DATA_SIZE \
|
||||
(984 - HAL_IO_CONFIG_DATA_SIZE - HAL_SYS_STATUS_DATA_SIZE)
|
||||
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Input 17
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output 18
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Header 19
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra1 20
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices1 21
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra2 22
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices2 23
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Joystick 24
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Custom 25
|
||||
|
||||
struct HAL_ControlWord {
|
||||
uint32_t enabled : 1;
|
||||
uint32_t autonomous : 1;
|
||||
uint32_t test : 1;
|
||||
uint32_t eStop : 1;
|
||||
uint32_t fmsAttached : 1;
|
||||
uint32_t dsAttached : 1;
|
||||
uint32_t control_reserved : 26;
|
||||
};
|
||||
typedef struct HAL_ControlWord HAL_ControlWord;
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_AllianceStationID) {
|
||||
HAL_AllianceStationID_kRed1,
|
||||
HAL_AllianceStationID_kRed2,
|
||||
HAL_AllianceStationID_kRed3,
|
||||
HAL_AllianceStationID_kBlue1,
|
||||
HAL_AllianceStationID_kBlue2,
|
||||
HAL_AllianceStationID_kBlue3,
|
||||
};
|
||||
|
||||
HAL_ENUM(HAL_MatchType) {
|
||||
HAL_kMatchType_none,
|
||||
HAL_kMatchType_practice,
|
||||
HAL_kMatchType_qualification,
|
||||
HAL_kMatchType_elimination,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/* The maximum number of axes that will be stored in a single HALJoystickAxes
|
||||
* struct. This is used for allocating buffers, not bounds checking, since
|
||||
* there are usually less axes in practice.
|
||||
*/
|
||||
#define HAL_kMaxJoystickAxes 12
|
||||
#define HAL_kMaxJoystickPOVs 12
|
||||
#define HAL_kMaxJoysticks 6
|
||||
|
||||
struct HAL_JoystickAxes {
|
||||
int16_t count;
|
||||
float axes[HAL_kMaxJoystickAxes];
|
||||
};
|
||||
typedef struct HAL_JoystickAxes HAL_JoystickAxes;
|
||||
|
||||
struct HAL_JoystickPOVs {
|
||||
int16_t count;
|
||||
int16_t povs[HAL_kMaxJoystickPOVs];
|
||||
};
|
||||
typedef struct HAL_JoystickPOVs HAL_JoystickPOVs;
|
||||
|
||||
struct HAL_JoystickButtons {
|
||||
uint32_t buttons;
|
||||
uint8_t count;
|
||||
};
|
||||
typedef struct HAL_JoystickButtons HAL_JoystickButtons;
|
||||
|
||||
struct HAL_JoystickDescriptor {
|
||||
uint8_t isXbox;
|
||||
uint8_t type;
|
||||
char name[256];
|
||||
uint8_t axisCount;
|
||||
uint8_t axisTypes[HAL_kMaxJoystickAxes];
|
||||
uint8_t buttonCount;
|
||||
uint8_t povCount;
|
||||
};
|
||||
typedef struct HAL_JoystickDescriptor HAL_JoystickDescriptor;
|
||||
|
||||
struct HAL_MatchInfo {
|
||||
char eventName[64];
|
||||
HAL_MatchType matchType;
|
||||
uint16_t matchNumber;
|
||||
uint8_t replayNumber;
|
||||
uint8_t gameSpecificMessage[64];
|
||||
uint16_t gameSpecificMessageSize;
|
||||
};
|
||||
typedef struct HAL_MatchInfo HAL_MatchInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
110
hal/src/main/native/include/hal/DriverStationTypes.h
Normal file
110
hal/src/main/native/include/hal/DriverStationTypes.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_driverstation Driver Station Functions
|
||||
* @ingroup hal_capi
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define HAL_IO_CONFIG_DATA_SIZE 32
|
||||
#define HAL_SYS_STATUS_DATA_SIZE 44
|
||||
#define HAL_USER_STATUS_DATA_SIZE \
|
||||
(984 - HAL_IO_CONFIG_DATA_SIZE - HAL_SYS_STATUS_DATA_SIZE)
|
||||
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Input 17
|
||||
#define HALFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output 18
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Header 19
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra1 20
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices1 21
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Extra2 22
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Vertices2 23
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Joystick 24
|
||||
#define HALFRC_NetworkCommunication_DynamicType_Kinect_Custom 25
|
||||
|
||||
struct HAL_ControlWord {
|
||||
uint32_t enabled : 1;
|
||||
uint32_t autonomous : 1;
|
||||
uint32_t test : 1;
|
||||
uint32_t eStop : 1;
|
||||
uint32_t fmsAttached : 1;
|
||||
uint32_t dsAttached : 1;
|
||||
uint32_t control_reserved : 26;
|
||||
};
|
||||
typedef struct HAL_ControlWord HAL_ControlWord;
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_AllianceStationID) {
|
||||
HAL_AllianceStationID_kRed1,
|
||||
HAL_AllianceStationID_kRed2,
|
||||
HAL_AllianceStationID_kRed3,
|
||||
HAL_AllianceStationID_kBlue1,
|
||||
HAL_AllianceStationID_kBlue2,
|
||||
HAL_AllianceStationID_kBlue3,
|
||||
};
|
||||
|
||||
HAL_ENUM(HAL_MatchType) {
|
||||
HAL_kMatchType_none,
|
||||
HAL_kMatchType_practice,
|
||||
HAL_kMatchType_qualification,
|
||||
HAL_kMatchType_elimination,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/* The maximum number of axes that will be stored in a single HALJoystickAxes
|
||||
* struct. This is used for allocating buffers, not bounds checking, since
|
||||
* there are usually less axes in practice.
|
||||
*/
|
||||
#define HAL_kMaxJoystickAxes 12
|
||||
#define HAL_kMaxJoystickPOVs 12
|
||||
#define HAL_kMaxJoysticks 6
|
||||
|
||||
struct HAL_JoystickAxes {
|
||||
int16_t count;
|
||||
float axes[HAL_kMaxJoystickAxes];
|
||||
};
|
||||
typedef struct HAL_JoystickAxes HAL_JoystickAxes;
|
||||
|
||||
struct HAL_JoystickPOVs {
|
||||
int16_t count;
|
||||
int16_t povs[HAL_kMaxJoystickPOVs];
|
||||
};
|
||||
typedef struct HAL_JoystickPOVs HAL_JoystickPOVs;
|
||||
|
||||
struct HAL_JoystickButtons {
|
||||
uint32_t buttons;
|
||||
uint8_t count;
|
||||
};
|
||||
typedef struct HAL_JoystickButtons HAL_JoystickButtons;
|
||||
|
||||
struct HAL_JoystickDescriptor {
|
||||
uint8_t isXbox;
|
||||
uint8_t type;
|
||||
char name[256];
|
||||
uint8_t axisCount;
|
||||
uint8_t axisTypes[HAL_kMaxJoystickAxes];
|
||||
uint8_t buttonCount;
|
||||
uint8_t povCount;
|
||||
};
|
||||
typedef struct HAL_JoystickDescriptor HAL_JoystickDescriptor;
|
||||
|
||||
struct HAL_MatchInfo {
|
||||
char eventName[64];
|
||||
HAL_MatchType matchType;
|
||||
uint16_t matchNumber;
|
||||
uint8_t replayNumber;
|
||||
uint8_t gameSpecificMessage[64];
|
||||
uint16_t gameSpecificMessageSize;
|
||||
};
|
||||
typedef struct HAL_MatchInfo HAL_MatchInfo;
|
||||
/** @} */
|
||||
@@ -39,177 +39,8 @@
|
||||
#endif // HAL_USE_LABVIEW
|
||||
|
||||
#include "hal/Types.h"
|
||||
#include "hal/HALBase.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "hal/FRCUsageReporting.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup hal_capi WPILib HAL API
|
||||
* Hardware Abstraction Layer to hardware or simulator
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_RuntimeType) { HAL_Athena, HAL_Mock };
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the error message for a specific status code.
|
||||
*
|
||||
* @param code the status code
|
||||
* @return the error message for the code. This does not need to be freed.
|
||||
*/
|
||||
const char* HAL_GetErrorMessage(int32_t code);
|
||||
|
||||
/**
|
||||
* Returns the FPGA Version number.
|
||||
*
|
||||
* For now, expect this to be competition year.
|
||||
*
|
||||
* @return FPGA Version number.
|
||||
*/
|
||||
int32_t HAL_GetFPGAVersion(int32_t* status);
|
||||
|
||||
/**
|
||||
* Returns the FPGA Revision number.
|
||||
*
|
||||
* The format of the revision is 3 numbers.
|
||||
* The 12 most significant bits are the Major Revision.
|
||||
* the next 8 bits are the Minor Revision.
|
||||
* The 12 least significant bits are the Build Number.
|
||||
*
|
||||
* @return FPGA Revision number.
|
||||
*/
|
||||
int64_t HAL_GetFPGARevision(int32_t* status);
|
||||
|
||||
HAL_RuntimeType HAL_GetRuntimeType(void);
|
||||
|
||||
/**
|
||||
* Gets the state of the "USER" button on the roboRIO.
|
||||
*
|
||||
* @return true if the button is currently pressed down
|
||||
*/
|
||||
HAL_Bool HAL_GetFPGAButton(int32_t* status);
|
||||
|
||||
/**
|
||||
* Gets if the system outputs are currently active
|
||||
*
|
||||
* @return true if the system outputs are active, false if disabled
|
||||
*/
|
||||
HAL_Bool HAL_GetSystemActive(int32_t* status);
|
||||
|
||||
/**
|
||||
* Gets if the system is in a browned out state.
|
||||
*
|
||||
* @return true if the system is in a low voltage brown out, false otherwise
|
||||
*/
|
||||
HAL_Bool HAL_GetBrownedOut(int32_t* status);
|
||||
|
||||
/**
|
||||
* The base HAL initialize function. Useful if you need to ensure the DS and
|
||||
* base HAL functions (the ones above this declaration in HAL.h) are properly
|
||||
* initialized. For normal programs and executables, please use HAL_Initialize.
|
||||
*
|
||||
* This is mainly expected to be use from libraries that are expected to be used
|
||||
* from LabVIEW, as it handles its own initialization for objects.
|
||||
*/
|
||||
void HAL_BaseInitialize(int32_t* status);
|
||||
|
||||
#ifndef HAL_USE_LABVIEW
|
||||
|
||||
/**
|
||||
* Gets a port handle for a specific channel.
|
||||
*
|
||||
* The created handle does not need to be freed.
|
||||
*
|
||||
* @param channel the channel number
|
||||
* @return the created port
|
||||
*/
|
||||
HAL_PortHandle HAL_GetPort(int32_t channel);
|
||||
|
||||
/**
|
||||
* Gets a port handle for a specific channel and module.
|
||||
*
|
||||
* This is expected to be used for PCMs, as the roboRIO does not work with
|
||||
* modules anymore.
|
||||
*
|
||||
* The created handle does not need to be freed.
|
||||
*
|
||||
* @param module the module number
|
||||
* @param channel the channel number
|
||||
* @return the created port
|
||||
*/
|
||||
HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);
|
||||
|
||||
/**
|
||||
* Reads the microsecond-resolution timer on the FPGA.
|
||||
*
|
||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
||||
* reset).
|
||||
*/
|
||||
uint64_t HAL_GetFPGATime(int32_t* status);
|
||||
|
||||
/**
|
||||
* Call this to start up HAL. This is required for robot programs.
|
||||
*
|
||||
* This must be called before any other HAL functions. Failure to do so will
|
||||
* result in undefined behavior, and likely segmentation faults. This means that
|
||||
* any statically initialized variables in a program MUST call this function in
|
||||
* their constructors if they want to use other HAL calls.
|
||||
*
|
||||
* The common parameters are 500 for timeout and 0 for mode.
|
||||
*
|
||||
* This function is safe to call from any thread, and as many times as you wish.
|
||||
* It internally guards from any reentrancy.
|
||||
*
|
||||
* The applicable modes are:
|
||||
* 0: Try to kill an existing HAL from another program, if not successful,
|
||||
* error.
|
||||
* 1: Force kill a HAL from another program.
|
||||
* 2: Just warn if another hal exists and cannot be killed. Will likely result
|
||||
* in undefined behavior.
|
||||
*
|
||||
* @param timeout the initialization timeout (ms)
|
||||
* @param mode the initialization mode (see remarks)
|
||||
* @return true if initialization was successful, otherwise false.
|
||||
*/
|
||||
HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);
|
||||
|
||||
// ifdef's definition is to allow for default parameters in C++.
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* Reports a hardware usage to the HAL.
|
||||
*
|
||||
* @param resource the used resource
|
||||
* @param instanceNumber the instance of the resource
|
||||
* @param context a user specified context index
|
||||
* @param feature a user specified feature string
|
||||
* @return the index of the added value in NetComm
|
||||
*/
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber,
|
||||
int32_t context = 0, const char* feature = nullptr);
|
||||
#else
|
||||
|
||||
/**
|
||||
* Reports a hardware usage to the HAL.
|
||||
*
|
||||
* @param resource the used resource
|
||||
* @param instanceNumber the instance of the resource
|
||||
* @param context a user specified context index
|
||||
* @param feature a user specified feature string
|
||||
* @return the index of the added value in NetComm
|
||||
*/
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
|
||||
const char* feature);
|
||||
#endif
|
||||
|
||||
#endif // HAL_USE_LABVIEW
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
182
hal/src/main/native/include/hal/HALBase.h
Normal file
182
hal/src/main/native/include/hal/HALBase.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_capi WPILib HAL API
|
||||
* Hardware Abstraction Layer to hardware or simulator
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_RuntimeType) { HAL_Athena, HAL_Mock };
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the error message for a specific status code.
|
||||
*
|
||||
* @param code the status code
|
||||
* @return the error message for the code. This does not need to be freed.
|
||||
*/
|
||||
const char* HAL_GetErrorMessage(int32_t code);
|
||||
|
||||
/**
|
||||
* Returns the FPGA Version number.
|
||||
*
|
||||
* For now, expect this to be competition year.
|
||||
*
|
||||
* @return FPGA Version number.
|
||||
*/
|
||||
int32_t HAL_GetFPGAVersion(int32_t* status);
|
||||
|
||||
/**
|
||||
* Returns the FPGA Revision number.
|
||||
*
|
||||
* The format of the revision is 3 numbers.
|
||||
* The 12 most significant bits are the Major Revision.
|
||||
* the next 8 bits are the Minor Revision.
|
||||
* The 12 least significant bits are the Build Number.
|
||||
*
|
||||
* @return FPGA Revision number.
|
||||
*/
|
||||
int64_t HAL_GetFPGARevision(int32_t* status);
|
||||
|
||||
HAL_RuntimeType HAL_GetRuntimeType(void);
|
||||
|
||||
/**
|
||||
* Gets the state of the "USER" button on the roboRIO.
|
||||
*
|
||||
* @return true if the button is currently pressed down
|
||||
*/
|
||||
HAL_Bool HAL_GetFPGAButton(int32_t* status);
|
||||
|
||||
/**
|
||||
* Gets if the system outputs are currently active
|
||||
*
|
||||
* @return true if the system outputs are active, false if disabled
|
||||
*/
|
||||
HAL_Bool HAL_GetSystemActive(int32_t* status);
|
||||
|
||||
/**
|
||||
* Gets if the system is in a browned out state.
|
||||
*
|
||||
* @return true if the system is in a low voltage brown out, false otherwise
|
||||
*/
|
||||
HAL_Bool HAL_GetBrownedOut(int32_t* status);
|
||||
|
||||
/**
|
||||
* The base HAL initialize function. Useful if you need to ensure the DS and
|
||||
* base HAL functions (the ones above this declaration in HAL.h) are properly
|
||||
* initialized. For normal programs and executables, please use HAL_Initialize.
|
||||
*
|
||||
* This is mainly expected to be use from libraries that are expected to be used
|
||||
* from LabVIEW, as it handles its own initialization for objects.
|
||||
*/
|
||||
void HAL_BaseInitialize(int32_t* status);
|
||||
|
||||
#ifndef HAL_USE_LABVIEW
|
||||
|
||||
/**
|
||||
* Gets a port handle for a specific channel.
|
||||
*
|
||||
* The created handle does not need to be freed.
|
||||
*
|
||||
* @param channel the channel number
|
||||
* @return the created port
|
||||
*/
|
||||
HAL_PortHandle HAL_GetPort(int32_t channel);
|
||||
|
||||
/**
|
||||
* Gets a port handle for a specific channel and module.
|
||||
*
|
||||
* This is expected to be used for PCMs, as the roboRIO does not work with
|
||||
* modules anymore.
|
||||
*
|
||||
* The created handle does not need to be freed.
|
||||
*
|
||||
* @param module the module number
|
||||
* @param channel the channel number
|
||||
* @return the created port
|
||||
*/
|
||||
HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel);
|
||||
|
||||
/**
|
||||
* Reads the microsecond-resolution timer on the FPGA.
|
||||
*
|
||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
||||
* reset).
|
||||
*/
|
||||
uint64_t HAL_GetFPGATime(int32_t* status);
|
||||
|
||||
/**
|
||||
* Call this to start up HAL. This is required for robot programs.
|
||||
*
|
||||
* This must be called before any other HAL functions. Failure to do so will
|
||||
* result in undefined behavior, and likely segmentation faults. This means that
|
||||
* any statically initialized variables in a program MUST call this function in
|
||||
* their constructors if they want to use other HAL calls.
|
||||
*
|
||||
* The common parameters are 500 for timeout and 0 for mode.
|
||||
*
|
||||
* This function is safe to call from any thread, and as many times as you wish.
|
||||
* It internally guards from any reentrancy.
|
||||
*
|
||||
* The applicable modes are:
|
||||
* 0: Try to kill an existing HAL from another program, if not successful,
|
||||
* error.
|
||||
* 1: Force kill a HAL from another program.
|
||||
* 2: Just warn if another hal exists and cannot be killed. Will likely result
|
||||
* in undefined behavior.
|
||||
*
|
||||
* @param timeout the initialization timeout (ms)
|
||||
* @param mode the initialization mode (see remarks)
|
||||
* @return true if initialization was successful, otherwise false.
|
||||
*/
|
||||
HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode);
|
||||
|
||||
// ifdef's definition is to allow for default parameters in C++.
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* Reports a hardware usage to the HAL.
|
||||
*
|
||||
* @param resource the used resource
|
||||
* @param instanceNumber the instance of the resource
|
||||
* @param context a user specified context index
|
||||
* @param feature a user specified feature string
|
||||
* @return the index of the added value in NetComm
|
||||
*/
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber,
|
||||
int32_t context = 0, const char* feature = nullptr);
|
||||
#else
|
||||
|
||||
/**
|
||||
* Reports a hardware usage to the HAL.
|
||||
*
|
||||
* @param resource the used resource
|
||||
* @param instanceNumber the instance of the resource
|
||||
* @param context a user specified context index
|
||||
* @param feature a user specified feature string
|
||||
* @return the index of the added value in NetComm
|
||||
*/
|
||||
int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
|
||||
const char* feature);
|
||||
#endif
|
||||
|
||||
#endif // HAL_USE_LABVIEW
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
/** @} */
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/I2CTypes.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
@@ -17,10 +18,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_I2CPort) { HAL_I2C_kInvalid = -1, HAL_I2C_kOnboard, HAL_I2C_kMXP };
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
24
hal/src/main/native/include/hal/I2CTypes.h
Normal file
24
hal/src/main/native/include/hal/I2CTypes.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_i2c I2C Functions
|
||||
* @ingroup hal_capi
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_I2CPort) { HAL_I2C_kInvalid = -1, HAL_I2C_kOnboard, HAL_I2C_kMXP };
|
||||
// clang-format on
|
||||
|
||||
/** @} */
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/AnalogTrigger.h"
|
||||
#include "hal/SPITypes.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
@@ -18,17 +19,6 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_SPIPort) {
|
||||
HAL_SPI_kInvalid = -1,
|
||||
HAL_SPI_kOnboardCS0,
|
||||
HAL_SPI_kOnboardCS1,
|
||||
HAL_SPI_kOnboardCS2,
|
||||
HAL_SPI_kOnboardCS3,
|
||||
HAL_SPI_kMXP
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
30
hal/src/main/native/include/hal/SPITypes.h
Normal file
30
hal/src/main/native/include/hal/SPITypes.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
/**
|
||||
* @defgroup hal_spi SPI Functions
|
||||
* @ingroup hal_capi
|
||||
* @{
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
HAL_ENUM(HAL_SPIPort) {
|
||||
HAL_SPI_kInvalid = -1,
|
||||
HAL_SPI_kOnboardCS0,
|
||||
HAL_SPI_kOnboardCS1,
|
||||
HAL_SPI_kOnboardCS2,
|
||||
HAL_SPI_kOnboardCS3,
|
||||
HAL_SPI_kMXP
|
||||
};
|
||||
// clang-format on
|
||||
/** @} */
|
||||
@@ -7,13 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#define NativeThreadHandle const HANDLE*
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#define NativeThreadHandle const pthread_t*
|
||||
#endif
|
||||
#define NativeThreadHandle const void*
|
||||
|
||||
#include "hal/Types.h"
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Accelerometer.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
enum HALSIM_AnalogTriggerMode : int32_t {
|
||||
HALSIM_AnalogTriggerUnassigned,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "HAL_Value.h"
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
typedef void (*HAL_CAN_SendMessageCallback)(const char* name, void* param,
|
||||
uint32_t messageID,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/DriverStation.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/DriverStationTypes.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#ifndef __FRC_ROBORIO__
|
||||
|
||||
#include "NotifyListener.h"
|
||||
#include "hal/HAL.h"
|
||||
#include "hal/Types.h"
|
||||
|
||||
typedef void (*HAL_SpiReadAutoReceiveBufferCallback)(const char* name,
|
||||
void* param,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "AnalogInternal.h"
|
||||
#include "HALInitializer.h"
|
||||
#include "PortsInternal.h"
|
||||
#include "hal/AnalogAccumulator.h"
|
||||
#include "hal/handles/HandlesInternal.h"
|
||||
#include "mockdata/AnalogInDataInternal.h"
|
||||
|
||||
|
||||
@@ -149,8 +149,7 @@ char* HAL_GetJoystickName(int32_t joystickNum) {
|
||||
SimDriverStationData->GetJoystickDescriptor(joystickNum, &desc);
|
||||
size_t len = std::strlen(desc.name);
|
||||
char* name = static_cast<char*>(std::malloc(len + 1));
|
||||
std::strncpy(name, desc.name, len);
|
||||
name[len] = '\0';
|
||||
std::memcpy(name, desc.name, len + 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "DriverStationDataInternal.h"
|
||||
#include "hal/DriverStation.h"
|
||||
|
||||
namespace hal {
|
||||
struct JoystickOutputStore {
|
||||
|
||||
@@ -52,6 +52,7 @@ jar {
|
||||
model {
|
||||
components {
|
||||
myRobotCpp(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
baseName = 'FRCUserProgram'
|
||||
sources {
|
||||
cpp {
|
||||
@@ -75,6 +76,7 @@ model {
|
||||
}
|
||||
}
|
||||
myRobotCppStatic(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
baseName = 'FRCUserProgram'
|
||||
sources {
|
||||
cpp {
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
project(ntcore)
|
||||
|
||||
file(GLOB
|
||||
ntcore_native_src src/main/native/cpp/*.cpp
|
||||
ntcore_native_src src/main/native/cpp/networktables/*.cpp
|
||||
ntcore_native_src src/main/native/cpp/tables/*.cpp)
|
||||
add_library(ntcore ${ntcore_native_src})
|
||||
set_target_properties(ntcore PROPERTIES DEBUG_POSTFIX "d")
|
||||
target_include_directories(ntcore PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/ntcore>)
|
||||
target_link_libraries(ntcore PUBLIC wpiutil)
|
||||
|
||||
set_property(TARGET ntcore PROPERTY FOLDER "libraries")
|
||||
|
||||
install(TARGETS ntcore EXPORT ntcore DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/ntcore")
|
||||
|
||||
if (MSVC)
|
||||
set (ntcore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (ntcore_config_dir share/ntcore)
|
||||
endif()
|
||||
|
||||
install(FILES ntcore-config.cmake DESTINATION ${ntcore_config_dir})
|
||||
install(EXPORT ntcore DESTINATION ${ntcore_config_dir})
|
||||
|
||||
# Java bindings
|
||||
if (NOT WITHOUT_JAVA)
|
||||
@@ -26,42 +50,23 @@ if (NOT WITHOUT_JAVA)
|
||||
|
||||
set_property(TARGET ntcore_jar PROPERTY FOLDER "java")
|
||||
|
||||
endif()
|
||||
add_library(ntcorejni ${ntcore_jni_src})
|
||||
target_link_libraries(ntcorejni PUBLIC ntcore wpiutil)
|
||||
|
||||
file(GLOB
|
||||
ntcore_native_src src/main/native/cpp/*.cpp
|
||||
ntcore_native_src src/main/native/cpp/networktables/*.cpp
|
||||
ntcore_native_src src/main/native/cpp/tables/*.cpp)
|
||||
add_library(ntcore ${ntcore_native_src} ${ntcore_jni_src})
|
||||
target_include_directories(ntcore PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/ntcore>)
|
||||
target_link_libraries(ntcore PUBLIC wpiutil)
|
||||
set_property(TARGET ntcorejni PROPERTY FOLDER "libraries")
|
||||
|
||||
set_property(TARGET ntcore PROPERTY FOLDER "libraries")
|
||||
|
||||
if (NOT WITHOUT_JAVA)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
target_include_directories(ntcore PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(ntcore PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
else()
|
||||
target_link_libraries(ntcore PRIVATE ntcore_jni_headers)
|
||||
if (MSVC)
|
||||
install(TARGETS ntcorejni RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
add_dependencies(ntcore ntcore_jar)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.11.0")
|
||||
target_include_directories(ntcorejni PRIVATE ${JNI_INCLUDE_DIRS})
|
||||
target_include_directories(ntcorejni PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/jniheaders")
|
||||
else()
|
||||
target_link_libraries(ntcorejni PRIVATE ntcore_jni_headers)
|
||||
endif()
|
||||
add_dependencies(ntcorejni ntcore_jar)
|
||||
|
||||
install(TARGETS ntcorejni EXPORT ntcorejni DESTINATION "${main_lib_dest}")
|
||||
|
||||
endif()
|
||||
|
||||
install(TARGETS ntcore EXPORT ntcore DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/ntcore")
|
||||
|
||||
if (NOT WITHOUT_JAVA AND MSVC)
|
||||
install(TARGETS ntcore RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
set (ntcore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (ntcore_config_dir share/ntcore)
|
||||
endif()
|
||||
|
||||
install(FILES ntcore-config.cmake DESTINATION ${ntcore_config_dir})
|
||||
install(EXPORT ntcore DESTINATION ${ntcore_config_dir})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user