Compare commits

...

37 Commits

Author SHA1 Message Date
Peter Johnson
43d188a429 RobotBase: Call cscore Shutdown() from destructor 2018-11-09 23:33:55 -08:00
Peter Johnson
563d5334c9 Update OpenCV to 3.4.3-17 2018-11-09 23:33:55 -08:00
Peter Johnson
193b0a222c cscore: Add Shutdown() function
This allows ordered shutdown / destruction of sources and sinks prior to
global singleton destruction.
2018-11-09 23:33:55 -08:00
Peter Johnson
76f5d153fa wpiutil: Add Stop() to EventLoopRunner
This allows stopping the event loop without having to destroy the object.

Also fix ExecSync() to actually wait for the call to complete.
2018-11-09 23:33:55 -08:00
Peter Johnson
19caeca990 cscore: Use more standard naming for Instance public variables 2018-11-09 23:33:55 -08:00
Peter Johnson
0abae17653 cscore: Refactor sink and source creation
Also make sources and sinks members of Instance private, with appropriate
accessor functions.
2018-11-09 23:33:55 -08:00
Peter Johnson
81d10bc656 cscore: Build examples on Windows (#1421) 2018-11-09 22:42:04 -08:00
Austin Shalit
b51b86525d Stop webserver on test run (#1420) 2018-11-09 20:36:35 -08:00
Peter Johnson
ace37c517e CameraServer: enable usb cameras on non-Linux platforms (#1411) 2018-11-09 20:27:23 -08:00
Austin Schuh
ac751d3224 Fix unused variable warnings in ntcore (#1416)
This avoids -Wextra warnings.
2018-11-09 20:02:58 -08:00
Thad House
7c9a3c4d77 Update NI Library to 2019.7.1 and OpenCV to 3.4.3-16 (#1418)
Add def for each to eliminate duplication of version number.
2018-11-09 19:59:06 -08:00
Sam Carlberg
8be693f55d Fix list layout in shuffleboard example (#1413) 2018-11-09 01:14:15 -08:00
Peter Johnson
622ae29dff CameraServer: Change opencv sources to publish "cv:" type (#1412)
The LabVIEW dashboard has been fixed to understand this prefix.
2018-11-09 01:13:39 -08:00
Peter Johnson
e7c98feca2 libuv: Use WPI (FPGA) clock on roboRio (#1409)
This is set to the FPGA clock by HAL_Initialize.  Note this change means
that libuv loops should not be started until after HAL_Initialize is called (on the Rio).
Non-Rio functionality is unchanged.
2018-11-07 00:06:18 -08:00
Jaci Brunning
28087424ec Add deploy directory detection (#1400)
Add Filesystem class for java and namespace methods for C++ for detecting deploy location.
2018-11-02 13:16:44 -07:00
Peter Johnson
b6830638df NetworkListener: use Pimpl idiom (#1405)
This enables different platforms to use very different implementations.
2018-11-02 13:14:06 -07:00
Liam Kinne
fb557f49ea Add missing driver station documentation (#1388) 2018-11-01 23:34:48 -07:00
Peter Johnson
746f950a0b Remove ifdefs from linux NetworkListener (#1404) 2018-11-01 23:27:22 -07:00
Peter Johnson
9a38a3e188 Don't use static for raw_ostream outs/errs (#1401)
Static destruction order is not well defined, so it was possible for outs()
or errs() return value to be destroyed even while other code was running,
resulting in a crash.  Instead dynamically allocate the static so the
destructor never runs.  While this technically leaks, valgrind generally
supresses such leaks as the data is still "reachable" from the static pointer.
2018-11-01 10:48:50 -07:00
Thad House
2e3e3a47b9 Use a kill -9 after attemting a safe kill (#1397)
Should fix some deploy deadlocks.
2018-11-01 01:55:26 -07:00
Peter Johnson
e27d6d7bb8 cscore: Change impl to only one singleton (#1398)
This avoids a number of shutdown use-after-free races by controlling the
destruction order.  It also is a prerequisite to making the internal
interfaces mockable for unit testing.
2018-10-31 20:22:58 -07:00
Thad House
1dec0393a1 Fix static deletion race condition in DS thread (#1396)
The static condition variable was getting destroyed before the DS thread exited,
resulting in a deadlock on program exit when the DS thread tried to notify it.
This change moves the condition variable into the DS thread to avoid the race.
2018-10-30 11:51:17 -07:00
Peter Johnson
d03b020326 wpiutil: Add WorkerThread (#1302)
This provides a worker thread that can execute a work function with the result
going into either a future or a uv::Loop functor.
2018-10-29 20:54:42 -07:00
Austin Shalit
71e29b1d91 Remove unused import from rumble example (#1395)
This fixes a nit in #1394.
2018-10-29 20:54:15 -07:00
Thad House
f0b0965f9b Remove large HAL headers from wpilibc headers (#1386)
Now only includes the types in the wpilib headers.
Should immensely clean up intellisense.

Closes #1383
2018-10-29 12:49:17 -07:00
Austin Shalit
f774e47c80 Add an example showing how to use a hid rumbler (#1394) 2018-10-29 12:37:30 -07:00
Nicolas Machado
761933a164 Refactor Java Ultrasonic to use a List container (#1389) 2018-10-29 01:15:32 -07:00
Tyler Veness
99e0f08a6f Move applicable integration tests to native build as unit tests (#1364) 2018-10-29 00:12:38 -07:00
Tyler Veness
e89d5eb692 Fix stringop truncation warning from GCC 8.2 (#1393)
The next line adds a null terminator, but it's cleaner to just do a
std::memcpy() since the code already assumes a null terminator exists in
the source string.
2018-10-29 00:09:53 -07:00
Austin Shalit
2501e11886 Enable HTML5 javadocs (#1267)
This suppresses a build warning about HTML 4.01 being used.
2018-10-29 00:08:21 -07:00
Thad House
9174f23f36 Remove some usages of windows.h (#1370)
For HAL and wpilib, we don't need them, especially where they were being used.
2018-10-28 22:33:55 -07:00
Redrield
9f6544fa87 Allow binding commands to POV (#1378) 2018-10-28 21:54:06 -07:00
Peter Johnson
9a1af132bf Unify GetHostname() and use libuv implementation (#1391) 2018-10-28 19:01:48 -07:00
Thad House
a8aacd3657 Update build setup for raspbian and debug binaries (#1384)
- Build both debug and release binaries
- Append "d" to debug libraries in the style of opencv
- Split shared and static classifiers
- Add raspbian support
2018-10-27 00:19:38 -07:00
Peter Johnson
8ff81f5a2a cscore: Separate platform-specific sources (#1387) 2018-10-23 22:59:47 -07:00
Liam Kinne
349e273ecc AnalogGyro: add "calibrating for n seconds" message (#1380) 2018-10-23 00:29:23 -07:00
Tyler Veness
0a2ab4f0d7 Revert change in behavior in HeldButtonScheduler (#1381)
Originally, the command was restarted every time the scheduler was
executed if the button was pressed. #1340 changed this behavior in a
breaking manner.
2018-10-20 21:25:37 -07:00
182 changed files with 2860 additions and 1501 deletions

View File

@@ -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'

View File

@@ -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 {

View 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)
// }
// }
// }
}
}
}

View File

@@ -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
}
}

View File

@@ -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>)

View File

@@ -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:";
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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/
}

View File

@@ -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()

View File

@@ -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'

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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_

View File

@@ -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>{};

View File

@@ -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,

View 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);
}

View 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_

View File

@@ -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); }

View File

@@ -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_

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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),

View File

@@ -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;

View File

@@ -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) {}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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_

View 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"

View File

@@ -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);

View File

@@ -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

View File

@@ -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
}
/*

View File

@@ -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
* @{

View File

@@ -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
* @{

View File

@@ -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
}

View 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

View File

@@ -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;

View File

@@ -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__

View File

@@ -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;

View File

@@ -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__

View File

@@ -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};

View File

@@ -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

View File

@@ -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_

View 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() {}

View 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

View 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

View 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() {}

View 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

View 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

View File

@@ -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

View File

@@ -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})

View File

@@ -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
}
}
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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));
}
}
}

View File

@@ -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 {

View File

@@ -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

View 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
/** @} */

View File

@@ -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

View 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;
/** @} */

View File

@@ -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
/** @} */

View 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
/** @} */

View File

@@ -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

View 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
/** @} */

View File

@@ -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

View 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
/** @} */

View File

@@ -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"

View File

@@ -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" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -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,

View File

@@ -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,

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -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" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -10,7 +10,7 @@
#ifndef __FRC_ROBORIO__
#include "NotifyListener.h"
#include "hal/HAL.h"
#include "hal/Types.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -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,

View File

@@ -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"

View File

@@ -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;
}

View File

@@ -10,6 +10,7 @@
#include <string>
#include "DriverStationDataInternal.h"
#include "hal/DriverStation.h"
namespace hal {
struct JoystickOutputStore {

View File

@@ -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 {

View File

@@ -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