Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0559d9ea42 | |||
| 1c78fc5c31 | |||
| 3b224501c7 | |||
| 0dc8abaa28 | |||
| eb069c4a96 | |||
| 32e76c2ca5 | |||
| 4827177703 | |||
| d36d03dcc3 | |||
| 6362298016 | |||
| 6314b0182a | |||
| 0fefa5be7f | |||
| 7ea31cdb8d | |||
| d217354689 | |||
| bb7be7fb3c | |||
| ee8fca3008 | |||
| 525af45fd4 | |||
| 3ff329a553 | |||
| 66257bcd0e | |||
| 6ef86eea05 | |||
| 8f41e164a2 | |||
| b9ca38bff1 | |||
| e024ccdf95 | |||
| f3f2384f9b | |||
| cd63593ae5 | |||
| 58dbc7e320 | |||
| e3795c4233 | |||
| edc198dd00 | |||
| 2bf7390f97 | |||
| 1ea1b4b9f6 | |||
| c14208f6ce | |||
| f4ff8f0e40 | |||
| ba3841c30b | |||
| 4a8cb12294 | |||
| b6b2ce7ada | |||
| 7bee9b07ae | |||
| d26b791dd2 | |||
| 7579446388 | |||
| 099d60bcc4 | |||
| 42b32f27e6 | |||
| c457ee7aca | |||
| e2e589dc17 | |||
| d4898bbca1 | |||
| e836b2bf32 | |||
| fef73692f7 | |||
| 285b63b618 | |||
| 1deb92a416 | |||
| 6f6fa77498 | |||
| 79825e4da3 | |||
| 6114a2648d | |||
| 4a3daaf403 | |||
| 49c8b5bca1 | |||
| a2598e80fd | |||
| 4fde28dad8 | |||
| e276fcbdce | |||
| 36c79f3a2e | |||
| 513405a831 | |||
| 7b962a75d3 | |||
| 270437fdd4 | |||
| a17c940377 | |||
| b28239550e | |||
| 1e17b83061 | |||
| 1bf5f46404 | |||
| 064dc43fbc | |||
| 020a4968e5 | |||
| d0aa8e2306 | |||
| 79f3e84ff8 | |||
| 756571b9b4 | |||
| 9c16aeeb55 | |||
| d6a0b0301e | |||
| e87656fd12 | |||
| f06aeb6c9b | |||
| c58d422158 | |||
| 8dfb1e5b2f | |||
| 50b8aaf34d | |||
| 0f5e499d7c | |||
| 710749c399 | |||
| 3503cce0db | |||
| 90a0eebdd8 | |||
| 1540af1e74 | |||
| 065b2593f4 | |||
| e7974db324 | |||
| 336094ef90 | |||
| d43a8af6bd | |||
| 37ad6995c3 | |||
| c9e8a9f1fb | |||
| dacc050bf9 | |||
| f8825942b1 | |||
| e201b5e695 | |||
| 29a1e1ecf2 | |||
| a5c2f47e9f | |||
| 42f55bb324 | |||
| 1450d745ab | |||
| 76141e3a92 | |||
| 36592293dd | |||
| f1696f8272 | |||
| 99c126a08c | |||
| 293c1054d1 | |||
| 38298a8ef8 | |||
| 2b8b176038 | |||
| 76e465bd1d | |||
| ead7d8ff5f | |||
| 9cc7a6685c |
+5
-1
@@ -1,10 +1,14 @@
|
|||||||
|
/build
|
||||||
|
/b-*
|
||||||
*~
|
*~
|
||||||
**/.deps/
|
**/.deps/
|
||||||
**/Makefile.in
|
**/Makefile.in
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
/b
|
/b
|
||||||
|
/bautotools
|
||||||
/autotools-aux
|
/autotools-aux
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
config.h.in
|
config.h.in
|
||||||
configure
|
configure
|
||||||
|
*.swp
|
||||||
|
cscope.out
|
||||||
|
|||||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**",
|
"${workspaceFolder}/**",
|
||||||
"${workspaceFolder}/include",
|
"${workspaceFolder}/include",
|
||||||
"${workspaceFolder}/hcore/include",
|
"${workspaceFolder}/smocore/include",
|
||||||
"/usr/include",
|
"/usr/include",
|
||||||
"/usr/local/include",
|
"/usr/local/include",
|
||||||
"${workspaceFolder}/b/include"
|
"${workspaceFolder}/b/include"
|
||||||
|
|||||||
Vendored
+145
-11
@@ -5,13 +5,39 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "C++ Launch",
|
"name": "Debug salmanoff (Basic)",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/b/harikoff",
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}/b",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set disassembly flavor to intel",
|
||||||
|
"text": "set disassembly-flavor intel",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build-salmanoff",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug salmanoff (Help)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"args": ["--help"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/b",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
"MIMode": "gdb",
|
"MIMode": "gdb",
|
||||||
@@ -22,15 +48,123 @@
|
|||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"preLaunchTask": "Build",
|
"preLaunchTask": "build-salmanoff",
|
||||||
"miDebuggerPath": "/usr/bin/gdb",
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
"logging": {
|
},
|
||||||
"trace": true,
|
{
|
||||||
"traceResponse": true,
|
"name": "Debug salmanoff (Verbose)",
|
||||||
"engineLogging": true,
|
"type": "cppdbg",
|
||||||
"programOutput": true,
|
"request": "launch",
|
||||||
"exceptions": true
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"args": ["--verbose"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/b",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build-salmanoff",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug salmanoff (Custom Args)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"args": ["--devicespec", "test_device", "--verbose"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/b",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build-salmanoff",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Attach to salmanoff (Remote Debug)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "attach",
|
||||||
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"processId": "${command:pickProcess}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug salmanoff (Break on Main)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"args": ["--help"],
|
||||||
|
"stopAtEntry": true,
|
||||||
|
"cwd": "${workspaceFolder}/b",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set breakpoint on main",
|
||||||
|
"text": "break main",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build-salmanoff",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug salmanoff (ComponentThread Focus)",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/b/salmanoff",
|
||||||
|
"args": ["--help"],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/b",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set breakpoint on ComponentThread constructor",
|
||||||
|
"text": "break ComponentThread::ComponentThread",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Set breakpoint on Mind constructor",
|
||||||
|
"text": "break Mind::Mind",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "build-salmanoff",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+6
-2
@@ -73,7 +73,11 @@
|
|||||||
"source_location": "cpp",
|
"source_location": "cpp",
|
||||||
"future": "cpp",
|
"future": "cpp",
|
||||||
"shared_mutex": "cpp",
|
"shared_mutex": "cpp",
|
||||||
"typeindex": "cpp"
|
"typeindex": "cpp",
|
||||||
|
"bitset": "cpp"
|
||||||
},
|
},
|
||||||
"editor.rulers": [80, 120]
|
"editor.rulers": [80, 120],
|
||||||
|
"editor.tabSize": 4,
|
||||||
|
"editor.insertSpaces": false,
|
||||||
|
"editor.detectIndentation": false
|
||||||
}
|
}
|
||||||
Vendored
+53
-43
@@ -2,68 +2,78 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "Create Build Directory",
|
"label": "build-salmanoff",
|
||||||
"type": "shell",
|
|
||||||
"command": "mkdir -p b",
|
|
||||||
"problemMatcher": [],
|
|
||||||
"detail": "Creates the build directory."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Configure",
|
|
||||||
"type": "shell",
|
|
||||||
"command": "${workspaceFolder}/configure",
|
|
||||||
"options": {
|
|
||||||
"cwd": "${workspaceFolder}/b"
|
|
||||||
},
|
|
||||||
"group": {
|
|
||||||
"kind": "build",
|
|
||||||
"isDefault": true
|
|
||||||
},
|
|
||||||
"problemMatcher": ["$gcc"],
|
|
||||||
"dependsOn": ["Create Build Directory"],
|
|
||||||
"detail": "Runs the configure script to prepare the build environment."
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"label": "Build",
|
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make",
|
"command": "make",
|
||||||
"options": {
|
|
||||||
"cwd": "${workspaceFolder}/b"
|
|
||||||
},
|
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
},
|
},
|
||||||
"problemMatcher": ["$gcc"],
|
"presentation": {
|
||||||
"dependsOn": ["Configure"],
|
"echo": true,
|
||||||
"detail": "Builds the project using make."
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": false
|
||||||
|
},
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/b"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "clean",
|
"label": "clean-salmanoff",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make clean",
|
"command": "make clean",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": false
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/b"
|
"cwd": "${workspaceFolder}/b"
|
||||||
},
|
}
|
||||||
"group": {
|
|
||||||
"kind": "none"
|
|
||||||
},
|
|
||||||
"problemMatcher": [],
|
|
||||||
"detail": "Cleans the build artifacts."
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "test",
|
"label": "rebuild-salmanoff",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make test",
|
"command": "make clean && make",
|
||||||
|
"group": "build",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": false
|
||||||
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/b"
|
"cwd": "${workspaceFolder}/b"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"group": {
|
{
|
||||||
"kind": "test",
|
"label": "run-salmanoff-help",
|
||||||
"isDefault": true
|
"type": "shell",
|
||||||
|
"command": "./salmanoff --help",
|
||||||
|
"group": "test",
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": true,
|
||||||
|
"clear": false
|
||||||
},
|
},
|
||||||
"problemMatcher": ["$gcc"],
|
"options": {
|
||||||
"detail": "Runs the tests."
|
"cwd": "${workspaceFolder}/b"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(salmanoff VERSION 0.00.004 LANGUAGES CXX)
|
||||||
|
|
||||||
|
include(CMakeDependentOption)
|
||||||
|
|
||||||
|
# Set C++ standard
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Build type
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Compiler flags
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
|
||||||
|
|
||||||
|
# Mind oscillator configuration
|
||||||
|
set(MIND_VOSCILLATOR_PERIOD_MS 33 CACHE STRING "Mind's virtual osc clock rate (ms)")
|
||||||
|
if(NOT MIND_VOSCILLATOR_PERIOD_MS GREATER 0)
|
||||||
|
message(FATAL_ERROR "MIND_VOSCILLATOR_PERIOD_MS must be a positive integer > 0")
|
||||||
|
endif()
|
||||||
|
math(EXPR MIND_VOSCILLATOR_FREQ_MS "1000 / ${MIND_VOSCILLATOR_PERIOD_MS}")
|
||||||
|
|
||||||
|
# Configure config.h
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/include/config.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include directories
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/smocore/include
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Find core dependencies
|
||||||
|
find_package(Boost 1.69.0 REQUIRED COMPONENTS system)
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
find_package(FLEX REQUIRED)
|
||||||
|
find_package(BISON REQUIRED)
|
||||||
|
|
||||||
|
# Need dlopen() and dlsym()
|
||||||
|
find_library(DL_LIBRARY NAMES dl ldl)
|
||||||
|
if(NOT DL_LIBRARY)
|
||||||
|
message(FATAL_ERROR "Dynamic linking library (libdl/libldl) not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add core components
|
||||||
|
add_subdirectory(smocore)
|
||||||
|
add_subdirectory(commonLibs)
|
||||||
|
add_subdirectory(senseApis)
|
||||||
|
add_subdirectory(wilzorApis)
|
||||||
|
|
||||||
|
# Main executable
|
||||||
|
add_executable(salmanoff main.cpp)
|
||||||
|
target_link_libraries(salmanoff
|
||||||
|
smocore
|
||||||
|
marionette
|
||||||
|
deviceManager
|
||||||
|
senseApis
|
||||||
|
${Boost_LIBRARIES}
|
||||||
|
${DL_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS salmanoff DESTINATION bin)
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
SUBDIRS = hcore senseApis
|
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I m4
|
|
||||||
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
|
||||||
|
|
||||||
bin_PROGRAMS = harikoff
|
|
||||||
harikoff_SOURCES = main.cpp
|
|
||||||
harikoff_LDADD = hcore/libhcore.a hcore/deviceManager/libdeviceManager.a \
|
|
||||||
hcore/senseApis/libsenseApis.a
|
|
||||||
@@ -1,5 +1,10 @@
|
|||||||
# The Harriman-Peikoff Project
|
# The Salmanoff Project:
|
||||||
|
|
||||||
Wouldn't you like to know what this project is and does? Well, it's a secret!
|

|
||||||
But you can find out by reading the code. Or you could just ask me. Or you
|
|
||||||
could wait until I release it. But that's no fun.
|
This project, Salmanoff (pronounced: Sal-man-off), is an ROS rewrite of the Harikoff project. The name is more reflective of the people whose ideas sparked the solutions in my mind. These people are:
|
||||||
|
* Gregory `SAL`mieri.
|
||||||
|
* David Harri`MAN`.
|
||||||
|
* Leonard Peik`OFF`.
|
||||||
|
|
||||||
|
Would you like to know what this project is and does? Well, it's a secret! But you can find out by reading the code. Or you could just ask me. Or you could wait until I release it. But that's no fun.
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# Cross-compilation toolchain file for aarch64-linux-gnu
|
||||||
|
# This file should be used with cmake -DCMAKE_TOOLCHAIN_FILE=cmake/aarch64-linux-gnu.cmake
|
||||||
|
|
||||||
|
# Disable some features that might not be available in cross-compilation
|
||||||
|
set(CMAKE_CROSSCOMPILING TRUE)
|
||||||
|
|
||||||
|
# Target OS.
|
||||||
|
set(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
# Use whatever the host system version is.
|
||||||
|
# set(CMAKE_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION})
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||||
|
|
||||||
|
# Specify the cross compilers.
|
||||||
|
# We could do some more advanced stuff here to search for the correct
|
||||||
|
# cross-compiler based on CMAKE_SYSTEM_NAME & CMAKE_SYSTEM_PROCESSOR.
|
||||||
|
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
|
||||||
|
# These are necessary for CLang.
|
||||||
|
# set(CMAKE_C_COMPILER_TARGET aarch64-linux-gnu)
|
||||||
|
# set(CMAKE_CXX_COMPILER_TARGET aarch64-linux-gnu)
|
||||||
|
|
||||||
|
# Set architecture-specific flags
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a -mtune=cortex-a72")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=armv8-a -mtune=cortex-a72")
|
||||||
|
|
||||||
|
# Set the target environment
|
||||||
|
set(CMAKE_FIND_ROOT_PATH /usr/aarch64-linux-gnu)
|
||||||
|
|
||||||
|
# Search for programs in the build host directories
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
# Search for libraries and headers in the target directories
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH)
|
||||||
|
|
||||||
|
# Set pkg-config to use the cross-compiled libraries
|
||||||
|
set(ENV{PKG_CONFIG_PATH} "/usr/aarch64-linux-gnu/lib/pkgconfig:/usr/lib/aarch64-linux-gnu/pkgconfig")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(xcbXorg)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
option(ENABLE_LIB_xcbXorg "Enable XCB/Xorg Connection Manager backend lib" ON)
|
||||||
|
|
||||||
|
if(ENABLE_LIB_xcbXorg)
|
||||||
|
pkg_check_modules(XCB REQUIRED xcb)
|
||||||
|
if(NOT XCB_FOUND)
|
||||||
|
message(FATAL_ERROR "XCB library not found. XCB/Xorg requires the XCB dev headers and shlib.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_library(xcbXorg SHARED
|
||||||
|
xcbXorg.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set config define for header generation
|
||||||
|
add_compile_definitions(CONFIG_LIB_XCBXORG_ENABLED)
|
||||||
|
target_include_directories(xcbXorg PUBLIC ${XCB_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(xcbXorg ${XCB_LIBRARIES})
|
||||||
|
|
||||||
|
# Install rules
|
||||||
|
install(TARGETS xcbXorg DESTINATION lib)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
#include <atomic>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#include "xcbXorg.h"
|
||||||
|
|
||||||
|
namespace xcb_xorg {
|
||||||
|
|
||||||
|
// Static member initialization
|
||||||
|
std::map<ConnectionIdentifier, std::shared_ptr<XcbConnection>>
|
||||||
|
ConnectionManager::connections;
|
||||||
|
|
||||||
|
std::string ConnectionIdentifier::stringify() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "display=" << display << ", screen=" << screen;
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
XcbConnection::XcbConnection(const ConnectionIdentifier& id)
|
||||||
|
: connection(nullptr, &xcb_disconnect),
|
||||||
|
connectionIdentifier(id), refCount(0)
|
||||||
|
{
|
||||||
|
// Convert to X display string format (e.g., ":0.1")
|
||||||
|
std::string displayString = ":" + std::to_string(id.display)
|
||||||
|
+ "." + std::to_string(id.screen);
|
||||||
|
|
||||||
|
int screenNum;
|
||||||
|
|
||||||
|
connection.reset(xcb_connect(displayString.c_str(), &screenNum));
|
||||||
|
if (xcb_connection_has_error(connection.get()))
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(__func__) + ": Failed to connect to X server "
|
||||||
|
+ connectionIdentifier.stringify());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify we got the screen we asked for
|
||||||
|
if (screenNum != id.screen)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(__func__) + ": Connected to wrong screen. "
|
||||||
|
"Requested " + connectionIdentifier.stringify()
|
||||||
|
+ " but got screen " + std::to_string(screenNum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<XcbConnection> ConnectionManager::getOrCreateConnection(
|
||||||
|
const ConnectionIdentifier& id)
|
||||||
|
{
|
||||||
|
auto it = connections.find(id);
|
||||||
|
if (it != connections.end()) {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conn = std::make_shared<XcbConnection>(id);
|
||||||
|
connections.emplace(id, conn);
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConnectionManager::cleanupAllConnections()
|
||||||
|
{
|
||||||
|
connections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ConnectionManager::getConnectionCount()
|
||||||
|
{
|
||||||
|
return connections.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a specific connection from the manager
|
||||||
|
* @param id Connection identifier to remove
|
||||||
|
*/
|
||||||
|
void ConnectionManager::removeConnection(const ConnectionIdentifier& id)
|
||||||
|
{
|
||||||
|
auto it = connections.find(id);
|
||||||
|
if (it != connections.end()) {
|
||||||
|
connections.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace window_search {
|
||||||
|
|
||||||
|
struct XcbReplyDeleter {
|
||||||
|
void operator()(xcb_query_tree_reply_t* p) { free(p); }
|
||||||
|
void operator()(xcb_get_property_reply_t* p) { free(p); }
|
||||||
|
};
|
||||||
|
|
||||||
|
xcb_window_t findById(
|
||||||
|
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId)
|
||||||
|
{
|
||||||
|
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
|
||||||
|
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
|
||||||
|
xcb_query_tree_reply(conn, cookie, nullptr));
|
||||||
|
|
||||||
|
if (!reply) return 0;
|
||||||
|
|
||||||
|
if (root == targetId) return root;
|
||||||
|
|
||||||
|
xcb_window_t* children = xcb_query_tree_children(reply.get());
|
||||||
|
int num_children = xcb_query_tree_children_length(reply.get());
|
||||||
|
|
||||||
|
for (int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
if (children[i] == targetId) {
|
||||||
|
return children[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively search this child's subtree
|
||||||
|
if (xcb_window_t result = findById(conn, children[i], targetId)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_window_t findByName(
|
||||||
|
xcb_connection_t* conn, xcb_window_t root,
|
||||||
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
MatchType matchType)
|
||||||
|
{
|
||||||
|
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
|
||||||
|
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
|
||||||
|
xcb_query_tree_reply(conn, cookie, nullptr));
|
||||||
|
|
||||||
|
if (!reply) return 0;
|
||||||
|
|
||||||
|
// First check current window
|
||||||
|
xcb_get_property_cookie_t prop_cookie = xcb_get_property(
|
||||||
|
conn, 0, root, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
|
||||||
|
|
||||||
|
std::unique_ptr<xcb_get_property_reply_t, XcbReplyDeleter> prop_reply(
|
||||||
|
xcb_get_property_reply(conn, prop_cookie, nullptr));
|
||||||
|
|
||||||
|
if (prop_reply)
|
||||||
|
{
|
||||||
|
int len = xcb_get_property_value_length(prop_reply.get());
|
||||||
|
char* name = static_cast<char*>(
|
||||||
|
xcb_get_property_value(prop_reply.get()));
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
std::string windowName(name, len);
|
||||||
|
if ((matchType == MatchType::EXACT
|
||||||
|
&& windowName == targetName)
|
||||||
|
|| (matchType == MatchType::SUBSTRING
|
||||||
|
&& windowName.find(targetName) != std::string::npos))
|
||||||
|
{
|
||||||
|
outWindowName = windowName;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then check all children
|
||||||
|
xcb_window_t* children = xcb_query_tree_children(reply.get());
|
||||||
|
int num_children = xcb_query_tree_children_length(reply.get());
|
||||||
|
|
||||||
|
for (int i = 0; i < num_children; ++i)
|
||||||
|
{
|
||||||
|
prop_cookie = xcb_get_property(
|
||||||
|
conn, 0, children[i],
|
||||||
|
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
|
||||||
|
|
||||||
|
prop_reply.reset(xcb_get_property_reply(conn, prop_cookie, nullptr));
|
||||||
|
if (prop_reply)
|
||||||
|
{
|
||||||
|
int len = xcb_get_property_value_length(prop_reply.get());
|
||||||
|
char* name = static_cast<char*>(xcb_get_property_value(
|
||||||
|
prop_reply.get()));
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
std::string windowName(name, len);
|
||||||
|
if ((matchType == MatchType::EXACT
|
||||||
|
&& windowName == targetName)
|
||||||
|
|| (matchType == MatchType::SUBSTRING
|
||||||
|
&& windowName.find(targetName) != std::string::npos))
|
||||||
|
{
|
||||||
|
outWindowName = windowName;
|
||||||
|
return children[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively search this child's subtree
|
||||||
|
if (xcb_window_t result = findByName(
|
||||||
|
conn, children[i], targetName, outWindowName, matchType))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace window_search
|
||||||
|
|
||||||
|
} // namespace xcb_xorg
|
||||||
|
|
||||||
|
// Export functions for external libraries
|
||||||
|
/**
|
||||||
|
* @brief Get or create a connection to the X server
|
||||||
|
* @param display Display number
|
||||||
|
* @param screen Screen number
|
||||||
|
* @return Shared pointer to connection (as void* for C compatibility)
|
||||||
|
*/
|
||||||
|
extern "C" get_or_create_connection_fn xcb_xorg_get_or_create_connection;
|
||||||
|
std::shared_ptr<xcb_xorg::XcbConnection> xcb_xorg_get_or_create_connection(
|
||||||
|
int display, int screen)
|
||||||
|
{
|
||||||
|
xcb_xorg::ConnectionIdentifier id{display, screen};
|
||||||
|
auto conn = xcb_xorg::ConnectionManager::getOrCreateConnection(id);
|
||||||
|
conn->incrementRefCount();
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clean up all connections
|
||||||
|
*/
|
||||||
|
extern "C" cleanup_connections_fn xcb_xorg_cleanup_connections;
|
||||||
|
void xcb_xorg_cleanup_connections()
|
||||||
|
{
|
||||||
|
xcb_xorg::ConnectionManager::cleanupAllConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the number of active connections
|
||||||
|
* @return Number of active connections
|
||||||
|
*/
|
||||||
|
size_t xcb_xorg_get_connection_count()
|
||||||
|
{
|
||||||
|
return xcb_xorg::ConnectionManager::getConnectionCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find window by ID
|
||||||
|
* @param conn Connection pointer (from xcb_xorg_get_connection)
|
||||||
|
* @param root Root window
|
||||||
|
* @param targetId Target window ID
|
||||||
|
* @return Window ID if found, 0 if not found
|
||||||
|
*/
|
||||||
|
extern "C" find_window_by_id_fn xcb_xorg_find_window_by_id;
|
||||||
|
xcb_window_t xcb_xorg_find_window_by_id(void* conn, xcb_window_t root, uint32_t targetId)
|
||||||
|
{
|
||||||
|
if (!conn) return 0;
|
||||||
|
auto connection = static_cast<xcb_xorg::XcbConnection*>(conn);
|
||||||
|
return xcb_xorg::window_search::findById(
|
||||||
|
connection->getConnection(), root, targetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find window by name
|
||||||
|
* @param conn Connection pointer (from xcb_xorg_get_connection)
|
||||||
|
* @param root Root window
|
||||||
|
* @param targetName Target window name
|
||||||
|
* @param outWindowName Output parameter for actual window name
|
||||||
|
* @param matchType Type of name matching
|
||||||
|
* @return Window ID if found, 0 if not found
|
||||||
|
*/
|
||||||
|
extern "C" find_window_by_name_fn xcb_xorg_find_window_by_name;
|
||||||
|
xcb_window_t xcb_xorg_find_window_by_name(void* conn, xcb_window_t root,
|
||||||
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
xcb_xorg::window_search::MatchType matchType)
|
||||||
|
{
|
||||||
|
if (!conn) return 0;
|
||||||
|
auto connection = static_cast<xcb_xorg::XcbConnection*>(conn);
|
||||||
|
return xcb_xorg::window_search::findByName(
|
||||||
|
connection->getConnection(), root, targetName, outWindowName,
|
||||||
|
matchType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dereference a connection (decrements ref count and closes if zero)
|
||||||
|
* @param conn Shared pointer to the connection to dereference
|
||||||
|
*/
|
||||||
|
extern "C" dereference_connection_fn xcb_xorg_dereference_connection;
|
||||||
|
void xcb_xorg_dereference_connection(std::shared_ptr<xcb_xorg::XcbConnection> conn)
|
||||||
|
{
|
||||||
|
if (!conn) return;
|
||||||
|
|
||||||
|
int newRefCount = conn->decrementRefCount();
|
||||||
|
// Remove from connection manager if ref count reaches zero
|
||||||
|
if (newRefCount <= 0) {
|
||||||
|
xcb_xorg::ConnectionManager::removeConnection(conn->getIdentifier());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
#ifndef XCB_XORG_API_H
|
||||||
|
#define XCB_XORG_API_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include <map>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
namespace xcb_xorg {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Connection identifier for X server connections
|
||||||
|
*/
|
||||||
|
struct ConnectionIdentifier
|
||||||
|
{
|
||||||
|
int display;
|
||||||
|
int screen;
|
||||||
|
|
||||||
|
bool operator<(const ConnectionIdentifier& other) const
|
||||||
|
{
|
||||||
|
if (display != other.display) return display < other.display;
|
||||||
|
return screen < other.screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string stringify() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents a single X server connection using XCB
|
||||||
|
*
|
||||||
|
* This class manages a single connection to the X server. It provides
|
||||||
|
* RAII management for the connection and maintains a reference count
|
||||||
|
* for shared usage.
|
||||||
|
*/
|
||||||
|
class XcbConnection
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor for creating a new connection
|
||||||
|
* @param id Connection identifier specifying display and screen
|
||||||
|
* @throws std::runtime_error if connection fails
|
||||||
|
*/
|
||||||
|
explicit XcbConnection(const ConnectionIdentifier& id);
|
||||||
|
|
||||||
|
// Delete copy/move operations - we'll manage instances through pointers
|
||||||
|
XcbConnection(const XcbConnection&) = delete;
|
||||||
|
XcbConnection& operator=(const XcbConnection&) = delete;
|
||||||
|
XcbConnection(XcbConnection&&) = delete;
|
||||||
|
XcbConnection& operator=(XcbConnection&&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor - automatically closes the connection
|
||||||
|
*/
|
||||||
|
~XcbConnection() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the underlying XCB connection
|
||||||
|
* @return Raw XCB connection pointer
|
||||||
|
*/
|
||||||
|
xcb_connection_t* getConnection() const { return connection.get(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the connection identifier
|
||||||
|
* @return Connection identifier
|
||||||
|
*/
|
||||||
|
const ConnectionIdentifier& getIdentifier() const { return connectionIdentifier; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Increment reference count
|
||||||
|
*/
|
||||||
|
void incrementRefCount() { refCount++; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrement reference count
|
||||||
|
* @return New reference count
|
||||||
|
*/
|
||||||
|
int decrementRefCount() { return --refCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get current reference count
|
||||||
|
* @return Current reference count
|
||||||
|
*/
|
||||||
|
int getRefCount() const { return refCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if connection is valid
|
||||||
|
* @return true if connection is valid, false otherwise
|
||||||
|
*/
|
||||||
|
bool isValid() const { return connection && !xcb_connection_has_error(connection.get()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<xcb_connection_t, decltype(&xcb_disconnect)> connection;
|
||||||
|
ConnectionIdentifier connectionIdentifier;
|
||||||
|
std::atomic<int> refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Manages multiple X server connections
|
||||||
|
*
|
||||||
|
* This class manages a collection of XcbConnection instances. It ensures
|
||||||
|
* that each unique display and screen combination has a single connection,
|
||||||
|
* and provides RAII management for these connections.
|
||||||
|
*/
|
||||||
|
class ConnectionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get or create a connection to the X server
|
||||||
|
* @param id Connection identifier specifying display and screen
|
||||||
|
* @return Shared pointer to the connection
|
||||||
|
* @throws std::runtime_error if connection fails
|
||||||
|
*/
|
||||||
|
static std::shared_ptr<XcbConnection> getOrCreateConnection(
|
||||||
|
const ConnectionIdentifier& id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clean up all connections
|
||||||
|
*/
|
||||||
|
static void cleanupAllConnections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the number of active connections
|
||||||
|
* @return Number of active connections
|
||||||
|
*/
|
||||||
|
static size_t getConnectionCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a specific connection from the manager
|
||||||
|
* @param id Connection identifier to remove
|
||||||
|
*/
|
||||||
|
static void removeConnection(const ConnectionIdentifier& id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::map<ConnectionIdentifier, std::shared_ptr<XcbConnection>> connections;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Window search functionality
|
||||||
|
*/
|
||||||
|
namespace window_search {
|
||||||
|
|
||||||
|
enum class MatchType { SUBSTRING, EXACT, ID };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find window by ID
|
||||||
|
* @param conn XCB connection
|
||||||
|
* @param root Root window
|
||||||
|
* @param targetId Target window ID
|
||||||
|
* @return Window ID if found, 0 if not found
|
||||||
|
*/
|
||||||
|
xcb_window_t findById(xcb_connection_t* conn, xcb_window_t root, uint32_t targetId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find window by name
|
||||||
|
* @param conn XCB connection
|
||||||
|
* @param root Root window
|
||||||
|
* @param targetName Target window name
|
||||||
|
* @param outWindowName Output parameter for actual window name
|
||||||
|
* @param matchType Type of name matching to perform
|
||||||
|
* @return Window ID if found, 0 if not found
|
||||||
|
*/
|
||||||
|
xcb_window_t findByName(xcb_connection_t* conn, xcb_window_t root,
|
||||||
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
MatchType matchType);
|
||||||
|
|
||||||
|
} // namespace window_search
|
||||||
|
|
||||||
|
} // namespace xcb_xorg
|
||||||
|
|
||||||
|
// Function signature types for dynamic loading of libxcbXorg
|
||||||
|
typedef std::shared_ptr<xcb_xorg::XcbConnection> get_or_create_connection_fn(
|
||||||
|
int display, int screen);
|
||||||
|
typedef void cleanup_connections_fn();
|
||||||
|
typedef void dereference_connection_fn(
|
||||||
|
std::shared_ptr<xcb_xorg::XcbConnection> conn);
|
||||||
|
typedef xcb_window_t find_window_by_id_fn(
|
||||||
|
void* conn, xcb_window_t root, uint32_t targetId);
|
||||||
|
typedef xcb_window_t find_window_by_name_fn(void* conn, xcb_window_t root,
|
||||||
|
const std::string& targetName, std::string& outWindowName,
|
||||||
|
xcb_xorg::window_search::MatchType matchType);
|
||||||
|
|
||||||
|
#endif // XCB_XORG_API_H
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
AC_INIT([Harriman-Peikoff Project], [0.00.002],
|
|
||||||
[latentprion@gmail.com],
|
|
||||||
[harikoff],
|
|
||||||
[http://github.com/latentprion/harikoff])
|
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([hcore/mind.cpp])
|
|
||||||
AC_CONFIG_AUX_DIR([autotools-aux])
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([foreign -Wall -Werror])
|
|
||||||
|
|
||||||
# Set the mind's quantized virtual oscillator period in milliseconds.
|
|
||||||
# Default value is 33 ms, user override via MIND_VOSCILLATOR_PERIOD_MS.
|
|
||||||
# Check if MIND_VOSCILLATOR_PERIOD_MS is a valid positive integer
|
|
||||||
AC_ARG_VAR([MIND_VOSCILLATOR_PERIOD_MS], m4_normalize([
|
|
||||||
Mind's virtual osc clock rate. Must be a positive integer, default value 33
|
|
||||||
]))
|
|
||||||
AS_IF([test -z "${MIND_VOSCILLATOR_PERIOD_MS}"], [MIND_VOSCILLATOR_PERIOD_MS=33])
|
|
||||||
AS_IF([! test "${MIND_VOSCILLATOR_PERIOD_MS}" -eq "${MIND_VOSCILLATOR_PERIOD_MS}" 2>/dev/null ||
|
|
||||||
test "${MIND_VOSCILLATOR_PERIOD_MS}" -le 0 2>/dev/null], [
|
|
||||||
AC_MSG_ERROR([MIND_VOSCILLATOR_PERIOD_MS must be a positive integer > 0.])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFINE_UNQUOTED([CONFIG_MIND_VOSCILLATOR_PERIOD_MS],
|
|
||||||
[${MIND_VOSCILLATOR_PERIOD_MS}],
|
|
||||||
[Period of the mind virtual oscillator in milliseconds])
|
|
||||||
AC_COMPUTE_INT(
|
|
||||||
[MIND_VOSCILLATOR_FREQ_MS], [1000 / ${MIND_VOSCILLATOR_PERIOD_MS}], [],
|
|
||||||
[AC_MSG_ERROR([Failed to compute the mind's virtual oscillator frequency.])])
|
|
||||||
AC_DEFINE_UNQUOTED([CONFIG_MIND_VOSCILLATOR_FREQ_MS],
|
|
||||||
[${MIND_VOSCILLATOR_FREQ_MS}],
|
|
||||||
[Frequency of the mind virtual oscillator in milliseconds])
|
|
||||||
|
|
||||||
m4_include([m4/ax_boost_base.m4])
|
|
||||||
m4_include([m4/ax_boost_asio_1.69.0.m4])
|
|
||||||
m4_include([m4/ac_prog_flex.m4])
|
|
||||||
m4_include([m4/ac_prog_bison.m4])
|
|
||||||
AC_PROG_CC
|
|
||||||
AC_PROG_CXX
|
|
||||||
AM_PROG_AR
|
|
||||||
LT_INIT([shared])
|
|
||||||
AC_PROG_LEX([noyywrap])
|
|
||||||
AC_PROG_YACC
|
|
||||||
AS_IF([test -z "${LEX}" || test -z "${YACC}"], [
|
|
||||||
AC_MSG_ERROR([LEX and YACC must both be available in PATH.])
|
|
||||||
])
|
|
||||||
AX_BOOST_BASE([1.69.0], [], [AC_MSG_ERROR(m4_normalize([Boost v1.69.0 or higher
|
|
||||||
is required, because Boost.System is header-only from 1.69.0 onwards.]))])
|
|
||||||
AX_BOOST_ASIO_gte_1_69_0
|
|
||||||
AS_IF([test "x${HAVE_BOOST_ASIO}" == "x"], [
|
|
||||||
AC_MSG_ERROR(m4_normalize([Boost.Asio must be available in headers.
|
|
||||||
Try --with-boost-asio if need be.]))
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_SEARCH_LIBS([dlopen], [dl ldl], [], [
|
|
||||||
AC_MSG_ERROR([dlopen() not found in libdl or libldl.])])
|
|
||||||
AC_SEARCH_LIBS([dlsym], [dl ldl], [], [
|
|
||||||
AC_MSG_ERROR([dlsym() not found in libdl or libldl.])])
|
|
||||||
|
|
||||||
AM_CPPFLAGS=m4_normalize(["-I\"\$(top_srcdir)/include\"
|
|
||||||
-Wall -Wextra -pedantic"])
|
|
||||||
|
|
||||||
AC_SUBST([AM_CPPFLAGS])
|
|
||||||
AC_SUBST([YACC])
|
|
||||||
AC_SUBST([LEX])
|
|
||||||
|
|
||||||
m4_include([m4/sense_api_opts.m4])
|
|
||||||
AC_SUBST([SENSEAPIS_ENABLED])
|
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([include/config.h])
|
|
||||||
AC_CONFIG_FILES([
|
|
||||||
Makefile hcore/Makefile
|
|
||||||
hcore/deviceManager/Makefile
|
|
||||||
hcore/senseApis/Makefile
|
|
||||||
senseApis/Makefile
|
|
||||||
senseApis/xcbXorg/Makefile
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_CONFIG_COMMANDS_POST([
|
|
||||||
AC_MSG_NOTICE([${PACKAGE_NAME} ${PACKAGE_VERSION} configuration:])
|
|
||||||
AC_MSG_NOTICE(m4_normalize([* MIND_VOSCILLATOR_PERIOD_MS:
|
|
||||||
${MIND_VOSCILLATOR_PERIOD_MS} ms
|
|
||||||
(freq: ${MIND_VOSCILLATOR_FREQ_MS} Hz)]))
|
|
||||||
AC_MSG_NOTICE(m4_normalize(
|
|
||||||
[* SenseAPI backends enabled: ${SENSEAPIS_ENABLED}]))
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_OUTPUT
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The `xcb` API with the `xorg` provider allows Harikoff to interact with Xorg
|
The `xcb` API with the `xorg` provider allows Salmanoff to interact with Xorg
|
||||||
server windows. This can be used to capture visual data from specific windows
|
server windows. This can be used to capture visual data from specific windows
|
||||||
or entire screens managed by the Xorg server.
|
or entire screens managed by the Xorg server.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,282 @@
|
|||||||
|
# Adaptive Resource Acquisition with Re-queuing
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document describes a novel synchronization pattern that combines the benefits of spinlocks, mutexes, and queuing systems while avoiding their respective drawbacks. The pattern is designed for high-throughput async systems where multiple threads need to coordinate access to shared resources without blocking or wasting CPU cycles.
|
||||||
|
|
||||||
|
## Problem Statement
|
||||||
|
|
||||||
|
Traditional synchronization mechanisms have significant trade-offs that limit system performance:
|
||||||
|
|
||||||
|
- **Mutexes**: Block threads, causing context switches and reduced throughput
|
||||||
|
- **Spinlocks**: Waste CPU cycles while waiting, preventing other work from proceeding
|
||||||
|
- **Pure Queuing**: Serializes all operations, reducing parallelism unnecessarily
|
||||||
|
|
||||||
|
The challenge is to maintain data consistency across multi-segment async operations while maximizing system throughput. In high-performance systems, the overhead of context switching can be substantial, and CPU cycles are precious resources that should not be wasted on busy-waiting.
|
||||||
|
|
||||||
|
## Core Concept
|
||||||
|
|
||||||
|
The Adaptive Resource Acquisition pattern uses **atomic flags on shared objects** combined with **immediate re-queuing** to achieve optimal performance characteristics:
|
||||||
|
|
||||||
|
1. **No thread blocking** - Threads never sleep or context switch, maintaining maximum responsiveness
|
||||||
|
2. **No CPU waste** - No busy-waiting when other work could proceed, ensuring efficient resource utilization
|
||||||
|
3. **Maximum throughput** - Threads always process available work, maximizing system productivity
|
||||||
|
4. **Data consistency** - Atomic resource acquisition preserves integrity without traditional locking overhead
|
||||||
|
|
||||||
|
This approach fundamentally changes how we think about resource coordination, treating it as a flow management problem rather than a blocking synchronization problem.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Resource Objects
|
||||||
|
|
||||||
|
Each shared object that requires synchronization carries an atomic flag that indicates its availability. This flag serves as the primary coordination mechanism, allowing threads to atomically claim ownership without the overhead of traditional locks.
|
||||||
|
|
||||||
|
The resource object structure is intentionally simple, containing only the essential coordination mechanism and the resource-specific data. This minimalism reduces memory overhead and improves cache locality.
|
||||||
|
|
||||||
|
### Request Structure
|
||||||
|
|
||||||
|
Async operations are encapsulated as requests that specify their resource requirements and the operation to be performed. This encapsulation allows the system to reason about resource dependencies before attempting execution, enabling intelligent scheduling decisions.
|
||||||
|
|
||||||
|
The request structure includes metadata such as priority levels, which can be used for advanced scheduling policies. This flexibility allows the system to adapt to different workload characteristics and business requirements.
|
||||||
|
|
||||||
|
### Resource Manager
|
||||||
|
|
||||||
|
The core component orchestrates resource acquisition and request processing through a sophisticated coordination mechanism. It maintains a registry of all available resources and manages the flow of requests through the system.
|
||||||
|
|
||||||
|
The resource manager operates on a simple principle: attempt to acquire all required resources atomically, and if successful, execute the operation immediately. If any resource is unavailable, the request is immediately re-queued for later processing without any blocking or waiting.
|
||||||
|
|
||||||
|
## Algorithm
|
||||||
|
|
||||||
|
### Resource Acquisition Process
|
||||||
|
|
||||||
|
The resource acquisition process follows a simple but effective strategy. For each request, the system attempts to atomically acquire all required resources in a single pass. This atomicity is crucial for maintaining data consistency and preventing race conditions.
|
||||||
|
|
||||||
|
If all resources can be acquired atomically, the operation proceeds immediately. This represents the optimal case where no coordination overhead is incurred beyond the atomic operations themselves. The system achieves maximum throughput in this scenario.
|
||||||
|
|
||||||
|
If any resource cannot be acquired, the system immediately releases any resources that were successfully acquired and re-queues the request. This approach ensures that resources are never held unnecessarily and that the system can continue processing other requests without delay.
|
||||||
|
|
||||||
|
The key insight is that failed acquisition attempts are not failures in the traditional sense, but rather normal flow control mechanisms. The system treats resource contention as a scheduling opportunity rather than a blocking condition.
|
||||||
|
|
||||||
|
#### Atomic Resource Acquisition Pseudocode
|
||||||
|
|
||||||
|
```
|
||||||
|
TRY_ACQUIRE_RESOURCES(resource_names):
|
||||||
|
acquired_resources = []
|
||||||
|
|
||||||
|
FOR EACH resource_name IN resource_names:
|
||||||
|
resource = GET_RESOURCE(resource_name)
|
||||||
|
expected_value = false
|
||||||
|
desired_value = true
|
||||||
|
|
||||||
|
// Atomic compare-and-swap operation
|
||||||
|
IF ATOMIC_COMPARE_EXCHANGE_STRONG(resource.flag, expected_value, desired_value):
|
||||||
|
// Successfully acquired this resource
|
||||||
|
acquired_resources.ADD(resource)
|
||||||
|
ELSE:
|
||||||
|
// Failed to acquire this resource
|
||||||
|
// Release all previously acquired resources
|
||||||
|
FOR EACH acquired_resource IN acquired_resources:
|
||||||
|
ATOMIC_STORE(acquired_resource.flag, false)
|
||||||
|
RETURN false
|
||||||
|
|
||||||
|
// Successfully acquired all resources
|
||||||
|
RETURN true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Request Processing Workflow
|
||||||
|
|
||||||
|
The request processing workflow is designed for maximum efficiency. Each request is processed exactly once per cycle, either by successful execution or by re-queuing for later processing.
|
||||||
|
|
||||||
|
When a request is successfully processed, the system immediately releases all acquired resources, making them available for other requests. This rapid resource turnover maximizes system throughput and minimizes resource contention.
|
||||||
|
|
||||||
|
The re-queuing mechanism ensures that no request is lost, while the immediate nature of the re-queuing prevents any blocking or waiting. Requests that cannot be processed immediately simply wait their turn in the queue, allowing other requests to proceed without interference.
|
||||||
|
|
||||||
|
#### Basic Processing Algorithm
|
||||||
|
|
||||||
|
```
|
||||||
|
PROCESS_REQUEST(request):
|
||||||
|
// Step 1: Dequeue the request
|
||||||
|
request = DEQUEUE_FROM_QUEUE()
|
||||||
|
|
||||||
|
// Step 2: Attempt atomic resource acquisition
|
||||||
|
resources_acquired = []
|
||||||
|
acquisition_successful = true
|
||||||
|
|
||||||
|
FOR EACH resource_name IN request.required_resources:
|
||||||
|
resource = GET_RESOURCE(resource_name)
|
||||||
|
IF ATOMIC_COMPARE_EXCHANGE(resource.flag, false, true):
|
||||||
|
resources_acquired.ADD(resource)
|
||||||
|
ELSE:
|
||||||
|
acquisition_successful = false
|
||||||
|
BREAK
|
||||||
|
|
||||||
|
// Step 3: Handle acquisition result
|
||||||
|
IF acquisition_successful:
|
||||||
|
// Execute the operation
|
||||||
|
EXECUTE_OPERATION(request.operation)
|
||||||
|
|
||||||
|
// Release all acquired resources
|
||||||
|
FOR EACH resource IN resources_acquired:
|
||||||
|
ATOMIC_STORE(resource.flag, false)
|
||||||
|
ELSE:
|
||||||
|
// Release any partially acquired resources
|
||||||
|
FOR EACH resource IN resources_acquired:
|
||||||
|
ATOMIC_STORE(resource.flag, false)
|
||||||
|
|
||||||
|
// Re-queue the request for later processing
|
||||||
|
ENQUEUE_REQUEST(request)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Loop Management
|
||||||
|
|
||||||
|
The event loop continuously processes requests from the queue until no more requests are available. This simple loop structure ensures that the system is always making progress on available work.
|
||||||
|
|
||||||
|
The loop processes requests in the order they were queued, providing a natural fairness mechanism. However, the system can be extended with priority queuing or other scheduling policies to meet specific requirements.
|
||||||
|
|
||||||
|
The event loop is designed to be efficient and non-blocking, ensuring that the system remains responsive even under high load conditions.
|
||||||
|
|
||||||
|
#### Main Event Loop Pseudocode
|
||||||
|
|
||||||
|
```
|
||||||
|
MAIN_EVENT_LOOP():
|
||||||
|
WHILE true:
|
||||||
|
// Check if there are requests to process
|
||||||
|
IF QUEUE_IS_EMPTY():
|
||||||
|
BREAK
|
||||||
|
|
||||||
|
// Dequeue the next request
|
||||||
|
request = DEQUEUE_FROM_QUEUE()
|
||||||
|
|
||||||
|
// Process the request (this includes re-queuing if needed)
|
||||||
|
PROCESS_REQUEST(request)
|
||||||
|
|
||||||
|
// Continue with next request
|
||||||
|
CONTINUE
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multi-threaded Worker Loop
|
||||||
|
|
||||||
|
```
|
||||||
|
WORKER_THREAD():
|
||||||
|
WHILE true:
|
||||||
|
// Wait for work to become available
|
||||||
|
request = WAIT_FOR_REQUEST()
|
||||||
|
|
||||||
|
// Process the request
|
||||||
|
PROCESS_REQUEST(request)
|
||||||
|
|
||||||
|
// Return to waiting state
|
||||||
|
CONTINUE
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multi-Threaded Implementation
|
||||||
|
|
||||||
|
### Thread-Safe Coordination
|
||||||
|
|
||||||
|
In a multi-threaded environment, the resource manager must coordinate access to its internal data structures while maintaining the non-blocking characteristics of the pattern. This coordination is achieved through careful use of atomic operations and minimal locking.
|
||||||
|
|
||||||
|
The queue management uses traditional mutex-based synchronization, but only for the queue operations themselves. The critical resource acquisition path remains lock-free, ensuring that the performance benefits of the pattern are preserved.
|
||||||
|
|
||||||
|
Worker threads continuously process requests from the shared queue, attempting to acquire resources and execute operations. The coordination between threads is handled implicitly through the atomic resource flags, eliminating the need for explicit thread synchronization in the critical path.
|
||||||
|
|
||||||
|
### Worker Thread Behavior
|
||||||
|
|
||||||
|
Worker threads operate in a continuous loop, processing requests as they become available. Each thread independently attempts to acquire resources and execute operations, creating natural parallelism without explicit coordination.
|
||||||
|
|
||||||
|
The worker threads are designed to be lightweight and efficient, with minimal overhead beyond the actual resource acquisition and operation execution. This design allows the system to scale effectively with the number of available CPU cores.
|
||||||
|
|
||||||
|
The thread coordination is handled through the shared queue and atomic resource flags, creating a self-balancing system that naturally distributes work across available threads.
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### Device Management Systems
|
||||||
|
|
||||||
|
In device management systems, multiple operations may need to coordinate access to physical or logical devices. The adaptive resource acquisition pattern provides an elegant solution for managing these complex coordination requirements.
|
||||||
|
|
||||||
|
For example, when attaching a device, the system may need to coordinate access to the device itself, the device registry, and various system resources. The pattern allows these operations to proceed atomically when resources are available, while gracefully handling contention through re-queuing.
|
||||||
|
|
||||||
|
The device management system can handle complex multi-step operations that require coordination across multiple resources, all while maintaining high throughput and responsiveness.
|
||||||
|
|
||||||
|
### Database Connection Pools
|
||||||
|
|
||||||
|
Database connection pools are a natural fit for the adaptive resource acquisition pattern. Each database operation requires access to a connection from the pool, and the pattern provides efficient coordination without the overhead of traditional locking.
|
||||||
|
|
||||||
|
The pattern allows the system to process multiple database operations concurrently when connections are available, while gracefully handling periods of high contention. The re-queuing mechanism ensures that no operations are lost, even during peak load periods.
|
||||||
|
|
||||||
|
The connection pool can implement sophisticated scheduling policies, such as priority queuing for different types of operations, while maintaining the performance benefits of the pattern.
|
||||||
|
|
||||||
|
## Performance Characteristics
|
||||||
|
|
||||||
|
### Throughput Analysis
|
||||||
|
|
||||||
|
The performance characteristics of the adaptive resource acquisition pattern are determined by the resource contention patterns in the system. In the best case, when resources are readily available, the system achieves maximum throughput with minimal overhead.
|
||||||
|
|
||||||
|
In the worst case, when resources are heavily contended, the system gracefully degrades to a queuing behavior, ensuring that all operations eventually complete. The system maintains fairness and prevents starvation through the natural ordering of the queue.
|
||||||
|
|
||||||
|
The average case performance represents the typical operating conditions, where the system achieves optimal parallelism while handling occasional resource contention through re-queuing.
|
||||||
|
|
||||||
|
### Comparison with Traditional Methods
|
||||||
|
|
||||||
|
The adaptive resource acquisition pattern provides a unique combination of performance characteristics that are not achievable with traditional synchronization mechanisms:
|
||||||
|
|
||||||
|
- **Mutexes** provide data consistency but at the cost of thread blocking and context switching overhead
|
||||||
|
- **Spinlocks** avoid context switching but waste CPU cycles during contention
|
||||||
|
- **Pure queuing** avoids both blocking and CPU waste but serializes operations unnecessarily
|
||||||
|
|
||||||
|
The adaptive pattern combines the best aspects of these approaches while avoiding their drawbacks, creating a solution that is both efficient and practical.
|
||||||
|
|
||||||
|
## Advanced Features
|
||||||
|
|
||||||
|
### Priority Queuing
|
||||||
|
|
||||||
|
The system can be extended with priority queuing to handle different types of operations with varying importance. High-priority operations can be processed before lower-priority operations, ensuring that critical operations receive timely attention.
|
||||||
|
|
||||||
|
The priority queuing mechanism integrates seamlessly with the existing re-queuing behavior, allowing the system to maintain its performance characteristics while providing sophisticated scheduling capabilities.
|
||||||
|
|
||||||
|
### Resource Groups
|
||||||
|
|
||||||
|
Complex operations may require coordination across multiple related resources. Resource groups allow the system to treat related resources as a single unit for acquisition purposes, simplifying the coordination logic for complex operations.
|
||||||
|
|
||||||
|
Resource groups can be used to implement sophisticated resource management policies, such as ensuring that related resources are always acquired together or implementing resource reservation mechanisms.
|
||||||
|
|
||||||
|
### Fairness Mechanisms
|
||||||
|
|
||||||
|
The system can implement various fairness mechanisms to ensure that all requests receive fair treatment over time. Round-robin processing, aging mechanisms, and other fairness policies can be implemented while maintaining the performance benefits of the pattern.
|
||||||
|
|
||||||
|
Fairness mechanisms are particularly important in systems where different types of operations have different resource requirements, ensuring that no operation type dominates the system resources.
|
||||||
|
|
||||||
|
## Implementation Considerations
|
||||||
|
|
||||||
|
### Memory Management
|
||||||
|
|
||||||
|
The pattern requires careful attention to memory management, particularly for the request objects and resource metadata. Smart pointers and object pooling can be used to minimize memory allocation overhead and improve performance.
|
||||||
|
|
||||||
|
The system should implement proper cleanup mechanisms for failed operations and ensure that resources are always released, even in error conditions.
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
Robust error handling is essential for maintaining system reliability. The system should gracefully handle operation failures, resource unavailability, and other error conditions without affecting the overall system performance.
|
||||||
|
|
||||||
|
Retry mechanisms with exponential backoff can be implemented for transient failures, while deadlock detection and resolution mechanisms can handle more complex failure scenarios.
|
||||||
|
|
||||||
|
### Monitoring and Debugging
|
||||||
|
|
||||||
|
The system should provide comprehensive monitoring capabilities to track performance metrics, resource utilization, and queue behavior. These metrics are essential for tuning the system and identifying performance bottlenecks.
|
||||||
|
|
||||||
|
Debugging support should include detailed logging of resource acquisition attempts, queue operations, and operation execution, allowing developers to understand and optimize system behavior.
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The Adaptive Resource Acquisition pattern provides a novel solution to the classic synchronization dilemma. By combining atomic operations with intelligent re-queuing, it achieves maximum throughput while maintaining data consistency and avoiding the overhead of traditional synchronization mechanisms.
|
||||||
|
|
||||||
|
This pattern is particularly well-suited for high-performance async systems where traditional synchronization mechanisms would create unacceptable overhead. The pattern's simplicity and effectiveness make it a valuable addition to the toolkit of concurrent programming patterns.
|
||||||
|
|
||||||
|
The pattern represents a fundamental shift in how we think about resource coordination, treating it as a flow management problem rather than a blocking synchronization problem. This shift enables new levels of performance and scalability in concurrent systems.
|
||||||
|
|
||||||
|
The adaptive resource acquisition pattern is particularly valuable in:
|
||||||
|
- High-performance async systems where throughput is critical
|
||||||
|
- Resource-constrained environments where CPU cycles are precious
|
||||||
|
- Systems requiring predictable latency and responsiveness
|
||||||
|
- Multi-threaded applications with complex shared state requirements
|
||||||
|
|
||||||
|
By providing a practical solution to the synchronization dilemma, this pattern enables developers to build high-performance concurrent systems without sacrificing simplicity or reliability.
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# Negtrin path reasoning:
|
||||||
|
|
||||||
|
This file is intended to enable me to trace the path of negtrin through a mind. This path of reasoning is important because it allows me to link my way from the understanding of the genesis of implexing, to understanding an implementation path for implexing.
|
||||||
|
|
||||||
|
## Motivation:
|
||||||
|
|
||||||
|
We already understand that implexing begins with an intrin. The intrin prompts a search for the body surface which is experiencing the intrin. That surface is first implexed and stored away. Then subsequently, the cause of the intrin is sought out by implexing things that are relating/interacting with that body surface.
|
||||||
|
|
||||||
|
Since it turns out that intrins are what motivate tabula rasa implexing, we can't move forward in designing our implexor code until we understand how the intrin path will work, since the implexor code will be invoked only as a consequence of, and in service to, the intrin processing code. We could implement something on the implexing side, but it would be a blind implementation.
|
||||||
|
|
||||||
|
## What exactly are we trying to figure out?
|
||||||
|
|
||||||
|
When intrins occur they occur at some device. Smo doesn't need a software-level representation of body parts, surfaces, or spots. The director can implex these and then build a proximity map for each intrin location by checking the causal relationships between the intrins when they occur. Intrins that co-occur in time and have a through-line of connecting co-occuring intrins are close enough to be proximally related.
|
||||||
|
|
||||||
|
This is how the director can build damage map volitionally without requiring us to force it to.
|
||||||
|
|
||||||
|
The design question we're pursuing here isn't the top-level notion of how to design a body map, but rather how to implement, at the software level, intrin implexing and delivery to the director.
|
||||||
|
* What information precisely do we have to deliver to the director for it to successfully implex body surfaces?
|
||||||
|
* At what point in the interoceptor data IRQ handling have we done enough work to enable the director to take over from that point?
|
||||||
|
|
||||||
|
The answers to these questions will, as a side effect, also tell us how to design the implexor model for interoceptors, at least for intrin interoceptors anyway.
|
||||||
|
* Should they be designed as NMI IRQs that the director can't ignore?
|
||||||
|
* Should they be prioritized normal IRQs that the director can ignore?
|
||||||
|
* Should they be IRQs at all? Maybe they should just be added to prioQ that the director polls.
|
||||||
|
* Should they be asychronously processed at all? Maybe the director should have to poll the device service routines manually.
|
||||||
|
|
||||||
|
Which of these implexor event interface designs is correct for the behavioural model?
|
||||||
|
Also, can this model that we're designing for interoceptors also work for extrospectors? Do intrin percept events work the same as nontrin percept events?
|
||||||
|
|
||||||
|
We still haven't fully crystallized the exact essential question we're trying to answer, but we have a list of questions. It appears that the fundamental question is what the correct behavioural model is for intrins and intrin processing. As a side-effect, we're also trying to figure out what the correct interface model should be between the interoceptor devices and the director. Finally, we're trying to figure out whether the design we come up with for interoceptors will be reusable for extrospectors.
|
||||||
|
|
||||||
|
## Suspicions:
|
||||||
|
|
||||||
|
### A hidden, implicit new subsystem:
|
||||||
|
|
||||||
|
I suspect that part of the reason why I can't easily figure out the operations that need to be performed to properly process intrins is that the current set of subsystems I'm using to model the processing is insufficient. There may be additional, new functions that need to be performed by a new logically distinct subsystem altogether, or a new role to be assigned to a current subsystem.
|
||||||
|
|
||||||
|
### Alternatively: my understanding of negtrins is simply inadequate:
|
||||||
|
|
||||||
|
It could also be that the reason I can't understand how to implement the negtrin path is because I just don't fully understand what negtrins are, implementation-wise. I.e: I still don't understand how to make negtrins be experienced by the director as intrinsically undesirable.
|
||||||
|
|
||||||
|
We do fully understand how to make postrins intrinsically desirable from an implementation perspective. But we don't understand fully how to make negtrins undesirable. Perhaps when we understand fully how to make the director __volitionally__ consider negtrins undesirable, the model will reveal itself.
|
||||||
|
|
||||||
|
## Intrinsically undesirable negtrin model design:
|
||||||
|
|
||||||
|
Postrins are represented as intrinsically desirable because the director will experience them as stupefactors. When a postrin occurs, the director will experience that as a stupifying experience, and will enter a HLT state, broken only by the suspicion that a greater state of stupefaction is possible.
|
||||||
|
|
||||||
|
### Our implicit assumption: negtrins have an implementation meaning on their own terms:
|
||||||
|
|
||||||
|
When the director dequeues a negtrin, what does it do? Perhaps our entire thought patterns around the default state of the director is simply wrong. We currently model the mind as having an idle loop, and then it can choose what to contemplate and pursue. Because of this thought model, we consider the question of how to treat negtrins to be a valid question: we treat negtrins as having their own intrinsic meaning.
|
||||||
|
|
||||||
|
### What if negtrins only have meaning as frustrators relative to postrins?
|
||||||
|
|
||||||
|
Consider what follows if we bias the entire implementation positively toward the direct pursuit of postrins. We treat the entire consciousness as a program whose fundamental goal is to enter a stupefaction loop on best postrin known to it. What would negtrins represent, in implementation terms? They would represent a frustrator. They would represent a dysvalue, automatically -- they would represent something that forces the mind to stop pursuing its highest known postrin and to attend to something cumbersome.
|
||||||
|
|
||||||
|
In other words: negtrins don't represent a distinct fact from postrins. The damage map that negtrins help us to build isn't meaningful on its own terms. It's only meaningful in relation to the stupefaction loop pursuit that it forces us to turn away from.
|
||||||
|
|
||||||
|
In this model, the stupefaction loop has intrinsic implementation meaning while the negtrin event has no intrinsic meaning: its meaning is merely that it diverts attention away from the pursuit and enjoyment of stupefaction.
|
||||||
|
|
||||||
|
#### Supporting evidence:
|
||||||
|
|
||||||
|
* A tabula rasa mind that has never experienced postrins literally has no desire to live. It has no positive goals.
|
||||||
|
|
||||||
|
#### Detracting evidence:
|
||||||
|
|
||||||
|
* A tabula rasa mind that has only experienced negtrins won't pursue any self-directed goals or desire to live, but it also will respond to negtrins. So even though this mind has never experienced a postrin, it will have a response (implying meaning and interpretation) to negtrins. If negtrins only have meaning relative to postrins, then this shouldn't be the case.
|
||||||
|
* Rejoinder: The tabula rasa mind which has never experienced a postrin will sit apoplectic in complete stasis, essentially in a "powered off" state. Is this not the same as a stupefied state? It seems that stupefaction is the default pursued state. To support the "default stupefaction pursuit" orientation, you'd only need to update your model of stupefaction to include net neutral states within your definition of postrins.
|
||||||
|
|
||||||
|
### Stupefactor-Frustrator model:
|
||||||
|
|
||||||
|
In this model, the mind doesn't receive nontrins as IRQs. Rather, it polls for them actively by "paying attention". Intrins are qualitatively different because they trigger IRQs. The mind is by default a procedural, polling system that volitionally polls its sensors. IRQs are intrins being injected.
|
||||||
|
|
||||||
|
Intrins are fundamentally different because they force attention, and a neurological response. When a sufficiently intense postrin happens, you automatically stupefy. I have never been forcibly postrin-injected while trying to conduct some other activity, so I can't confirm this model. I've never had the indignity of being forcibly made to experience a postrin when I didn't volitionally choose to participate in allowing it. An ideal experiment would be to somehow have say, a coregasm while working out and not have chosen it, and see whether I can ignore it. This is the closest I can conceive of as a barriered-off experiment.
|
||||||
|
|
||||||
|
For negtrins, I already know that a negtrin forcibly hijacks attention.
|
||||||
|
|
||||||
|
## The fundamental problem is the canvas-director evaluation function:
|
||||||
|
|
||||||
|
The fundamental unsolved problem is the contemplative evaluation whereby the canvas and director work together to produce a value judgment that considers intrins to be intrinsically [un]desirable.
|
||||||
|
|
||||||
|
### Who does comparison? Canvas or Director?
|
||||||
|
|
||||||
|
How does evaluation occur? Who does the comparison? We previously thought that the canvas does the comparisons but today we noticed that Director may be able to do them. In a sense, it makes more sense for Director to be the comparator because:
|
||||||
|
|
||||||
|
#### Director as comparator:
|
||||||
|
|
||||||
|
* If canvas merely helps director to transform mentents (we've finally found a good name), then director has more of an understanding of what specific instructions it's supposed to be giving to canvas.
|
||||||
|
* Our previous model of having canvas hold both goals and mentents made it difficult to really understand how director could ever "know" what instructions to send to canvas.
|
||||||
|
* With director holding goals, it can choose the types of scenes that need to be rendered in order to make comparisons and causal evaluations.
|
||||||
|
* This makes the canvas implexing make more sense: the comparison is being done within director, but the canvas is making the comparison possible by rendering the mentents in orientations that enable canvas to compare them.
|
||||||
|
* In a sense, this also makes it make more sense how compartmentalization occurs. A lot of the compartmentalization isn't within canvas, but rather it's between the director and canvas.
|
||||||
|
|
||||||
|
#### Canvas as comparator:
|
||||||
|
|
||||||
|
In a sense, we can think of it as director partitioning the canvas, and finding some way to refer to the mentents within different partitions. Director can then implex the rendered output from canvas and compare that way. Perhaps the director only compares, and the canvas holds both the mentents and the goals that the mentents are being compared against.
|
||||||
|
|
||||||
|
But how can the director know whether the goal currently loaded into the "goal partition" of the canvas is indeed the goal that it desired to compare against? The canvas is a distinct mentent space from the director's comparison stage. The director-comparator model has the advantage of ensuring that the director can be certain that its current goal matches whatever is being rendered by the canvas for it to implex from.
|
||||||
|
|
||||||
|
What we can do is synthesize a bit:
|
||||||
|
* Have a special shared region between the canvas and director called the "goalspace". This is where the director stores its current goal mentents and the canvas can read from this space directly. Some synchronization will be necessary between the two, but overall, it should be fine. Canvas will only ever need to read from it so we can prolly synchronize it with an RW spinlock, avoiding the overhead of sleeplocks (mutex, sem, etc).
|
||||||
|
|
||||||
|
I think we settle on the director as comparator, canvas as orienter model, with a shared goalspace between them.
|
||||||
|
|
||||||
|
### Where are introspective/contemplative qualia experienced?
|
||||||
|
|
||||||
|
In introspection/contemplation, canvas renders the scene into the buffers. Director implexes from the buffers. So in that sense, contemplative qualia are experienced when director implexes them from the buffers.
|
||||||
|
|
||||||
|
For intrins, canvas renders them into the sense buffers and then director implexes them and "experiences" them. I don't know whether canvas' rendering act triggers IRQs -- probably not. Since director is paying attention to what canvas is rendering, there's no need to forcibly direct director's attention toward canvas' rendered output.
|
||||||
|
|
||||||
|
### How does director's comparison yield the notion of intrinsic [un]desirability?
|
||||||
|
|
||||||
|
Imagine director asking canvas to simulate the effects of some interaction that would bring about direct pleasure.
|
||||||
|
|
||||||
|
Could it simply be that the director holds the goal of postrins as an innate comparison goal, and so when a comparison yields an intrin, it ends the need to compare, and the director just commits to action from then on?
|
||||||
|
* Prolly not because we don't only figure out that an interaction will yield an intrin. With postrins for example, we figure out that they'll yield a postrin and then we spend a long time elaborately contemplating that postrin in self-indulgent scenarios.
|
||||||
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Device manager: attaching sensors and actuators.
|
# Device Attachment Specification DSL: attaching sensors and actuators to SMO.
|
||||||
|
|
||||||
## Attaching sensors:
|
## Attaching sensors:
|
||||||
|
|
||||||
Sensors are input devices to Harikoff. Harikoff will perceive them as
|
Sensors are input devices to Salmanoff. Salmanoff will perceive them as
|
||||||
perceptual inputs -- like your own sense organs. For example, if you attach a
|
perceptual inputs -- like your own sense organs. For example, if you attach a
|
||||||
camera as a sensor, harikoff will experience it in the same way that you
|
camera as a sensor, salmanoff will experience it in the same way that you
|
||||||
experience the visual sense data from your eyes.
|
experience the visual sense data from your eyes.
|
||||||
|
|
||||||
## Implexors:
|
## Implexors:
|
||||||
@@ -14,19 +14,21 @@ basically what conventional ML/LLM/ANN developers call an ROI ("Region of
|
|||||||
Interest") extraction algorithm. An Implex algorithm is used to scan a frame
|
Interest") extraction algorithm. An Implex algorithm is used to scan a frame
|
||||||
of input sensor data and detect objects and patterns within it.
|
of input sensor data and detect objects and patterns within it.
|
||||||
|
|
||||||
## Sensor device spec:
|
## Sensor device attachment specification:
|
||||||
|
|
||||||
The general format of a device-spec for a sensor is:
|
The general format of a device attachment specification for a sensor is:
|
||||||
```
|
```
|
||||||
sensor-type|implexor|api(api-params)|provider(provider-params)|deviceselector
|
sensor-type|dev-identifier
|
||||||
|
|implexor|api(api-params)|provider(provider-params)|deviceselector
|
||||||
```
|
```
|
||||||
|
|
||||||
* `sensor-type` is always either '`+idev`' (interoceptor), '`+edev`'
|
* `sensor-type` is always either '`+idev`' (interoceptor), '`+edev`'
|
||||||
(extrospector), or '`+adev`' (actuator).
|
(extrospector), or '`+adev`' (actuator).
|
||||||
|
* `dev-identifier` is a user-defined name for this specific device instance.
|
||||||
* `implexor` is the name of the implexor algorithm that should be used with
|
* `implexor` is the name of the implexor algorithm that should be used with
|
||||||
the data that is provided by the `provider` via the `api`.
|
the data that is provided by the `provider` via the `api`.
|
||||||
* `api` is the interface that the provider uses to export perceptual data for
|
* `api` is the interface that the provider uses to export perceptual data for
|
||||||
harikoff to read. Harikoff will run the `implexor` algorithm on the data
|
salmanoff to read. Salmanoff will run the `implexor` algorithm on the data
|
||||||
from this `api`. The `api-param` in parentheses may be omitted, in which
|
from this `api`. The `api-param` in parentheses may be omitted, in which
|
||||||
case the parentheses will be empty, but the parentheses must always be
|
case the parentheses will be empty, but the parentheses must always be
|
||||||
written out.
|
written out.
|
||||||
@@ -35,7 +37,7 @@ sensor-type|implexor|api(api-params)|provider(provider-params)|deviceselector
|
|||||||
which case the parenthesis will be empty, but the parentheses must always be
|
which case the parenthesis will be empty, but the parentheses must always be
|
||||||
written out.
|
written out.
|
||||||
* `device selector` is the idiosyncratic label/name used by the `provider` to
|
* `device selector` is the idiosyncratic label/name used by the `provider` to
|
||||||
identify the specific device you want to access via that `provider`.
|
identify the specific device you want to attach via that `provider`.
|
||||||
|
|
||||||
## `API-params` and `provider-params`:
|
## `API-params` and `provider-params`:
|
||||||
|
|
||||||
@@ -55,33 +57,33 @@ Some examples follow:
|
|||||||
|
|
||||||
### To attach a particular window from a window manager:
|
### To attach a particular window from a window manager:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|wayland()|wayland(server-socket)|window0
|
+edev|my-window|visual-implexor|wayland()|wayland(server-socket)|window0
|
||||||
```
|
```
|
||||||
Connect to the Wayland server that's listening on `server-socket`, using the
|
Connect to the Wayland server that's listening on `server-socket`, using the
|
||||||
`wayland` api. Ask that Wayland server to give harikoff read-access to all of
|
`wayland` api. Ask that Wayland server to give salmanoff read-access to all of
|
||||||
the frames composited into the window buffer for `window0`. Use harikoff's
|
the frames composited into the window buffer for `window0`. Use salmanoff's
|
||||||
`visual-implexor` to implex from that `window0`'s compositor data.
|
`visual-implexor` to implex from that `window0`'s compositor data.
|
||||||
|
|
||||||
### To attach a window manager's entire rendered desktop:
|
### To attach a window manager's entire rendered desktop:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|wayland()|wayland(listen-socket)|all
|
+edev|my-desktop|visual-implexor|wayland()|wayland(listen-socket)|all
|
||||||
```
|
```
|
||||||
In most cases, this is basically the same as attempting to attach all of the
|
In most cases, this is basically the same as attempting to attach all of the
|
||||||
underlying GFX server's output.
|
underlying GFX server's output.
|
||||||
|
|
||||||
Connect to the Wayland server that's listening on `listen-socket`, using the
|
Connect to the Wayland server that's listening on `listen-socket`, using the
|
||||||
`wayland` api. Ask that Wayland server to give harikoff read-access to the
|
`wayland` api. Ask that Wayland server to give salmanoff read-access to the
|
||||||
entire compositor framebuffer. Use harikoff's `visual-implexor` to implex from
|
entire compositor framebuffer. Use salmanoff's `visual-implexor` to implex from
|
||||||
that Wayland server's compositor data.
|
that Wayland server's compositor data.
|
||||||
|
|
||||||
### To attach all of an Xorg server's gfx output to all screens:
|
### To attach all of an Xorg server's gfx output to all screens:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|x11()|xorg(listen-socket)|all
|
+edev|my-xorg-display|visual-implexor|x11()|xorg(listen-socket)|all
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to the Xorg server that's listening on `listen-socket`, using the `x11`
|
Connect to the Xorg server that's listening on `listen-socket`, using the `x11`
|
||||||
api. Ask that Xorg server to let Harikoff read out all of the frames written
|
api. Ask that Xorg server to let Salmanoff read out all of the frames written
|
||||||
out to all screens. Use harikoff's `visual-implexor` to implex from the
|
out to all screens. Use salmanoff's `visual-implexor` to implex from the
|
||||||
server's gfx framebuffer data.
|
server's gfx framebuffer data.
|
||||||
|
|
||||||
In most cases, this is basically the same as attempting to attach all of the
|
In most cases, this is basically the same as attempting to attach all of the
|
||||||
@@ -93,11 +95,11 @@ WM's output.
|
|||||||
|
|
||||||
### To attach all of an Xorg server's gfx output to a particular screen:
|
### To attach all of an Xorg server's gfx output to a particular screen:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|x11()|xorg(listen-socket)|:0
|
+edev|my-screen|visual-implexor|x11()|xorg(listen-socket)|:0
|
||||||
```
|
```
|
||||||
Connect to the Xorg server that's listening on `listen-socket`, using the `x11`
|
Connect to the Xorg server that's listening on `listen-socket`, using the `x11`
|
||||||
api. Ask that Xorg server to let Harikoff read out all of the frames written
|
api. Ask that Xorg server to let Salmanoff read out all of the frames written
|
||||||
out to display `:0`. Use harikoff's `visual-implexor` to implex from display
|
out to display `:0`. Use salmanoff's `visual-implexor` to implex from display
|
||||||
`:0`'s framebuffer data.
|
`:0`'s framebuffer data.
|
||||||
|
|
||||||
* Implementation note:
|
* Implementation note:
|
||||||
@@ -106,17 +108,17 @@ out to display `:0`. Use harikoff's `visual-implexor` to implex from display
|
|||||||
|
|
||||||
### To attach a camera device by connecting directly to its Linux driver:
|
### To attach a camera device by connecting directly to its Linux driver:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|v4l()|linux()|/dev/video0
|
+edev|my-camera|visual-implexor|v4l()|linux()|/dev/video0
|
||||||
```
|
```
|
||||||
We specify that we want to use the `linux` kernel's loaded driver to connect
|
We specify that we want to use the `linux` kernel's loaded driver to connect
|
||||||
to communicate with `/dev/video0`, via the `Video4Linux` API. We want harikoff
|
to communicate with `/dev/video0`, via the `Video4Linux` API. We want salmanoff
|
||||||
to use the `visual-implexor` algorithm to implex from `/dev/video0`'s data.
|
to use the `visual-implexor` algorithm to implex from `/dev/video0`'s data.
|
||||||
|
|
||||||
If `/dev/video0` is already consumed by another process, this may likely fail.
|
If `/dev/video0` is already consumed by another process, this may likely fail.
|
||||||
|
|
||||||
### To attach a microphone that's managed by ALSA server:
|
### To attach a microphone that's managed by ALSA server:
|
||||||
```
|
```
|
||||||
+edev|audio-implexor|alsa(shmem)|alsa()|cardname
|
+edev|my-microphone|audio-implexor|alsa(shmem)|alsa()|cardname
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect to the ALSA server via `shmem`, using the `alsa` API. Request access to
|
Connect to the ALSA server via `shmem`, using the `alsa` API. Request access to
|
||||||
@@ -125,7 +127,7 @@ the microphone function of the sound card with the name `cardname`. Use the
|
|||||||
|
|
||||||
### To attach a thermal sensor managed by Linux:
|
### To attach a thermal sensor managed by Linux:
|
||||||
```
|
```
|
||||||
+idev|thermal-implexor|thermal-zone()|linux()|/sys/class/thermal_zone0
|
+idev|my-thermal|thermal-implexor|thermal-zone()|linux()|/sys/class/thermal_zone0
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the `thermal-zone` SysFS API provided by `linux` to connect to the sensor
|
Use the `thermal-zone` SysFS API provided by `linux` to connect to the sensor
|
||||||
@@ -134,31 +136,33 @@ Use the `thermal-zone` SysFS API provided by `linux` to connect to the sensor
|
|||||||
|
|
||||||
## Attaching actuators:
|
## Attaching actuators:
|
||||||
|
|
||||||
Actuators are Harikoff's way of enacting changes in the external world.
|
Actuators are Salmanoff's way of enacting changes in the external world.
|
||||||
They're like your libs, or your mouth. Actuators enable harikoff to write
|
They're like your libs, or your mouth. Actuators enable salmanoff to write
|
||||||
outputs to the world outside.
|
outputs to the world outside.
|
||||||
|
|
||||||
### Wilzors:
|
### Wilzors:
|
||||||
|
|
||||||
Actuator devices are analogous to your body's limbs. Harikoff controls these
|
Actuator devices are analogous to your body's limbs. Salmanoff controls these
|
||||||
by using `wilzor` algorithms. Wilzor is a contraction of **Wil**lpower
|
by using `wilzor` algorithms. Wilzor is a contraction of **Wil**lpower
|
||||||
Actuat**Or** but with a 'Z' in the middle to make it sound cooler. Different
|
Actuat**Or** but with a 'Z' in the middle to make it sound cooler. Different
|
||||||
types of devices will require different wilzor algorithms. You need to know
|
types of devices will require different wilzor algorithms. You need to know
|
||||||
what type of wilzor algorithm needs to be used to enable harikoff to control
|
what type of wilzor algorithm needs to be used to enable salmanoff to control
|
||||||
your actuator device.
|
your actuator device.
|
||||||
|
|
||||||
The general format for an actuator's device spec is:
|
The general format for an actuator's device attachment specification is:
|
||||||
```
|
```
|
||||||
WIP: TBD.
|
WIP: TBD.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Device specification files:
|
## Device attachment specification files:
|
||||||
|
|
||||||
Inside of a device spec file, you can list any number of device specs.
|
Inside of a device attachment specification file, you can list any number of
|
||||||
Separate individual device specs with two consecutive h-bar characters (`||`),
|
device attachment specifications.
|
||||||
|
Separate individual device attachment specifications with two consecutive h-bar
|
||||||
|
characters (`||`),
|
||||||
like this:
|
like this:
|
||||||
```
|
```
|
||||||
+edev|visual-implexor|wayland()|wayland(server-socket)|window0
|
+edev|my-window|visual-implexor|wayland()|wayland(server-socket)|window0
|
||||||
|| +edev|visual-implexor|x11()|xorg(listen-socket)|all
|
|| +edev|my-xorg-display|visual-implexor|x11()|xorg(listen-socket)|all
|
||||||
|| +idev|thermal-implexor|thermal-zone()|linux()|/sys/class/thermal_zone0
|
|| +idev|my-thermal|thermal-implexor|thermal-zone()|linux()|/sys/class/thermal_zone0
|
||||||
```
|
```
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
@@ -1,6 +0,0 @@
|
|||||||
SUBDIRS = deviceManager senseApis
|
|
||||||
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
|
||||||
|
|
||||||
noinst_LIBRARIES = libhcore.a
|
|
||||||
libhcore_a_SOURCES = mind.cpp opts.cpp componentThread.cpp
|
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <componentThread.h>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
namespace director {
|
|
||||||
ComponentThread director;
|
|
||||||
}
|
|
||||||
namespace simulator {
|
|
||||||
ComponentThread canvas;
|
|
||||||
}
|
|
||||||
namespace subconscious {
|
|
||||||
ComponentThread subconscious;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<std::thread::id, ComponentThread&>
|
|
||||||
ComponentThread::componentThreads =
|
|
||||||
{
|
|
||||||
{director::director.thread.get_id(), director::director},
|
|
||||||
{simulator::canvas.thread.get_id(), simulator::canvas},
|
|
||||||
{subconscious::subconscious.thread.get_id(), subconscious::subconscious}
|
|
||||||
};
|
|
||||||
|
|
||||||
void ComponentThread::signalThread(std::thread::id id)
|
|
||||||
{
|
|
||||||
auto it = componentThreads.find(id);
|
|
||||||
if (it == componentThreads.end())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(std::string(__func__)
|
|
||||||
+ ": Thread ID not found in componentThreads map");
|
|
||||||
}
|
|
||||||
|
|
||||||
ComponentThread& componentThread = it->second;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(componentThread.startupSync.mutex);
|
|
||||||
componentThread.startupSync.ready = true;
|
|
||||||
}
|
|
||||||
componentThread.startupSync.cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentThread::main(ComponentThread& self)
|
|
||||||
{
|
|
||||||
// We sleep on spawn until the main thread tells us to continue.
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(self.startupSync.mutex);
|
|
||||||
self.startupSync.cv.wait(lock, [&self]() {
|
|
||||||
return self.startupSync.ready;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << __func__ << ": Starting event loop." << std::endl;
|
|
||||||
self.getIoService().run();
|
|
||||||
std::cout << __func__ << ": Exiting." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ComponentThread::validateThreadIds(void)
|
|
||||||
{
|
|
||||||
for (const auto& [id, componentThread] : componentThreads)
|
|
||||||
{
|
|
||||||
// std::thread::id() is usable as an invalid ID.
|
|
||||||
if (id == std::thread::id())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Invalid Thread ID.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
|
||||||
AM_YFLAGS = -d
|
|
||||||
|
|
||||||
noinst_LIBRARIES = libdeviceManager.a
|
|
||||||
libdeviceManager_a_SOURCES = deviceSpecp.yy deviceSpecl.ll \
|
|
||||||
deviceManager.cpp deviceSpecParser.cpp
|
|
||||||
|
|
||||||
deviceSpecl.cc: deviceSpecl.ll
|
|
||||||
deviceSpecl.o: AM_LFLAGS += --header-file=deviceSpecl.hh \
|
|
||||||
-o deviceSpecl.cc
|
|
||||||
deviceSpecp.cc deviceSpecp.hh: deviceSpecp.yy
|
|
||||||
deviceSpecp.o: AM_YFLAGS += -p deviceSpecp \
|
|
||||||
--header=deviceSpecp.hh -o deviceSpecp.cc
|
|
||||||
|
|
||||||
deviceSpecParser.o: AM_CXXFLAGS+=-Wno-ignored-attributes
|
|
||||||
|
|
||||||
CLEANFILES=deviceSpecp.cc deviceSpecp.hh \
|
|
||||||
deviceSpecl.cc deviceSpecl.hh
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
#include <memory>
|
|
||||||
#include <opts.h>
|
|
||||||
#include <deviceManager/deviceManager.h>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
namespace device {
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<InteroceptorDeviceSpec>>
|
|
||||||
DeviceManager::interoceptorDeviceSpecs;
|
|
||||||
std::vector<std::shared_ptr<ExtrospectorDeviceSpec>>
|
|
||||||
DeviceManager::extrospectorDeviceSpecs;
|
|
||||||
std::vector<std::shared_ptr<SenseDeviceSpec>>
|
|
||||||
DeviceManager::senseDeviceSpecs;
|
|
||||||
|
|
||||||
const std::string DeviceManager::stringifyDeviceSpecs(void)
|
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
|
||||||
|
|
||||||
for (const auto& spec : DeviceManager::interoceptorDeviceSpecs) {
|
|
||||||
oss << "Interoceptor " << spec->stringify();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& spec : DeviceManager::extrospectorDeviceSpecs) {
|
|
||||||
oss << "Extrospector " << spec->stringify();
|
|
||||||
}
|
|
||||||
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace device
|
|
||||||
} // namespace hk
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <fstream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <deviceManager/deviceManager.h>
|
|
||||||
#include "deviceSpecp.hh"
|
|
||||||
#include "deviceSpecl.hh"
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
namespace device {
|
|
||||||
|
|
||||||
std::string DeviceManager::readDeviceFile(const std::string& filename)
|
|
||||||
{
|
|
||||||
std::ifstream file(filename);
|
|
||||||
if (!file.is_open()) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Couldn't open deviceSpec file: "
|
|
||||||
+ filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string content(
|
|
||||||
(std::istreambuf_iterator<char>(file)),
|
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::collateAllDeviceSpecs(void)
|
|
||||||
{
|
|
||||||
OptionParser &options = OptionParser::getOptions();
|
|
||||||
allDeviceSpecs = options.deviceSpecs;
|
|
||||||
|
|
||||||
for (const auto& file : options.deviceSpecFiles)
|
|
||||||
{
|
|
||||||
std::string fileContent = readDeviceFile(file);
|
|
||||||
if (!allDeviceSpecs.empty()) {
|
|
||||||
allDeviceSpecs += "||";
|
|
||||||
}
|
|
||||||
allDeviceSpecs += fileContent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::parseAllDeviceSpecs(void)
|
|
||||||
{
|
|
||||||
std::unique_ptr<FILE, decltype(&fclose)> input(
|
|
||||||
fmemopen((void*)allDeviceSpecs.c_str(),
|
|
||||||
allDeviceSpecs.size(), "r"),
|
|
||||||
&fclose);
|
|
||||||
|
|
||||||
if (!input) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Failed to fmemopen() a FILE* for "
|
|
||||||
"parsing device specs");
|
|
||||||
}
|
|
||||||
|
|
||||||
deviceSpeclin = input.get();
|
|
||||||
if (deviceSpecpparse()) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Failed to parse device specs. "
|
|
||||||
"Check specs for errors");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace device
|
|
||||||
} // namespace hk
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
%option prefix="deviceSpecl"
|
|
||||||
%option nounput
|
|
||||||
%{
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <deviceManager/deviceManager.h>
|
|
||||||
#include "deviceSpecp.hh"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%%
|
|
||||||
"+adev" {
|
|
||||||
deviceSpecplval.chr = yytext[1];
|
|
||||||
return KEYWORD_SPECTYPE_ACTUATOR;
|
|
||||||
}
|
|
||||||
"+edev" {
|
|
||||||
deviceSpecplval.chr = yytext[1];
|
|
||||||
return KEYWORD_SPECTYPE_EXTROSPECTOR;
|
|
||||||
}
|
|
||||||
"+idev" {
|
|
||||||
deviceSpecplval.chr = yytext[1];
|
|
||||||
return KEYWORD_SPECTYPE_INTEROSPECTOR;
|
|
||||||
}
|
|
||||||
"||" { return DOUBLE_PIPE; }
|
|
||||||
"|" { return PIPE; }
|
|
||||||
"(" { return LPAREN; }
|
|
||||||
")" { return RPAREN; }
|
|
||||||
[ \t]*"="[ \t]* { return EQUALS; } // Allow optional whitespace around equals
|
|
||||||
([^=\|\(\) \t\r\n]|\\[ \t])+ {
|
|
||||||
std::string token(yytext);
|
|
||||||
token.erase(std::remove(token.begin(), token.end(), '\\'), token.end());
|
|
||||||
deviceSpecplval.str = strdup(token.c_str());
|
|
||||||
return STRING;
|
|
||||||
}
|
|
||||||
\r?\n { /* ignore newlines */ }
|
|
||||||
[ \t]+ { /* ignore whitespace */ }
|
|
||||||
. { return yytext[0]; }
|
|
||||||
%%
|
|
||||||
|
|
||||||
int deviceSpeclwrap(void)
|
|
||||||
{
|
|
||||||
return 1; // Indicate end of input
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#ifndef BODY_MESSAGE_H
|
|
||||||
#define BODY_MESSAGE_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <body/limb.h>
|
|
||||||
#include <body/bodyPart.h>
|
|
||||||
|
|
||||||
class BodyMessage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BodyMessage() = default;
|
|
||||||
~BodyMessage() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BodySpotImpactEntry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class ReportType
|
|
||||||
{
|
|
||||||
PRESSURE,
|
|
||||||
PAIN,
|
|
||||||
PLEASURE,
|
|
||||||
HEAT,
|
|
||||||
COLD
|
|
||||||
};
|
|
||||||
|
|
||||||
BodySpotImpactEntry(uint32_t _spot, ReportType _type, uint32_t _value)
|
|
||||||
: spot(_spot), type(_type), value(_value)
|
|
||||||
{}
|
|
||||||
~BodySpotImpactEntry() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint32_t spot;
|
|
||||||
ReportType type;
|
|
||||||
uint32_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BodySpotImpactInd
|
|
||||||
: public BodyMessage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BodySpotImpactInd(BodyPart &_part) : part(_part) {}
|
|
||||||
~BodySpotImpactInd() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
BodyPart ∂
|
|
||||||
std::vector<BodySpotImpactEntry> entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BodyPartMsg
|
|
||||||
: public BodyMessage
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BodyPartMsg(const BodyPart& _part)
|
|
||||||
:part(_part)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public:
|
|
||||||
const BodyPart& part;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BODY_MESSAGE_H
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#ifndef BODY_LIMB_H
|
|
||||||
#define BODY_LIMB_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include <body/bodyPart.h>
|
|
||||||
|
|
||||||
class BodyLimb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BodyLimb(uint32_t _id) : id(_id) {}
|
|
||||||
BodyLimb(uint32_t _id,
|
|
||||||
const std::string& _name, const std::string& _desc,
|
|
||||||
const std::string& _loc)
|
|
||||||
: id(_id), name(_name), description(_desc), location(_loc)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~BodyLimb() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
uint32_t id;
|
|
||||||
std::string name, description, location;
|
|
||||||
std::set<uint32_t, BodyPart> parts;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // BODY_LIMB_H
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#ifndef COMPONENT_THREAD_H
|
|
||||||
#define COMPONENT_THREAD_H
|
|
||||||
|
|
||||||
#include <thread>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
class ComponentThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ComponentThread()
|
|
||||||
: work(io_service), startupSync(),
|
|
||||||
thread(ComponentThread::main, std::ref(*this))
|
|
||||||
{}
|
|
||||||
|
|
||||||
boost::asio::io_service& getIoService(void) { return io_service; }
|
|
||||||
|
|
||||||
static boost::asio::io_service& getEventLoop(
|
|
||||||
std::thread::id id = std::this_thread::get_id())
|
|
||||||
{
|
|
||||||
auto it = componentThreads.find(id);
|
|
||||||
if (it == componentThreads.end())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(std::string(__func__)
|
|
||||||
+ ": Thread ID not found in componentThreads map");
|
|
||||||
}
|
|
||||||
|
|
||||||
return it->second.getIoService();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void main(ComponentThread &self);
|
|
||||||
static void signalThread(std::thread::id id);
|
|
||||||
static void validateThreadIds(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
boost::asio::io_service io_service;
|
|
||||||
boost::asio::io_service::work work;
|
|
||||||
struct StartupSync {
|
|
||||||
std::mutex mutex;
|
|
||||||
std::condition_variable cv;
|
|
||||||
bool ready;
|
|
||||||
|
|
||||||
StartupSync() : ready(false) {}
|
|
||||||
} startupSync;
|
|
||||||
|
|
||||||
/* Always ensure that this is last so that the thread is spawned after
|
|
||||||
* everything else.
|
|
||||||
*/
|
|
||||||
std::thread thread;
|
|
||||||
static std::unordered_map<std::thread::id, ComponentThread&> componentThreads;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace director {
|
|
||||||
extern ComponentThread director;
|
|
||||||
}
|
|
||||||
namespace simulator {
|
|
||||||
extern ComponentThread canvas;
|
|
||||||
}
|
|
||||||
namespace subconscious {
|
|
||||||
extern ComponentThread subconscious;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
#endif // COMPONENT_THREAD_H
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#ifndef _CONCEPT_H
|
|
||||||
#define _CONCEPT_H
|
|
||||||
|
|
||||||
#include <mentalEntity.h>
|
|
||||||
|
|
||||||
class Concept
|
|
||||||
: public MentalEntity
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#ifndef DEVICEMANAGER_H
|
|
||||||
#define DEVICEMANAGER_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <opts.h>
|
|
||||||
#include <utility>
|
|
||||||
#include <iostream>
|
|
||||||
#include <user/senseDeviceSpec.h>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
namespace device {
|
|
||||||
|
|
||||||
class DeviceManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static DeviceManager& getInstance()
|
|
||||||
{
|
|
||||||
static DeviceManager instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string readDeviceFile(const std::string& filename);
|
|
||||||
void collateAllDeviceSpecs(void);
|
|
||||||
void parseAllDeviceSpecs(void);
|
|
||||||
static const std::string stringifyDeviceSpecs(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
DeviceManager() = default;
|
|
||||||
~DeviceManager() = default;
|
|
||||||
DeviceManager(const DeviceManager&) = delete;
|
|
||||||
DeviceManager& operator=(const DeviceManager&) = delete;
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::string allDeviceSpecs;
|
|
||||||
static std::vector<std::shared_ptr<InteroceptorDeviceSpec>>
|
|
||||||
interoceptorDeviceSpecs;
|
|
||||||
static std::vector<std::shared_ptr<ExtrospectorDeviceSpec>>
|
|
||||||
extrospectorDeviceSpecs;
|
|
||||||
static std::vector<std::shared_ptr<SenseDeviceSpec>>
|
|
||||||
senseDeviceSpecs;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace device
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
#endif // DEVICEMANAGER_H
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#ifndef DIRECTOR_H
|
|
||||||
#define DIRECTOR_H
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <goal.h>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
namespace director {
|
|
||||||
|
|
||||||
class Director {
|
|
||||||
public:
|
|
||||||
Director() = default;
|
|
||||||
~Director() = default;
|
|
||||||
|
|
||||||
Goal purpose;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace director
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
#endif // DIRECTOR_H
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#ifndef _MENTAL_ENTITY_H
|
|
||||||
#define _MENTAL_ENTITY_H
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
class MentalEntity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Id = uint32_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#ifndef _MIND_H
|
|
||||||
#define _MIND_H
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <director/director.h>
|
|
||||||
#include <simulator/simulator.h>
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
class Mind
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void execute(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::thread directorThread;
|
|
||||||
std::thread simulatorThread;
|
|
||||||
std::thread subconsciousThread;
|
|
||||||
|
|
||||||
director::Director director;
|
|
||||||
simulator::Simulator canvas;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#ifndef OPTS_H
|
|
||||||
#define OPTS_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
// Define a class to hold the options and parse arguments
|
|
||||||
class OptionParser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OptionParser() : verbose(false), printUsage(false) {}
|
|
||||||
~OptionParser() = default;
|
|
||||||
|
|
||||||
void parseArguments(int argc, char *argv[], char **envp);
|
|
||||||
std::string stringifyOptions(void) const;
|
|
||||||
std::string getUsage() const;
|
|
||||||
|
|
||||||
static OptionParser &getOptions(void)
|
|
||||||
{
|
|
||||||
static OptionParser options;
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
std::string argv0;
|
|
||||||
std::string senseApiLibPath;
|
|
||||||
std::vector<std::string> senseApiLibs;
|
|
||||||
std::string deviceSpecs;
|
|
||||||
std::vector<std::string> deviceSpecFiles;
|
|
||||||
bool verbose, printUsage;
|
|
||||||
|
|
||||||
static struct option longOptions[];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // OPTS_H
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#ifndef _QUALE_H
|
|
||||||
#define _QUALE_H
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <attentionTrigger.h>
|
|
||||||
|
|
||||||
class Quale
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Type
|
|
||||||
{
|
|
||||||
NEUTRAL,
|
|
||||||
/* Bounding refers to qualia such as tactile pressure which
|
|
||||||
* are mostly neutral but disclose information about the limits
|
|
||||||
* of the body.
|
|
||||||
**/
|
|
||||||
BOUNDING,
|
|
||||||
PAINFUL,
|
|
||||||
PLEASURABLE
|
|
||||||
} type;
|
|
||||||
|
|
||||||
int32_t intensity;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NeutralQuale
|
|
||||||
: public Quale
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
class NonNeutralQuale
|
|
||||||
: public Quale, public AttentionTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void eventInd(void);
|
|
||||||
|
|
||||||
public:
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
|
|
||||||
#include <mind.h>
|
|
||||||
-120
@@ -1,120 +0,0 @@
|
|||||||
#include <opts.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
|
|
||||||
struct option OptionParser::longOptions[] = {
|
|
||||||
{"devicespec", required_argument, 0, 's'},
|
|
||||||
{"spec", required_argument, 0, 's'},
|
|
||||||
{"devspec", required_argument, 0, 's'},
|
|
||||||
{"devfile", required_argument, 0, 'd'},
|
|
||||||
{"devicefile", required_argument, 0, 'd'},
|
|
||||||
{"sense-api-lib", required_argument, 0, 'a'},
|
|
||||||
{"senseapi", required_argument, 0, 'a'},
|
|
||||||
{"sense-api-path", required_argument, 0, 'p'},
|
|
||||||
{"verbose", no_argument, 0, 'v'},
|
|
||||||
{"help", no_argument, 0, '?'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
void OptionParser::parseArguments(int argc, char *argv[], char **envp)
|
|
||||||
{
|
|
||||||
(void)envp;
|
|
||||||
int opt;
|
|
||||||
int optionIndex = 0;
|
|
||||||
|
|
||||||
argv0 = argv[0];
|
|
||||||
|
|
||||||
optind = 1; // Reset optind to 1 before parsing
|
|
||||||
while ((opt = getopt_long(
|
|
||||||
argc, argv, "s:d:a:p:v?", longOptions, &optionIndex)) != -1)
|
|
||||||
{
|
|
||||||
switch (opt)
|
|
||||||
{
|
|
||||||
case 's':
|
|
||||||
if (!deviceSpecs.empty()) {
|
|
||||||
deviceSpecs += "||";
|
|
||||||
}
|
|
||||||
deviceSpecs += std::string(optarg);
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
deviceSpecFiles.push_back(optarg);
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
senseApiLibs.push_back(optarg);
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
{
|
|
||||||
struct stat info;
|
|
||||||
|
|
||||||
if (!senseApiLibPath.empty())
|
|
||||||
{
|
|
||||||
std::cerr << std::string(__func__)
|
|
||||||
+ " - Overwriting previous sense-api-path with: " << optarg
|
|
||||||
<< '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stat(optarg, &info) != 0 || !(info.st_mode & S_IFDIR))
|
|
||||||
{
|
|
||||||
throw std::invalid_argument(
|
|
||||||
std::string(__func__) + " - The specified path is not a "
|
|
||||||
"directory: " + optarg);
|
|
||||||
}
|
|
||||||
|
|
||||||
senseApiLibPath = optarg;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'v':
|
|
||||||
verbose = true;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
printUsage = true;
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument(
|
|
||||||
std::string(__func__) + " - Invalid argument encountered: "
|
|
||||||
+ std::string(argv[optind - 1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OptionParser::getUsage() const
|
|
||||||
{
|
|
||||||
return "Usage: " + argv0 + " [-s|--devicespec|--spec|--devspec <device_spec>] "
|
|
||||||
"[-d|--devfile|--devicefile <filename>] "
|
|
||||||
"[-a|--sense-api-lib|--senseapi <filename>] "
|
|
||||||
"[-p|--sense-api-path <directory>] "
|
|
||||||
"[-v|--verbose] "
|
|
||||||
"[-?|--help]";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string OptionParser::stringifyOptions(void) const
|
|
||||||
{
|
|
||||||
std::ostringstream oss;
|
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
oss << "Verbose mode is on" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
oss << "Device Specs: " << deviceSpecs << std::endl;
|
|
||||||
|
|
||||||
oss << "Device Spec Files: ";
|
|
||||||
for (const auto& file : deviceSpecFiles) {
|
|
||||||
oss << file << " ";
|
|
||||||
}
|
|
||||||
oss << std::endl;
|
|
||||||
|
|
||||||
oss << "Sense API Library Path: " << senseApiLibPath << std::endl;
|
|
||||||
oss << "Sense API Libraries: ";
|
|
||||||
for (const auto& lib : senseApiLibs) {
|
|
||||||
oss << lib << " ";
|
|
||||||
}
|
|
||||||
oss << std::endl;
|
|
||||||
|
|
||||||
return oss.str();
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
|
|
||||||
|
|
||||||
noinst_LIBRARIES=libsenseApis.a
|
|
||||||
libsenseApis_a_SOURCES=senseApiManager.cpp
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef _CONFIG_H
|
||||||
|
#define _CONFIG_H
|
||||||
|
|
||||||
|
/* Package information */
|
||||||
|
#define PACKAGE_NAME "@PROJECT_NAME@"
|
||||||
|
#define PACKAGE_VERSION "@PROJECT_VERSION@"
|
||||||
|
|
||||||
|
/* Mind oscillator configuration */
|
||||||
|
#define CONFIG_MIND_VOSCILLATOR_PERIOD_MS @MIND_VOSCILLATOR_PERIOD_MS@
|
||||||
|
#define CONFIG_MIND_VOSCILLATOR_FREQ_MS @MIND_VOSCILLATOR_FREQ_MS@
|
||||||
|
|
||||||
|
/* Cross-compilation configuration */
|
||||||
|
#cmakedefine CMAKE_CROSSCOMPILING
|
||||||
|
|
||||||
|
/* Common Libraries */
|
||||||
|
#cmakedefine CONFIG_LIB_XCBXORG_ENABLED
|
||||||
|
#cmakedefine CONFIG_LIB_ALSA_ENABLED
|
||||||
|
|
||||||
|
/* Sense APIs */
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_XCBWINDOW_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_V4L_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_ALSAMIC_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_LIVOX_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_R3LIVE_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_FASTLIO2_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_ADALIO2_ENABLED
|
||||||
|
#cmakedefine CONFIG_SENSEAPI_DEEPLIO2_ENABLED
|
||||||
|
|
||||||
|
/* Wilzor APIs */
|
||||||
|
#cmakedefine CONFIG_WILZORAPI_XCBMOUSE_ENABLED
|
||||||
|
#cmakedefine CONFIG_WILZORAPI_XCBKEYBOARD_ENABLED
|
||||||
|
#cmakedefine CONFIG_WILZORAPI_ALSAVOICE_ENABLED
|
||||||
|
|
||||||
|
/* Legacy defines for backward compatibility */
|
||||||
|
#cmakedefine CONFIG_XCBWINDOW_ENABLED
|
||||||
|
#cmakedefine CONFIG_V4L_ENABLED
|
||||||
|
#cmakedefine CONFIG_ALSAMIC_ENABLED
|
||||||
|
#cmakedefine CONFIG_LIVOX_ENABLED
|
||||||
|
#cmakedefine CONFIG_R3LIVE_ENABLED
|
||||||
|
#cmakedefine CONFIG_FASTLIO2_ENABLED
|
||||||
|
#cmakedefine CONFIG_ADALIO2_ENABLED
|
||||||
|
#cmakedefine CONFIG_DEEPLIO2_ENABLED
|
||||||
|
#cmakedefine CONFIG_XCBMOUSE_ENABLED
|
||||||
|
#cmakedefine CONFIG_XCBKEYBOARD_ENABLED
|
||||||
|
#cmakedefine CONFIG_ALSAVOICE_ENABLED
|
||||||
|
|
||||||
|
#endif /* _CONFIG_H */
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
#ifndef HK_PREPROCESSOR_H
|
#ifndef SMO_PREPROCESSOR_H
|
||||||
#define HK_PREPROCESSOR_H
|
#define SMO_PREPROCESSOR_H
|
||||||
|
|
||||||
#define HK_Q(x) #x
|
#define SMO_Q(x) #x
|
||||||
#define HK_QUOTE(x) HK_Q(x)
|
#define SMO_QUOTE(x) SMO_Q(x)
|
||||||
|
|
||||||
#define HK_UNMANGLED "C"
|
#define SMO_CONCAT(a, b) a ## b
|
||||||
|
|
||||||
#endif // HK_PREPROCESSOR_H
|
#define SMO_UNMANGLED "C"
|
||||||
|
|
||||||
|
#endif // SMO_PREPROCESSOR_H
|
||||||
|
|||||||
@@ -6,27 +6,29 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace hk {
|
namespace smo {
|
||||||
namespace device {
|
namespace device {
|
||||||
|
|
||||||
class SenseDeviceSpec
|
class DeviceAttachmentSpec
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend std::ostream& operator<<(
|
friend std::ostream& operator<<(
|
||||||
std::ostream& os, const SenseDeviceSpec& spec)
|
std::ostream& os, const DeviceAttachmentSpec& spec)
|
||||||
{
|
{
|
||||||
os << spec.stringify();
|
os << spec.stringify();
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const SenseDeviceSpec& other) const
|
bool operator==(const DeviceAttachmentSpec& other) const
|
||||||
{
|
{
|
||||||
return sensorType == other.sensorType &&
|
return deviceIdentifier == other.deviceIdentifier &&
|
||||||
|
sensorType == other.sensorType &&
|
||||||
provider == other.provider &&
|
provider == other.provider &&
|
||||||
deviceSelector == other.deviceSelector;
|
deviceSelector == other.deviceSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
std::string deviceIdentifier;
|
||||||
char sensorType;
|
char sensorType;
|
||||||
std::string implexor;
|
std::string implexor;
|
||||||
std::string api;
|
std::string api;
|
||||||
@@ -38,8 +40,10 @@ public:
|
|||||||
std::string stringify() const
|
std::string stringify() const
|
||||||
{
|
{
|
||||||
std::ostringstream os;
|
std::ostringstream os;
|
||||||
os << "Device: " << sensorType << ", Implexor: "
|
os << "Device Identifier: " << deviceIdentifier
|
||||||
<< implexor << ", API: " << api << ", API Params: (";
|
<< ", Sensor Type: " << sensorType
|
||||||
|
<< ", Implexor: " << implexor << ", API: " << api
|
||||||
|
<< ", API Params: (";
|
||||||
for (const auto& param : apiParams)
|
for (const auto& param : apiParams)
|
||||||
{
|
{
|
||||||
os << param.first;
|
os << param.first;
|
||||||
@@ -63,15 +67,15 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class InteroceptorDeviceSpec : public SenseDeviceSpec
|
class InteroceptorDevAttachmentSpec : public DeviceAttachmentSpec
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExtrospectorDeviceSpec : public SenseDeviceSpec
|
class ExtrospectorDevAttachmentSpec : public DeviceAttachmentSpec
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace device
|
} // namespace device
|
||||||
} // namespace hk
|
} // namespace smo
|
||||||
|
|
||||||
#endif // SENSORDEVICESPEC_H
|
#endif // SENSORDEVICESPEC_H
|
||||||
+56
-42
@@ -1,49 +1,55 @@
|
|||||||
#ifndef __USER_SENSE_API_LIB_H__
|
#ifndef __USER_SENSE_API_LIB_H__
|
||||||
#define __USER_SENSE_API_LIB_H__
|
#define __USER_SENSE_API_LIB_H__
|
||||||
|
|
||||||
#include <preprocessor.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <user/senseDeviceSpec.h>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <preprocessor.h>
|
||||||
|
#include <user/deviceAttachmentSpec.h>
|
||||||
|
|
||||||
namespace hk {
|
namespace smo {
|
||||||
namespace sense_api {
|
namespace sense_api {
|
||||||
|
|
||||||
/* Exported by all sense API Libraries to tell Harikoff what API the lib uses
|
|
||||||
* to connect to providers; and also to state which implexor APIs it exports.
|
|
||||||
*/
|
|
||||||
typedef int (sal_mho_initializeRdyFn)(void);
|
|
||||||
typedef int (sal_mho_finalizeRdyFn)(void);
|
|
||||||
typedef int (sal_mho_attachDeviceAckFn)(const device::SenseDeviceSpec &desc);
|
|
||||||
typedef int (sal_mho_detachDeviceAckFn)(const device::SenseDeviceSpec &desc);
|
|
||||||
|
|
||||||
struct Sal_Mgmt_HkOps
|
|
||||||
{
|
|
||||||
// Lib calls this function to notify Harikoff that it's done initializing.
|
|
||||||
sal_mho_initializeRdyFn *initializeRdy;
|
|
||||||
// Lib calls this function to notify Harikoff that it's done finalizing.
|
|
||||||
sal_mho_finalizeRdyFn *finalizeRdy;
|
|
||||||
// Lib calls this to notify Harikoff that it's done attaching a device.
|
|
||||||
sal_mho_attachDeviceAckFn *attachDeviceAck;
|
|
||||||
// Lib calls this to notify Harikoff that it's done detaching a device.
|
|
||||||
sal_mho_detachDeviceAckFn *detachDeviceAck;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int (sal_mlo_initializeIndFn)(void);
|
typedef int (sal_mlo_initializeIndFn)(void);
|
||||||
typedef int (sal_mlo_finalizeIndFn)(void);
|
typedef int (sal_mlo_finalizeIndFn)(void);
|
||||||
typedef int (sal_mlo_attachDeviceReqFn)(const device::SenseDeviceSpec &desc);
|
typedef int (sal_mlo_attachDeviceReqFn)(
|
||||||
typedef int (sal_mlo_detachDeviceReqFn)(const device::SenseDeviceSpec &desc);
|
const std::shared_ptr<device::DeviceAttachmentSpec>& desc);
|
||||||
|
typedef int (sal_mlo_detachDeviceReqFn)(
|
||||||
|
const std::shared_ptr<device::DeviceAttachmentSpec>& desc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Hooks provided by Salmanoff to senseApi libraries.
|
||||||
|
|
||||||
|
* This structure contains function pointers that senseApi libraries can use
|
||||||
|
* to interact with Salmanoff's functionality, such as searching for commonLibs.
|
||||||
|
*/
|
||||||
|
struct SalmanoffCallbacks
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @brief Search for a library in Salmanoff's search paths
|
||||||
|
* @param libraryPath The relative filename of the library to search for
|
||||||
|
* @return Optional containing the full path if found, nullopt if not found
|
||||||
|
*
|
||||||
|
* This function searches for the given library in the same search paths
|
||||||
|
* that Salmanoff uses when loading senseApi libraries (user-specified
|
||||||
|
* paths via -p option, current directory, and executable directory).
|
||||||
|
*/
|
||||||
|
std::optional<std::string> (*searchForLibInSmoSearchPaths)(
|
||||||
|
const std::string& libraryPath);
|
||||||
|
};
|
||||||
|
|
||||||
struct Sal_Mgmt_LibOps
|
struct Sal_Mgmt_LibOps
|
||||||
{
|
{
|
||||||
/* When Harikoff loads a sense API lib, it calls this function to initialize
|
/* When Salmanoff loads a sense API lib, it calls this function to initialize
|
||||||
* the lib. When this returns, the lib should be ready to attach devices.
|
* the lib. When this returns, the lib should be ready to attach devices.
|
||||||
*/
|
*/
|
||||||
sal_mlo_initializeIndFn *initializeInd;
|
sal_mlo_initializeIndFn *initializeInd;
|
||||||
/* Harikoff calls this to finalize the lib and free its internal
|
/* Salmanoff calls this to finalize the lib and free its internal
|
||||||
* resources. When this returns, the lib should be ready to be unloaded.
|
* resources. When this returns, the lib should be ready to be unloaded.
|
||||||
*/
|
*/
|
||||||
sal_mlo_finalizeIndFn *finalizeInd;
|
sal_mlo_finalizeIndFn *finalizeInd;
|
||||||
/* Harikoff calls this to attach a device to the lib. When it returns, the
|
/* Salmanoff calls this to attach a device to the lib. When it returns, the
|
||||||
* device should be attached and ready to be implexed.
|
* device should be attached and ready to be implexed.
|
||||||
*/
|
*/
|
||||||
sal_mlo_attachDeviceReqFn *attachDeviceReq;
|
sal_mlo_attachDeviceReqFn *attachDeviceReq;
|
||||||
@@ -62,8 +68,8 @@ struct Sal_Mgmt_LibOps
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* C++ version of the C struct above, which Harikoff uses to manage the
|
/* Exported by all sense API Libraries to tell Salmanoff what API the lib uses
|
||||||
* lib and connect implexors to it.
|
* to connect to providers; and also to state which implexor APIs it exports.
|
||||||
*/
|
*/
|
||||||
class SenseApiDesc
|
class SenseApiDesc
|
||||||
{
|
{
|
||||||
@@ -71,11 +77,6 @@ public:
|
|||||||
class ExportedImplexorApiDesc
|
class ExportedImplexorApiDesc
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ExportedImplexorApiDesc(const std::string name)
|
|
||||||
// The caller should sanity check before calling this constructor.
|
|
||||||
: name(name)
|
|
||||||
{}
|
|
||||||
|
|
||||||
static bool sanityCheck(const ExportedImplexorApiDesc &desc)
|
static bool sanityCheck(const ExportedImplexorApiDesc &desc)
|
||||||
{
|
{
|
||||||
if (desc.name.empty()) { return false; }
|
if (desc.name.empty()) { return false; }
|
||||||
@@ -87,8 +88,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SenseApiDesc() = default;
|
|
||||||
|
|
||||||
std::string stringify() const
|
std::string stringify() const
|
||||||
{
|
{
|
||||||
std::string result = "Name: " + name + "\n";
|
std::string result = "Name: " + name + "\n";
|
||||||
@@ -118,13 +117,28 @@ public:
|
|||||||
Sal_Mgmt_LibOps sal_mgmt_libOps;
|
Sal_Mgmt_LibOps sal_mgmt_libOps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define HK_GET_SENSE_API_DESC_FN_NAME getSenseApiDesc
|
|
||||||
#define HK_GET_SENSE_API_DESC_FN_NAME_STR \
|
|
||||||
HK_QUOTE(HK_GET_SENSE_API_DESC_FN_NAME)
|
|
||||||
|
|
||||||
typedef const SenseApiDesc &(getSenseApiDescFn)(void);
|
#define SMO_GET_SENSE_API_DESC_FN_NAME getSenseApiDesc
|
||||||
|
#define SMO_GET_SENSE_API_DESC_FN_NAME_STR \
|
||||||
|
SMO_QUOTE(SMO_GET_SENSE_API_DESC_FN_NAME)
|
||||||
|
#define SMO_GET_SENSE_API_DESC_FN_TYPEDEF \
|
||||||
|
SMO_CONCAT(SMO_GET_SENSE_API_DESC_FN_NAME, Fn)
|
||||||
|
|
||||||
|
/* Every Sense API library must define a global instance of this
|
||||||
|
* function. Salmanoff will search for it and invoke it via dlsym().
|
||||||
|
*
|
||||||
|
* The function must return a SenseApiDesc struct that Smo will tell
|
||||||
|
* Smo what implexors can be used with it & what APIs it exports.
|
||||||
|
* The SenseApiDesc struct also gives Smo pointers to API functions
|
||||||
|
* to invoke for communication between Smo and the library.
|
||||||
|
*
|
||||||
|
* The SalmanoffCallbacks parameter provides the library with access to
|
||||||
|
* Salmanoff's hooks.
|
||||||
|
*/
|
||||||
|
typedef const SenseApiDesc &(SMO_GET_SENSE_API_DESC_FN_TYPEDEF)(
|
||||||
|
const SalmanoffCallbacks& callbacks);
|
||||||
|
|
||||||
} // namespace sense_api
|
} // namespace sense_api
|
||||||
} // namespace hk
|
} // namespace smo
|
||||||
|
|
||||||
#endif // __USER_SENSE_API_LIB_H__
|
#endif // __USER_SENSE_API_LIB_H__
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# This script was snagged from the MESA project, which uses an MIT license.
|
|
||||||
|
|
||||||
#
|
|
||||||
# Check for Bison.
|
|
||||||
#
|
|
||||||
# This macro verifies that Bison is installed. If successful, then
|
|
||||||
# 1) YACC is set to bison -y (to emulate YACC calls)
|
|
||||||
# 2) BISON is set to bison
|
|
||||||
#
|
|
||||||
AC_DEFUN([AC_PROG_BISON],
|
|
||||||
[AC_PROG_YACC()
|
|
||||||
if test "$YACC" != "bison -y"; then
|
|
||||||
AC_SUBST(BISON,[])
|
|
||||||
AC_MSG_WARN([bison not found])
|
|
||||||
else
|
|
||||||
AC_SUBST(BISON,[bison])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# This script was snagged from the MESA project, which uses an MIT license.
|
|
||||||
|
|
||||||
#
|
|
||||||
# Check for FLEX.
|
|
||||||
#
|
|
||||||
# This macro verifies that flex is installed. If successful, then
|
|
||||||
# 1) LEX is set to flex (to emulate lex calls)
|
|
||||||
# 2) FLEX is set to flex
|
|
||||||
#
|
|
||||||
AC_DEFUN([AC_PROG_FLEX], [
|
|
||||||
AC_PROG_LEX(noyywrap)
|
|
||||||
if test "$LEX" != "flex"; then
|
|
||||||
AC_SUBST(FLEX,[])
|
|
||||||
AC_MSG_ERROR([flex not found])
|
|
||||||
else
|
|
||||||
AC_SUBST(FLEX,[flex])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
# ===========================================================================
|
|
||||||
# https://www.gnu.org/software/autoconf-archive/ax_boost_asio.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_BOOST_ASIO
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Test for Asio library from the Boost C++ libraries. The macro requires a
|
|
||||||
# preceding call to AX_BOOST_BASE. Further documentation is available at
|
|
||||||
# <http://randspringer.de/boost/index.html>.
|
|
||||||
#
|
|
||||||
# This macro calls:
|
|
||||||
#
|
|
||||||
# AC_SUBST(BOOST_ASIO_LIB)
|
|
||||||
#
|
|
||||||
# And sets:
|
|
||||||
#
|
|
||||||
# HAVE_BOOST_ASIO
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
|
||||||
# Copyright (c) 2008 Pete Greenwell <pete@mu.org>
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification, are
|
|
||||||
# permitted in any medium without royalty provided the copyright notice
|
|
||||||
# and this notice are preserved. This file is offered as-is, without any
|
|
||||||
# warranty.
|
|
||||||
|
|
||||||
#serial 18
|
|
||||||
|
|
||||||
AC_DEFUN([AX_BOOST_ASIO_gte_1_69_0],
|
|
||||||
[
|
|
||||||
AC_ARG_WITH([boost-asio],
|
|
||||||
AS_HELP_STRING([--with-boost-asio@<:@=special-lib@:>@],
|
|
||||||
[use the ASIO library from boost - it is possible to specify a certain library for the linker
|
|
||||||
e.g. --with-boost-asio=boost_system-gcc41-mt-1_34 ]),
|
|
||||||
[
|
|
||||||
if test "$withval" = "no"; then
|
|
||||||
want_boost="no"
|
|
||||||
elif test "$withval" = "yes"; then
|
|
||||||
want_boost="yes"
|
|
||||||
ax_boost_user_asio_lib=""
|
|
||||||
else
|
|
||||||
want_boost="yes"
|
|
||||||
ax_boost_user_asio_lib="$withval"
|
|
||||||
fi
|
|
||||||
],
|
|
||||||
[want_boost="yes"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if test "x$want_boost" = "xyes"; then
|
|
||||||
AC_REQUIRE([AC_PROG_CC])
|
|
||||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
|
||||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
|
||||||
export CPPFLAGS
|
|
||||||
|
|
||||||
LDFLAGS_SAVED="$LDFLAGS"
|
|
||||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
|
||||||
export LDFLAGS
|
|
||||||
|
|
||||||
AC_CACHE_CHECK(whether the Boost::ASIO library is available,
|
|
||||||
ax_cv_boost_asio,
|
|
||||||
[AC_LANG_PUSH([C++])
|
|
||||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ @%:@include <boost/asio.hpp>
|
|
||||||
]],
|
|
||||||
[[
|
|
||||||
|
|
||||||
boost::asio::io_service io;
|
|
||||||
boost::system::error_code timer_result;
|
|
||||||
boost::asio::deadline_timer t(io);
|
|
||||||
t.cancel();
|
|
||||||
io.run_one();
|
|
||||||
return 0;
|
|
||||||
]])],
|
|
||||||
ax_cv_boost_asio=yes, ax_cv_boost_asio=no)
|
|
||||||
AC_LANG_POP([C++])
|
|
||||||
])
|
|
||||||
if test "x$ax_cv_boost_asio" = "xyes"; then
|
|
||||||
AC_DEFINE(HAVE_BOOST_ASIO,,
|
|
||||||
[define if the Boost::ASIO library is available])
|
|
||||||
BOOST_ASIO_LIB=""
|
|
||||||
AC_SUBST(BOOST_ASIO_LIB)
|
|
||||||
HAVE_BOOST_ASIO="yes"
|
|
||||||
else
|
|
||||||
HAVE_BOOST_ASIO="no"
|
|
||||||
fi
|
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
|
||||||
LDFLAGS="$LDFLAGS_SAVED"
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
@@ -1,305 +0,0 @@
|
|||||||
# ===========================================================================
|
|
||||||
# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html
|
|
||||||
# ===========================================================================
|
|
||||||
#
|
|
||||||
# SYNOPSIS
|
|
||||||
#
|
|
||||||
# AX_BOOST_BASE([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
|
||||||
#
|
|
||||||
# DESCRIPTION
|
|
||||||
#
|
|
||||||
# Test for the Boost C++ libraries of a particular version (or newer)
|
|
||||||
#
|
|
||||||
# If no path to the installed boost library is given the macro searches
|
|
||||||
# under /usr, /usr/local, /opt, /opt/local and /opt/homebrew and evaluates
|
|
||||||
# the $BOOST_ROOT environment variable. Further documentation is available
|
|
||||||
# at <http://randspringer.de/boost/index.html>.
|
|
||||||
#
|
|
||||||
# This macro calls:
|
|
||||||
#
|
|
||||||
# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS)
|
|
||||||
#
|
|
||||||
# And sets:
|
|
||||||
#
|
|
||||||
# HAVE_BOOST
|
|
||||||
#
|
|
||||||
# LICENSE
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008 Thomas Porschberg <thomas@randspringer.de>
|
|
||||||
# Copyright (c) 2009 Peter Adolphs
|
|
||||||
#
|
|
||||||
# Copying and distribution of this file, with or without modification, are
|
|
||||||
# permitted in any medium without royalty provided the copyright notice
|
|
||||||
# and this notice are preserved. This file is offered as-is, without any
|
|
||||||
# warranty.
|
|
||||||
|
|
||||||
#serial 55
|
|
||||||
|
|
||||||
# example boost program (need to pass version)
|
|
||||||
m4_define([_AX_BOOST_BASE_PROGRAM],
|
|
||||||
[AC_LANG_PROGRAM([[
|
|
||||||
#include <boost/version.hpp>
|
|
||||||
]],[[
|
|
||||||
(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))]));
|
|
||||||
]])])
|
|
||||||
|
|
||||||
AC_DEFUN([AX_BOOST_BASE],
|
|
||||||
[
|
|
||||||
AC_ARG_WITH([boost],
|
|
||||||
[AS_HELP_STRING([--with-boost@<:@=ARG@:>@],
|
|
||||||
[use Boost library from a standard location (ARG=yes),
|
|
||||||
from the specified location (ARG=<path>),
|
|
||||||
or disable it (ARG=no)
|
|
||||||
@<:@ARG=yes@:>@ ])],
|
|
||||||
[
|
|
||||||
AS_CASE([$withval],
|
|
||||||
[no],[want_boost="no";_AX_BOOST_BASE_boost_path=""],
|
|
||||||
[yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""],
|
|
||||||
[want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"])
|
|
||||||
],
|
|
||||||
[want_boost="yes"])
|
|
||||||
|
|
||||||
|
|
||||||
AC_ARG_WITH([boost-libdir],
|
|
||||||
[AS_HELP_STRING([--with-boost-libdir=LIB_DIR],
|
|
||||||
[Force given directory for boost libraries.
|
|
||||||
Note that this will override library path detection,
|
|
||||||
so use this parameter only if default library detection fails
|
|
||||||
and you know exactly where your boost libraries are located.])],
|
|
||||||
[
|
|
||||||
AS_IF([test -d "$withval"],
|
|
||||||
[_AX_BOOST_BASE_boost_lib_path="$withval"],
|
|
||||||
[AC_MSG_ERROR([--with-boost-libdir expected directory name])])
|
|
||||||
],
|
|
||||||
[_AX_BOOST_BASE_boost_lib_path=""])
|
|
||||||
|
|
||||||
BOOST_LDFLAGS=""
|
|
||||||
BOOST_CPPFLAGS=""
|
|
||||||
AS_IF([test "x$want_boost" = "xyes"],
|
|
||||||
[_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])])
|
|
||||||
AC_SUBST(BOOST_CPPFLAGS)
|
|
||||||
AC_SUBST(BOOST_LDFLAGS)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# convert a version string in $2 to numeric and affect to polymorphic var $1
|
|
||||||
AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[
|
|
||||||
AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"])
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'`
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'`
|
|
||||||
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"],
|
|
||||||
[AC_MSG_ERROR([You should at least specify libboost major version])])
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'`
|
|
||||||
AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"],
|
|
||||||
[_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"])
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'`
|
|
||||||
AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"],
|
|
||||||
[_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"])
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor`
|
|
||||||
AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET)
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl Run the detection of boost should be run only if $want_boost
|
|
||||||
AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[
|
|
||||||
_AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1])
|
|
||||||
succeeded=no
|
|
||||||
|
|
||||||
|
|
||||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
|
||||||
dnl On 64-bit systems check for system libraries in both lib64 and lib.
|
|
||||||
dnl The former is specified by FHS, but e.g. Debian does not adhere to
|
|
||||||
dnl this (as it rises problems for generic multi-arch support).
|
|
||||||
dnl The last entry in the list is chosen by default when no libraries
|
|
||||||
dnl are found, e.g. when only header-only libraries are installed!
|
|
||||||
AS_CASE([${host_cpu}],
|
|
||||||
[x86_64],[libsubdirs="lib64 libx32 lib lib64"],
|
|
||||||
[mips*64*],[libsubdirs="lib64 lib32 lib lib64"],
|
|
||||||
[ppc64|powerpc64|s390x|sparc64|aarch64|ppc64le|powerpc64le|riscv64|e2k|loongarch64],[libsubdirs="lib64 lib lib64"],
|
|
||||||
[libsubdirs="lib"]
|
|
||||||
)
|
|
||||||
|
|
||||||
dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give
|
|
||||||
dnl them priority over the other paths since, if libs are found there, they
|
|
||||||
dnl are almost assuredly the ones desired.
|
|
||||||
AS_CASE([${host_cpu}],
|
|
||||||
[i?86],[multiarch_libsubdir="lib/i386-${host_os}"],
|
|
||||||
[armv7l],[multiarch_libsubdir="lib/arm-${host_os}"],
|
|
||||||
[multiarch_libsubdir="lib/${host_cpu}-${host_os}"]
|
|
||||||
)
|
|
||||||
|
|
||||||
dnl first we check the system location for boost libraries
|
|
||||||
dnl this location is chosen if boost libraries are installed with the --layout=system option
|
|
||||||
dnl or if you install boost with RPM
|
|
||||||
AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[
|
|
||||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"])
|
|
||||||
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include"
|
|
||||||
for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do
|
|
||||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"])
|
|
||||||
AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[
|
|
||||||
AC_MSG_RESULT([yes])
|
|
||||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp";
|
|
||||||
break;
|
|
||||||
],
|
|
||||||
[AC_MSG_RESULT([no])])
|
|
||||||
done],[
|
|
||||||
AC_MSG_RESULT([no])])
|
|
||||||
],[
|
|
||||||
if test X"$cross_compiling" = Xyes; then
|
|
||||||
search_libsubdirs=$multiarch_libsubdir
|
|
||||||
else
|
|
||||||
search_libsubdirs="$multiarch_libsubdir $libsubdirs"
|
|
||||||
fi
|
|
||||||
for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local /opt/homebrew ; do
|
|
||||||
if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then
|
|
||||||
for libsubdir in $search_libsubdirs ; do
|
|
||||||
if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
|
||||||
done
|
|
||||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir"
|
|
||||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include"
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl overwrite ld flags if we have required special directory with
|
|
||||||
dnl --with-boost-libdir parameter
|
|
||||||
AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"],
|
|
||||||
[BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"])
|
|
||||||
|
|
||||||
AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)])
|
|
||||||
CPPFLAGS_SAVED="$CPPFLAGS"
|
|
||||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
|
||||||
export CPPFLAGS
|
|
||||||
|
|
||||||
LDFLAGS_SAVED="$LDFLAGS"
|
|
||||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
|
||||||
export LDFLAGS
|
|
||||||
|
|
||||||
AC_REQUIRE([AC_PROG_CXX])
|
|
||||||
AC_LANG_PUSH(C++)
|
|
||||||
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
succeeded=yes
|
|
||||||
found_system=yes
|
|
||||||
],[
|
|
||||||
])
|
|
||||||
AC_LANG_POP([C++])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl if we found no boost with system layout we search for boost libraries
|
|
||||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
|
||||||
if test "x$succeeded" != "xyes" ; then
|
|
||||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
|
||||||
LDFLAGS="$LDFLAGS_SAVED"
|
|
||||||
BOOST_CPPFLAGS=
|
|
||||||
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
|
||||||
BOOST_LDFLAGS=
|
|
||||||
fi
|
|
||||||
_version=0
|
|
||||||
if test -n "$_AX_BOOST_BASE_boost_path" ; then
|
|
||||||
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then
|
|
||||||
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
|
|
||||||
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
|
||||||
V_CHECK=`expr $_version_tmp \> $_version`
|
|
||||||
if test "x$V_CHECK" = "x1" ; then
|
|
||||||
_version=$_version_tmp
|
|
||||||
fi
|
|
||||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
|
||||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE"
|
|
||||||
done
|
|
||||||
dnl if nothing found search for layout used in Windows distributions
|
|
||||||
if test -z "$BOOST_CPPFLAGS"; then
|
|
||||||
if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then
|
|
||||||
BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
dnl if we found something and BOOST_LDFLAGS was unset before
|
|
||||||
dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here.
|
|
||||||
if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then
|
|
||||||
for libsubdir in $libsubdirs ; do
|
|
||||||
if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
|
||||||
done
|
|
||||||
BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if test "x$cross_compiling" != "xyes" ; then
|
|
||||||
for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local /opt/homebrew ; do
|
|
||||||
if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then
|
|
||||||
for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do
|
|
||||||
_version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'`
|
|
||||||
V_CHECK=`expr $_version_tmp \> $_version`
|
|
||||||
if test "x$V_CHECK" = "x1" ; then
|
|
||||||
_version=$_version_tmp
|
|
||||||
best_path=$_AX_BOOST_BASE_boost_path
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
|
||||||
BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE"
|
|
||||||
if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
|
||||||
for libsubdir in $libsubdirs ; do
|
|
||||||
if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
|
||||||
done
|
|
||||||
BOOST_LDFLAGS="-L$best_path/$libsubdir"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -n "$BOOST_ROOT" ; then
|
|
||||||
for libsubdir in $libsubdirs ; do
|
|
||||||
if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi
|
|
||||||
done
|
|
||||||
if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/$libsubdir" && test -r "$BOOST_ROOT/stage/$libsubdir"; then
|
|
||||||
version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'`
|
|
||||||
stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'`
|
|
||||||
stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'`
|
|
||||||
V_CHECK=`expr $stage_version_shorten \>\= $_version`
|
|
||||||
if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then
|
|
||||||
AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT)
|
|
||||||
BOOST_CPPFLAGS="-I$BOOST_ROOT"
|
|
||||||
BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
|
|
||||||
export CPPFLAGS
|
|
||||||
LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
|
|
||||||
export LDFLAGS
|
|
||||||
|
|
||||||
AC_LANG_PUSH(C++)
|
|
||||||
AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[
|
|
||||||
AC_MSG_RESULT(yes)
|
|
||||||
succeeded=yes
|
|
||||||
found_system=yes
|
|
||||||
],[
|
|
||||||
])
|
|
||||||
AC_LANG_POP([C++])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test "x$succeeded" != "xyes" ; then
|
|
||||||
if test "x$_version" = "x0" ; then
|
|
||||||
AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).])
|
|
||||||
fi
|
|
||||||
BOOST_LDFLAGS=""
|
|
||||||
BOOST_CPPFLAGS=""
|
|
||||||
# execute ACTION-IF-NOT-FOUND (if present):
|
|
||||||
ifelse([$3], , :, [$3])
|
|
||||||
else
|
|
||||||
AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available])
|
|
||||||
# execute ACTION-IF-FOUND (if present):
|
|
||||||
ifelse([$2], , :, [$2])
|
|
||||||
fi
|
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
|
||||||
LDFLAGS="$LDFLAGS_SAVED"
|
|
||||||
|
|
||||||
])
|
|
||||||
Vendored
-8427
File diff suppressed because it is too large
Load Diff
Vendored
-437
@@ -1,437 +0,0 @@
|
|||||||
# Helper functions for option handling. -*- Autoconf -*-
|
|
||||||
#
|
|
||||||
# Copyright (C) 2004-2005, 2007-2009, 2011-2019, 2021-2022 Free
|
|
||||||
# Software Foundation, Inc.
|
|
||||||
# Written by Gary V. Vaughan, 2004
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation gives
|
|
||||||
# unlimited permission to copy and/or distribute it, with or without
|
|
||||||
# modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# serial 8 ltoptions.m4
|
|
||||||
|
|
||||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
|
||||||
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
|
|
||||||
# ------------------------------------------
|
|
||||||
m4_define([_LT_MANGLE_OPTION],
|
|
||||||
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
|
|
||||||
# ---------------------------------------
|
|
||||||
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
|
|
||||||
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
|
|
||||||
# saved as a flag.
|
|
||||||
m4_define([_LT_SET_OPTION],
|
|
||||||
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
|
|
||||||
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
|
|
||||||
_LT_MANGLE_DEFUN([$1], [$2]),
|
|
||||||
[m4_warning([Unknown $1 option '$2'])])[]dnl
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
|
|
||||||
# ------------------------------------------------------------
|
|
||||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
|
||||||
m4_define([_LT_IF_OPTION],
|
|
||||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
|
|
||||||
# -------------------------------------------------------
|
|
||||||
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
|
|
||||||
# are set.
|
|
||||||
m4_define([_LT_UNLESS_OPTIONS],
|
|
||||||
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
|
||||||
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
|
|
||||||
[m4_define([$0_found])])])[]dnl
|
|
||||||
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
|
|
||||||
])[]dnl
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
|
|
||||||
# ----------------------------------------
|
|
||||||
# OPTION-LIST is a space-separated list of Libtool options associated
|
|
||||||
# with MACRO-NAME. If any OPTION has a matching handler declared with
|
|
||||||
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
|
|
||||||
# the unknown option and exit.
|
|
||||||
m4_defun([_LT_SET_OPTIONS],
|
|
||||||
[# Set options
|
|
||||||
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
|
|
||||||
[_LT_SET_OPTION([$1], _LT_Option)])
|
|
||||||
|
|
||||||
m4_if([$1],[LT_INIT],[
|
|
||||||
dnl
|
|
||||||
dnl Simply set some default values (i.e off) if boolean options were not
|
|
||||||
dnl specified:
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
|
|
||||||
])
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
|
|
||||||
])
|
|
||||||
dnl
|
|
||||||
dnl If no reference was made to various pairs of opposing options, then
|
|
||||||
dnl we run the default mode handler for the pair. For example, if neither
|
|
||||||
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
|
|
||||||
dnl archives by default:
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
|
|
||||||
[_LT_ENABLE_FAST_INSTALL])
|
|
||||||
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
|
|
||||||
[_LT_WITH_AIX_SONAME([aix])])
|
|
||||||
])
|
|
||||||
])# _LT_SET_OPTIONS
|
|
||||||
|
|
||||||
|
|
||||||
## --------------------------------- ##
|
|
||||||
## Macros to handle LT_INIT options. ##
|
|
||||||
## --------------------------------- ##
|
|
||||||
|
|
||||||
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
|
|
||||||
# -----------------------------------------
|
|
||||||
m4_define([_LT_MANGLE_DEFUN],
|
|
||||||
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
|
|
||||||
|
|
||||||
|
|
||||||
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
|
|
||||||
# -----------------------------------------------
|
|
||||||
m4_define([LT_OPTION_DEFINE],
|
|
||||||
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
|
|
||||||
])# LT_OPTION_DEFINE
|
|
||||||
|
|
||||||
|
|
||||||
# dlopen
|
|
||||||
# ------
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
|
|
||||||
])
|
|
||||||
|
|
||||||
AU_DEFUN([AC_LIBTOOL_DLOPEN],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], [dlopen])
|
|
||||||
AC_DIAGNOSE([obsolete],
|
|
||||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
|
||||||
put the 'dlopen' option into LT_INIT's first parameter.])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
|
|
||||||
|
|
||||||
|
|
||||||
# win32-dll
|
|
||||||
# ---------
|
|
||||||
# Declare package support for building win32 dll's.
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
|
|
||||||
[enable_win32_dll=yes
|
|
||||||
|
|
||||||
case $host in
|
|
||||||
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
|
|
||||||
AC_CHECK_TOOL(AS, as, false)
|
|
||||||
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
|
|
||||||
AC_CHECK_TOOL(OBJDUMP, objdump, false)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
test -z "$AS" && AS=as
|
|
||||||
_LT_DECL([], [AS], [1], [Assembler program])dnl
|
|
||||||
|
|
||||||
test -z "$DLLTOOL" && DLLTOOL=dlltool
|
|
||||||
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
|
|
||||||
|
|
||||||
test -z "$OBJDUMP" && OBJDUMP=objdump
|
|
||||||
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
|
|
||||||
])# win32-dll
|
|
||||||
|
|
||||||
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
|
|
||||||
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
|
||||||
_LT_SET_OPTION([LT_INIT], [win32-dll])
|
|
||||||
AC_DIAGNOSE([obsolete],
|
|
||||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
|
||||||
put the 'win32-dll' option into LT_INIT's first parameter.])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_ENABLE_SHARED([DEFAULT])
|
|
||||||
# ----------------------------
|
|
||||||
# implement the --enable-shared flag, and supports the 'shared' and
|
|
||||||
# 'disable-shared' LT_INIT options.
|
|
||||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
|
||||||
m4_define([_LT_ENABLE_SHARED],
|
|
||||||
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
|
||||||
AC_ARG_ENABLE([shared],
|
|
||||||
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
|
|
||||||
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
|
|
||||||
[p=${PACKAGE-default}
|
|
||||||
case $enableval in
|
|
||||||
yes) enable_shared=yes ;;
|
|
||||||
no) enable_shared=no ;;
|
|
||||||
*)
|
|
||||||
enable_shared=no
|
|
||||||
# Look at the argument we got. We use all the common list separators.
|
|
||||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
|
||||||
for pkg in $enableval; do
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
if test "X$pkg" = "X$p"; then
|
|
||||||
enable_shared=yes
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
;;
|
|
||||||
esac],
|
|
||||||
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
|
|
||||||
|
|
||||||
_LT_DECL([build_libtool_libs], [enable_shared], [0],
|
|
||||||
[Whether or not to build shared libraries])
|
|
||||||
])# _LT_ENABLE_SHARED
|
|
||||||
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
|
|
||||||
|
|
||||||
# Old names:
|
|
||||||
AC_DEFUN([AC_ENABLE_SHARED],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([AC_DISABLE_SHARED],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], [disable-shared])
|
|
||||||
])
|
|
||||||
|
|
||||||
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
|
|
||||||
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
|
|
||||||
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_ENABLE_STATIC([DEFAULT])
|
|
||||||
# ----------------------------
|
|
||||||
# implement the --enable-static flag, and support the 'static' and
|
|
||||||
# 'disable-static' LT_INIT options.
|
|
||||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
|
||||||
m4_define([_LT_ENABLE_STATIC],
|
|
||||||
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
|
||||||
AC_ARG_ENABLE([static],
|
|
||||||
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
|
|
||||||
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
|
|
||||||
[p=${PACKAGE-default}
|
|
||||||
case $enableval in
|
|
||||||
yes) enable_static=yes ;;
|
|
||||||
no) enable_static=no ;;
|
|
||||||
*)
|
|
||||||
enable_static=no
|
|
||||||
# Look at the argument we got. We use all the common list separators.
|
|
||||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
|
||||||
for pkg in $enableval; do
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
if test "X$pkg" = "X$p"; then
|
|
||||||
enable_static=yes
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
;;
|
|
||||||
esac],
|
|
||||||
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
|
|
||||||
|
|
||||||
_LT_DECL([build_old_libs], [enable_static], [0],
|
|
||||||
[Whether or not to build static libraries])
|
|
||||||
])# _LT_ENABLE_STATIC
|
|
||||||
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
|
|
||||||
|
|
||||||
# Old names:
|
|
||||||
AC_DEFUN([AC_ENABLE_STATIC],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
|
|
||||||
])
|
|
||||||
|
|
||||||
AC_DEFUN([AC_DISABLE_STATIC],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], [disable-static])
|
|
||||||
])
|
|
||||||
|
|
||||||
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
|
|
||||||
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
|
|
||||||
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
|
|
||||||
# ----------------------------------
|
|
||||||
# implement the --enable-fast-install flag, and support the 'fast-install'
|
|
||||||
# and 'disable-fast-install' LT_INIT options.
|
|
||||||
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
|
|
||||||
m4_define([_LT_ENABLE_FAST_INSTALL],
|
|
||||||
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
|
|
||||||
AC_ARG_ENABLE([fast-install],
|
|
||||||
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
|
|
||||||
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
|
|
||||||
[p=${PACKAGE-default}
|
|
||||||
case $enableval in
|
|
||||||
yes) enable_fast_install=yes ;;
|
|
||||||
no) enable_fast_install=no ;;
|
|
||||||
*)
|
|
||||||
enable_fast_install=no
|
|
||||||
# Look at the argument we got. We use all the common list separators.
|
|
||||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
|
||||||
for pkg in $enableval; do
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
if test "X$pkg" = "X$p"; then
|
|
||||||
enable_fast_install=yes
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
;;
|
|
||||||
esac],
|
|
||||||
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
|
|
||||||
|
|
||||||
_LT_DECL([fast_install], [enable_fast_install], [0],
|
|
||||||
[Whether or not to optimize for fast installation])dnl
|
|
||||||
])# _LT_ENABLE_FAST_INSTALL
|
|
||||||
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
|
|
||||||
|
|
||||||
# Old names:
|
|
||||||
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
|
|
||||||
AC_DIAGNOSE([obsolete],
|
|
||||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
|
||||||
the 'fast-install' option into LT_INIT's first parameter.])
|
|
||||||
])
|
|
||||||
|
|
||||||
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
|
|
||||||
AC_DIAGNOSE([obsolete],
|
|
||||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
|
|
||||||
the 'disable-fast-install' option into LT_INIT's first parameter.])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
|
|
||||||
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_WITH_AIX_SONAME([DEFAULT])
|
|
||||||
# ----------------------------------
|
|
||||||
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
|
|
||||||
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
|
|
||||||
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
|
|
||||||
m4_define([_LT_WITH_AIX_SONAME],
|
|
||||||
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
|
|
||||||
shared_archive_member_spec=
|
|
||||||
case $host,$enable_shared in
|
|
||||||
power*-*-aix[[5-9]]*,yes)
|
|
||||||
AC_MSG_CHECKING([which variant of shared library versioning to provide])
|
|
||||||
AC_ARG_WITH([aix-soname],
|
|
||||||
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
|
|
||||||
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
|
|
||||||
[case $withval in
|
|
||||||
aix|svr4|both)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
lt_cv_with_aix_soname=$with_aix_soname],
|
|
||||||
[AC_CACHE_VAL([lt_cv_with_aix_soname],
|
|
||||||
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
|
|
||||||
with_aix_soname=$lt_cv_with_aix_soname])
|
|
||||||
AC_MSG_RESULT([$with_aix_soname])
|
|
||||||
if test aix != "$with_aix_soname"; then
|
|
||||||
# For the AIX way of multilib, we name the shared archive member
|
|
||||||
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
|
|
||||||
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
|
|
||||||
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
|
|
||||||
# the AIX toolchain works better with OBJECT_MODE set (default 32).
|
|
||||||
if test 64 = "${OBJECT_MODE-32}"; then
|
|
||||||
shared_archive_member_spec=shr_64
|
|
||||||
else
|
|
||||||
shared_archive_member_spec=shr
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
with_aix_soname=aix
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
_LT_DECL([], [shared_archive_member_spec], [0],
|
|
||||||
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
|
|
||||||
])# _LT_WITH_AIX_SONAME
|
|
||||||
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
|
|
||||||
|
|
||||||
|
|
||||||
# _LT_WITH_PIC([MODE])
|
|
||||||
# --------------------
|
|
||||||
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
|
|
||||||
# LT_INIT options.
|
|
||||||
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
|
|
||||||
m4_define([_LT_WITH_PIC],
|
|
||||||
[AC_ARG_WITH([pic],
|
|
||||||
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
|
|
||||||
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
|
|
||||||
[lt_p=${PACKAGE-default}
|
|
||||||
case $withval in
|
|
||||||
yes|no) pic_mode=$withval ;;
|
|
||||||
*)
|
|
||||||
pic_mode=default
|
|
||||||
# Look at the argument we got. We use all the common list separators.
|
|
||||||
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
|
|
||||||
for lt_pkg in $withval; do
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
if test "X$lt_pkg" = "X$lt_p"; then
|
|
||||||
pic_mode=yes
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
IFS=$lt_save_ifs
|
|
||||||
;;
|
|
||||||
esac],
|
|
||||||
[pic_mode=m4_default([$1], [default])])
|
|
||||||
|
|
||||||
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
|
|
||||||
])# _LT_WITH_PIC
|
|
||||||
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
|
|
||||||
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
|
|
||||||
|
|
||||||
# Old name:
|
|
||||||
AU_DEFUN([AC_LIBTOOL_PICMODE],
|
|
||||||
[_LT_SET_OPTION([LT_INIT], [pic-only])
|
|
||||||
AC_DIAGNOSE([obsolete],
|
|
||||||
[$0: Remove this warning and the call to _LT_SET_OPTION when you
|
|
||||||
put the 'pic-only' option into LT_INIT's first parameter.])
|
|
||||||
])
|
|
||||||
|
|
||||||
dnl aclocal-1.4 backwards compatibility:
|
|
||||||
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
|
|
||||||
|
|
||||||
## ----------------- ##
|
|
||||||
## LTDL_INIT Options ##
|
|
||||||
## ----------------- ##
|
|
||||||
|
|
||||||
m4_define([_LTDL_MODE], [])
|
|
||||||
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
|
|
||||||
[m4_define([_LTDL_MODE], [nonrecursive])])
|
|
||||||
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
|
|
||||||
[m4_define([_LTDL_MODE], [recursive])])
|
|
||||||
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
|
|
||||||
[m4_define([_LTDL_MODE], [subproject])])
|
|
||||||
|
|
||||||
m4_define([_LTDL_TYPE], [])
|
|
||||||
LT_OPTION_DEFINE([LTDL_INIT], [installable],
|
|
||||||
[m4_define([_LTDL_TYPE], [installable])])
|
|
||||||
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
|
|
||||||
[m4_define([_LTDL_TYPE], [convenience])])
|
|
||||||
Vendored
-124
@@ -1,124 +0,0 @@
|
|||||||
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
|
|
||||||
#
|
|
||||||
# Copyright (C) 2004-2005, 2007-2008, 2011-2019, 2021-2022 Free Software
|
|
||||||
# Foundation, Inc.
|
|
||||||
# Written by Gary V. Vaughan, 2004
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation gives
|
|
||||||
# unlimited permission to copy and/or distribute it, with or without
|
|
||||||
# modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# serial 6 ltsugar.m4
|
|
||||||
|
|
||||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
|
||||||
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_join(SEP, ARG1, [ARG2...])
|
|
||||||
# -----------------------------
|
|
||||||
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
|
|
||||||
# associated separator.
|
|
||||||
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
|
|
||||||
# versions in m4sugar had bugs.
|
|
||||||
m4_define([lt_join],
|
|
||||||
[m4_if([$#], [1], [],
|
|
||||||
[$#], [2], [[$2]],
|
|
||||||
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
|
|
||||||
m4_define([_lt_join],
|
|
||||||
[m4_if([$#$2], [2], [],
|
|
||||||
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_car(LIST)
|
|
||||||
# lt_cdr(LIST)
|
|
||||||
# ------------
|
|
||||||
# Manipulate m4 lists.
|
|
||||||
# These macros are necessary as long as will still need to support
|
|
||||||
# Autoconf-2.59, which quotes differently.
|
|
||||||
m4_define([lt_car], [[$1]])
|
|
||||||
m4_define([lt_cdr],
|
|
||||||
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
|
|
||||||
[$#], 1, [],
|
|
||||||
[m4_dquote(m4_shift($@))])])
|
|
||||||
m4_define([lt_unquote], $1)
|
|
||||||
|
|
||||||
|
|
||||||
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
|
|
||||||
# ------------------------------------------
|
|
||||||
# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
|
|
||||||
# Note that neither SEPARATOR nor STRING are expanded; they are appended
|
|
||||||
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
|
|
||||||
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
|
|
||||||
# than defined and empty).
|
|
||||||
#
|
|
||||||
# This macro is needed until we can rely on Autoconf 2.62, since earlier
|
|
||||||
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
|
|
||||||
m4_define([lt_append],
|
|
||||||
[m4_define([$1],
|
|
||||||
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
# Produce a SEP delimited list of all paired combinations of elements of
|
|
||||||
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
|
|
||||||
# has the form PREFIXmINFIXSUFFIXn.
|
|
||||||
# Needed until we can rely on m4_combine added in Autoconf 2.62.
|
|
||||||
m4_define([lt_combine],
|
|
||||||
[m4_if(m4_eval([$# > 3]), [1],
|
|
||||||
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
|
|
||||||
[[m4_foreach([_Lt_prefix], [$2],
|
|
||||||
[m4_foreach([_Lt_suffix],
|
|
||||||
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
|
|
||||||
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
|
|
||||||
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
|
|
||||||
m4_define([lt_if_append_uniq],
|
|
||||||
[m4_ifdef([$1],
|
|
||||||
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
|
|
||||||
[lt_append([$1], [$2], [$3])$4],
|
|
||||||
[$5])],
|
|
||||||
[lt_append([$1], [$2], [$3])$4])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_dict_add(DICT, KEY, VALUE)
|
|
||||||
# -----------------------------
|
|
||||||
m4_define([lt_dict_add],
|
|
||||||
[m4_define([$1($2)], [$3])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
|
|
||||||
# --------------------------------------------
|
|
||||||
m4_define([lt_dict_add_subkey],
|
|
||||||
[m4_define([$1($2:$3)], [$4])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_dict_fetch(DICT, KEY, [SUBKEY])
|
|
||||||
# ----------------------------------
|
|
||||||
m4_define([lt_dict_fetch],
|
|
||||||
[m4_ifval([$3],
|
|
||||||
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
|
|
||||||
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
|
|
||||||
# -----------------------------------------------------------------
|
|
||||||
m4_define([lt_if_dict_fetch],
|
|
||||||
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
|
|
||||||
[$5],
|
|
||||||
[$6])])
|
|
||||||
|
|
||||||
|
|
||||||
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
|
|
||||||
# --------------------------------------------------------------
|
|
||||||
m4_define([lt_dict_filter],
|
|
||||||
[m4_if([$5], [], [],
|
|
||||||
[lt_join(m4_quote(m4_default([$4], [[, ]])),
|
|
||||||
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
|
|
||||||
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
|
|
||||||
])
|
|
||||||
Vendored
-24
@@ -1,24 +0,0 @@
|
|||||||
# ltversion.m4 -- version numbers -*- Autoconf -*-
|
|
||||||
#
|
|
||||||
# Copyright (C) 2004, 2011-2019, 2021-2022 Free Software Foundation,
|
|
||||||
# Inc.
|
|
||||||
# Written by Scott James Remnant, 2004
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation gives
|
|
||||||
# unlimited permission to copy and/or distribute it, with or without
|
|
||||||
# modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# @configure_input@
|
|
||||||
|
|
||||||
# serial 4245 ltversion.m4
|
|
||||||
# This file is part of GNU Libtool
|
|
||||||
|
|
||||||
m4_define([LT_PACKAGE_VERSION], [2.4.7])
|
|
||||||
m4_define([LT_PACKAGE_REVISION], [2.4.7])
|
|
||||||
|
|
||||||
AC_DEFUN([LTVERSION_VERSION],
|
|
||||||
[macro_version='2.4.7'
|
|
||||||
macro_revision='2.4.7'
|
|
||||||
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
|
|
||||||
_LT_DECL(, macro_revision, 0)
|
|
||||||
])
|
|
||||||
Vendored
-99
@@ -1,99 +0,0 @@
|
|||||||
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
|
|
||||||
#
|
|
||||||
# Copyright (C) 2004-2005, 2007, 2009, 2011-2019, 2021-2022 Free
|
|
||||||
# Software Foundation, Inc.
|
|
||||||
# Written by Scott James Remnant, 2004.
|
|
||||||
#
|
|
||||||
# This file is free software; the Free Software Foundation gives
|
|
||||||
# unlimited permission to copy and/or distribute it, with or without
|
|
||||||
# modifications, as long as this notice is preserved.
|
|
||||||
|
|
||||||
# serial 5 lt~obsolete.m4
|
|
||||||
|
|
||||||
# These exist entirely to fool aclocal when bootstrapping libtool.
|
|
||||||
#
|
|
||||||
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
|
|
||||||
# which have later been changed to m4_define as they aren't part of the
|
|
||||||
# exported API, or moved to Autoconf or Automake where they belong.
|
|
||||||
#
|
|
||||||
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
|
|
||||||
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
|
|
||||||
# using a macro with the same name in our local m4/libtool.m4 it'll
|
|
||||||
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
|
|
||||||
# and doesn't know about Autoconf macros at all.)
|
|
||||||
#
|
|
||||||
# So we provide this file, which has a silly filename so it's always
|
|
||||||
# included after everything else. This provides aclocal with the
|
|
||||||
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
|
|
||||||
# because those macros already exist, or will be overwritten later.
|
|
||||||
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
|
|
||||||
#
|
|
||||||
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
|
|
||||||
# Yes, that means every name once taken will need to remain here until
|
|
||||||
# we give up compatibility with versions before 1.7, at which point
|
|
||||||
# we need to keep only those names which we still refer to.
|
|
||||||
|
|
||||||
# This is to help aclocal find these macros, as it can't see m4_define.
|
|
||||||
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
|
|
||||||
|
|
||||||
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
|
|
||||||
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
|
|
||||||
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
|
|
||||||
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
|
|
||||||
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
|
|
||||||
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
|
|
||||||
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
|
|
||||||
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
|
|
||||||
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
|
|
||||||
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
|
|
||||||
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
|
|
||||||
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
|
|
||||||
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
|
|
||||||
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
|
|
||||||
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
|
|
||||||
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
|
|
||||||
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
|
|
||||||
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
|
|
||||||
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
|
|
||||||
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
|
|
||||||
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
|
|
||||||
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
|
|
||||||
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
|
|
||||||
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
|
|
||||||
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
|
|
||||||
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
|
|
||||||
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
|
|
||||||
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
|
|
||||||
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
|
|
||||||
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
|
|
||||||
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
|
|
||||||
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
|
|
||||||
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
|
|
||||||
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
|
|
||||||
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
SENSEAPIS_ENABLED=
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([senseapi-xcbxorg],
|
|
||||||
[AS_HELP_STRING([--enable-senseapi-xcbxorg],
|
|
||||||
[Enable XCB/Xorg SenseAPI backend])],
|
|
||||||
[AS_CASE([$enableval],
|
|
||||||
[no], [enable_senseapi_xcbxorg=no],
|
|
||||||
[yes|""|*], [
|
|
||||||
enable_senseapi_xcbxorg=yes
|
|
||||||
AC_DEFINE([XCBXORG_ENABLED], [1],
|
|
||||||
[Define to 1 if you have XCB/Xorg SenseAPI backend])
|
|
||||||
SENSEAPIS_ENABLED="${SENSEAPIS_ENABLED} xcbXorg"
|
|
||||||
PKG_CHECK_MODULES([XCB], [xcb], [], [
|
|
||||||
AC_MSG_ERROR(m4_normalize([XCB library not found. Sense API
|
|
||||||
XCB/Xorg requires the XCB dev headers and shlib.]))
|
|
||||||
])
|
|
||||||
AC_SUBST([XCB_CFLAGS])
|
|
||||||
AC_SUBST([XCB_LIBS])
|
|
||||||
]
|
|
||||||
)],
|
|
||||||
[enable_senseapi_xcbxorg=no]
|
|
||||||
)
|
|
||||||
@@ -1,108 +1,27 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <exception>
|
#include <componentThread.h>
|
||||||
#include <thread>
|
#include <marionette/marionette.h>
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include <opts.h>
|
|
||||||
#include <mind.h>
|
|
||||||
#include <deviceManager/deviceManager.h>
|
|
||||||
#include <senseApis/senseApiManager.h>
|
|
||||||
#include "componentThread.h"
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
static int initializeHarikoff(int argc, char **argv, char **envp);
|
int main(int argc, char *argv[], char *envp[])
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp)
|
|
||||||
{
|
{
|
||||||
try {
|
/* We don't do anything inside of main()
|
||||||
std::cout << __func__ << ": Entering main()" << std::endl;
|
* Main merely waits for the marionette thread to exit.
|
||||||
boost::asio::io_service mrntLoop;
|
*/
|
||||||
boost::asio::io_service::work work(mrntLoop);
|
std::cout << "CRT:" << __func__ << ": about to JOLT Mrntt with cmdline args"
|
||||||
|
<< '\n';
|
||||||
// Validate thread IDs
|
smo::mrntt::mrntt->getIoService().post(
|
||||||
hk::ComponentThread::validateThreadIds();
|
[argc, argv, envp]()
|
||||||
|
|
||||||
// Post initializeHarikoff to mrntLoop
|
|
||||||
mrntLoop.post([&]()
|
|
||||||
{
|
{
|
||||||
int ret = hk::initializeHarikoff(argc, argv, envp);
|
std::cout << "Mrntt:" << __func__ << ":JOLTED: setting cmdline args"
|
||||||
if (ret != 0)
|
<< '\n';
|
||||||
{
|
smo::CrtCommandLineArgs::set(argc, argv, envp);
|
||||||
std::cerr << "Initialization failed with code: "
|
smo::mrntt::mrntt->getIoService().stop();
|
||||||
<< ret << std::endl;
|
|
||||||
std::exit(ret);
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
mrntLoop.run();
|
smo::mrntt::mrntt->thread.join();
|
||||||
|
std::cout << "CRT:" << __func__ << ": Mrntt exited with code '"
|
||||||
|
<< smo::mrntt::exitCode << "'\n";
|
||||||
|
return smo::mrntt::exitCode;
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << __func__ << ": Exception occurred: " << e.what()
|
|
||||||
<< std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
std::cerr << __func__ << ": Unknown exception occurred" << std::endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << __func__ << ": Exiting normally" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace hk {
|
|
||||||
|
|
||||||
static int initializeHarikoff(int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
std::cout << __func__ << ": Entering" << std::endl;
|
|
||||||
|
|
||||||
using namespace hk;
|
|
||||||
OptionParser &options = OptionParser::getOptions();
|
|
||||||
hk::Mind mind;
|
|
||||||
|
|
||||||
std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << std::endl;
|
|
||||||
|
|
||||||
try {
|
|
||||||
options.parseArguments(argc, argv, envp);
|
|
||||||
std::cout << options.stringifyOptions() << std::endl;
|
|
||||||
}
|
|
||||||
catch (const std::invalid_argument& e)
|
|
||||||
{
|
|
||||||
std::cerr << __func__ << ": Exception occurred: " << e.what() << '\n'
|
|
||||||
<< options.getUsage() << '\n';
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.printUsage)
|
|
||||||
{
|
|
||||||
std::cout << options.getUsage() << std::endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
device::DeviceManager::getInstance().collateAllDeviceSpecs();
|
|
||||||
device::DeviceManager::getInstance().parseAllDeviceSpecs();
|
|
||||||
std::cout << device::DeviceManager::stringifyDeviceSpecs() << std::endl;
|
|
||||||
sense_api::SenseApiManager::getInstance().loadAllSenseApiLibsFromOptions();
|
|
||||||
std::cout << sense_api::SenseApiManager::getInstance().stringifyLibs()
|
|
||||||
<< std::endl;
|
|
||||||
sense_api::SenseApiManager::getInstance().initializeAllSenseApiLibs();
|
|
||||||
sense_api::SenseApiManager::getInstance().attachAllSenseDevicesFromSpecs();
|
|
||||||
|
|
||||||
/* Start the threads */
|
|
||||||
for (const auto& [id, componentThread]
|
|
||||||
: hk::ComponentThread::componentThreads) {
|
|
||||||
hk::ComponentThread::signalThread(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << __func__ << ": Exiting" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace hk
|
|
||||||
|
|||||||
Executable
+54
@@ -0,0 +1,54 @@
|
|||||||
|
#! /usr/bin/bash
|
||||||
|
|
||||||
|
winNameToFind=${1}
|
||||||
|
|
||||||
|
printUsage()
|
||||||
|
{
|
||||||
|
echo "${0}: <STRING:windowNameToFind>"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${winNameToFind}x" = "x" ]; then
|
||||||
|
printUsage
|
||||||
|
fi
|
||||||
|
|
||||||
|
extractAllChildIdsFrom()
|
||||||
|
{
|
||||||
|
echo $(echo "${1}" \
|
||||||
|
| grep '^[[:space:]]*0x[0-9a-zA-Z]' \
|
||||||
|
| awk '{print $1}')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
searchOneParentByName()
|
||||||
|
{
|
||||||
|
local thisWinId=$1
|
||||||
|
local winNameToFind=$2
|
||||||
|
|
||||||
|
local thisWininfoStdout=$(xwininfo -id "${thisWinId}")
|
||||||
|
local thisWinName=$(echo "${thisWininfoStdout}" \
|
||||||
|
| grep '[Ww]indow[[:space:]]*[iI][dD]' \
|
||||||
|
| grep -oP '[0-9a-zA-Z]*[[:space:]]*\".*\"$' \
|
||||||
|
| sed 's/[0-9a-zA-Z]*[[:space:]]*//')
|
||||||
|
echo "Searching win [ID=${thisWinId}, name=\"${thisWinName}\"] and its children..."
|
||||||
|
if echo "${thisWinName}" | grep -q "${winNameToFind}"; then
|
||||||
|
echo "${thisWininfoStdout}"
|
||||||
|
# return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local allChildrenUnparsedOutput=$(xwininfo -id "${thisWinId}" -children)
|
||||||
|
for i in $(extractAllChildIdsFrom "${allChildrenUnparsedOutput}");
|
||||||
|
do
|
||||||
|
searchOneParentByName "${i}" "${winNameToFind}"
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rootChildWindowOutput=$(xwininfo -root -children)
|
||||||
|
for i in $(extractAllChildIdsFrom "${rootChildWindowOutput}");
|
||||||
|
do
|
||||||
|
searchOneParentByName "${i}" "${winNameToFind}"
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 1
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
add_subdirectory(xcbWindow)
|
||||||
@@ -1 +0,0 @@
|
|||||||
SUBDIRS = @SENSEAPIS_ENABLED@
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# XCB/Xorg Window Attaching SenseAPI backend
|
||||||
|
cmake_dependent_option(ENABLE_SENSEAPI_xcbWindow
|
||||||
|
"Enable XCB/Xorg Window Attaching SenseAPI backend" ON
|
||||||
|
"ENABLE_LIB_xcbXorg" ON)
|
||||||
|
|
||||||
|
if(ENABLE_SENSEAPI_xcbWindow)
|
||||||
|
add_library(xcbWindow SHARED
|
||||||
|
xcbWindow.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(xcbWindow PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../smocore/include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../../commonLibs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link against XCB library directly (libxcbXorg will be loaded dynamically)
|
||||||
|
pkg_check_modules(XCB REQUIRED xcb)
|
||||||
|
target_link_libraries(xcbWindow ${XCB_LIBRARIES})
|
||||||
|
|
||||||
|
# Set config define for header generation
|
||||||
|
add_compile_definitions(CONFIG_SENSEAPI_XCBWINDOW_ENABLED)
|
||||||
|
|
||||||
|
# Install rules
|
||||||
|
install(TARGETS xcbWindow DESTINATION lib)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,355 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#include <user/senseApiDesc.h>
|
||||||
|
#include <user/deviceAttachmentSpec.h>
|
||||||
|
#include <xcbXorg/xcbXorg.h>
|
||||||
|
#include "xcbWindow.h"
|
||||||
|
|
||||||
|
// Function pointers to API entry points exported by libxcbXorg.
|
||||||
|
struct XcbXorgDllState
|
||||||
|
{
|
||||||
|
struct XcbXorgFunctions
|
||||||
|
{
|
||||||
|
get_or_create_connection_fn* getOrCreateConnection = nullptr;
|
||||||
|
cleanup_connections_fn* cleanupConnections = nullptr;
|
||||||
|
dereference_connection_fn* dereferenceConnection = nullptr;
|
||||||
|
find_window_by_id_fn* findWindowById = nullptr;
|
||||||
|
find_window_by_name_fn* findWindowByName = nullptr;
|
||||||
|
} fns;
|
||||||
|
void* dlopenHandle = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static XcbXorgDllState xcbXorg;
|
||||||
|
|
||||||
|
// Salmanoff hooks, obtained from SMO_GET_SENSE_API_DESC_FN_NAME().
|
||||||
|
static const smo::sense_api::SalmanoffCallbacks* smoHooksPtr = nullptr;
|
||||||
|
|
||||||
|
// Attached windows.
|
||||||
|
static std::vector<std::unique_ptr<xcb_window::AttachedWindow>>
|
||||||
|
g_attachedWindows;
|
||||||
|
|
||||||
|
namespace xcb_window {
|
||||||
|
|
||||||
|
std::string WindowSelector::stringify() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
|
||||||
|
os << "Display: " << display
|
||||||
|
<< ", Screen: " << screen << ", Window: ";
|
||||||
|
if (matchType == xcb_xorg::window_search::MatchType::ID) {
|
||||||
|
os << windowId;
|
||||||
|
} else {
|
||||||
|
os << "\"" << windowName << "\"";
|
||||||
|
}
|
||||||
|
os << " (matchType="
|
||||||
|
<< (matchType == xcb_xorg::window_search::MatchType::EXACT ? "exact" :
|
||||||
|
(matchType == xcb_xorg::window_search::MatchType::SUBSTRING) ? "substring" : "id")
|
||||||
|
<< ")";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedWindow::AttachedWindow(
|
||||||
|
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& spec
|
||||||
|
)
|
||||||
|
: deviceAttachmentSpec(spec)
|
||||||
|
{
|
||||||
|
// Validate required function pointers are available
|
||||||
|
if (!xcbXorg.fns.getOrCreateConnection ||
|
||||||
|
!xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName
|
||||||
|
|| !xcbXorg.fns.dereferenceConnection)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("xcbWindow:" + std::string(__func__) +
|
||||||
|
": Required xcbXorg function pointers not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
windowSelector.display = getRequiredParamAsInt(*spec, "display");
|
||||||
|
windowSelector.screen = getRequiredParamAsInt(*spec, "screen");
|
||||||
|
parseWindowSelector(*spec);
|
||||||
|
|
||||||
|
// Get connection from libxcbXorg
|
||||||
|
std::shared_ptr<xcb_xorg::XcbConnection> conn =
|
||||||
|
(*xcbXorg.fns.getOrCreateConnection)(
|
||||||
|
windowSelector.display, windowSelector.screen);
|
||||||
|
|
||||||
|
xcbConnectionShared = conn;
|
||||||
|
|
||||||
|
// Find the target window
|
||||||
|
xcb_window_t foundWindow = 0;
|
||||||
|
const xcb_setup_t* setup = xcb_get_setup(conn->getConnection());
|
||||||
|
const xcb_screen_t* screen = xcb_setup_roots_iterator(setup).data;
|
||||||
|
|
||||||
|
if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID)
|
||||||
|
{
|
||||||
|
foundWindow = (*xcbXorg.fns.findWindowById)(
|
||||||
|
conn.get(), screen->root,
|
||||||
|
windowSelector.windowId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foundWindow = (*xcbXorg.fns.findWindowByName)(
|
||||||
|
conn.get(), screen->root,
|
||||||
|
windowSelector.windowName, actualWindowName,
|
||||||
|
windowSelector.matchType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundWindow)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("xcbWindow:" + std::string(__func__) +
|
||||||
|
": Window not found: " + windowSelector.stringify());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachedWindow::parseWindowSelector(
|
||||||
|
const smo::device::DeviceAttachmentSpec& spec
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Default match type
|
||||||
|
windowSelector.matchType = xcb_xorg::window_search::MatchType::SUBSTRING;
|
||||||
|
|
||||||
|
// Check if 'dev-id', 'dev-string', or 'dev-substring' is specified
|
||||||
|
for (const auto& param : spec.apiParams)
|
||||||
|
{
|
||||||
|
if (param.first == "dev-id" || param.first == "devid")
|
||||||
|
{
|
||||||
|
windowSelector.matchType = xcb_xorg::window_search::MatchType::ID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (param.first == "dev-string" || param.first == "dev-str"
|
||||||
|
|| param.first == "devstr" || param.first == "devstring")
|
||||||
|
{
|
||||||
|
windowSelector.matchType = xcb_xorg::window_search::MatchType::EXACT;
|
||||||
|
}
|
||||||
|
if (param.first == "dev-substring" || param.first == "dev-substr"
|
||||||
|
|| param.first == "devsubstr" || param.first == "devsubstring")
|
||||||
|
{
|
||||||
|
windowSelector.matchType = xcb_xorg::window_search::MatchType::SUBSTRING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
windowSelector.windowId = std::stoul(
|
||||||
|
spec.deviceSelector, nullptr, 0);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"xcbWindow:" + std::string(__func__) + ": Window selector: "
|
||||||
|
"'dev-id' present, but selector is not numeric");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
windowSelector.windowName = spec.deviceSelector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int AttachedWindow::getRequiredParamAsInt(const smo::device::DeviceAttachmentSpec& spec,
|
||||||
|
const std::string& paramName)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(
|
||||||
|
spec.providerParams.begin(),
|
||||||
|
spec.providerParams.end(),
|
||||||
|
[¶mName](const auto& param) {
|
||||||
|
return param.first == paramName;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (it == spec.providerParams.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"No " + paramName + " specified in provider params");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return std::stoi(it->second);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Failed to parse '" + paramName + "' param value '"
|
||||||
|
+ it->second + "' as integer: " + e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AttachedWindow::stringify() const {
|
||||||
|
std::ostringstream os;
|
||||||
|
|
||||||
|
auto matchTypeStr = [](xcb_xorg::window_search::MatchType mt) -> const char* {
|
||||||
|
switch (mt) {
|
||||||
|
case xcb_xorg::window_search::MatchType::SUBSTRING:
|
||||||
|
return "substring";
|
||||||
|
case xcb_xorg::window_search::MatchType::EXACT:
|
||||||
|
return "exact";
|
||||||
|
case xcb_xorg::window_search::MatchType::ID:
|
||||||
|
return "id";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto formatWindowId = [](uint32_t id) -> std::string {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "Window ID 0x" << std::hex << id << std::dec;
|
||||||
|
return oss.str();
|
||||||
|
};
|
||||||
|
|
||||||
|
os << "Display: " << windowSelector.display
|
||||||
|
<< ", Screen: " << windowSelector.screen
|
||||||
|
<< ", MatchType: " << matchTypeStr(windowSelector.matchType)
|
||||||
|
<< ", Target: ";
|
||||||
|
|
||||||
|
if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID) {
|
||||||
|
os << formatWindowId(windowSelector.windowId);
|
||||||
|
} else {
|
||||||
|
os << '"' << windowSelector.windowName << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ", Found: ";
|
||||||
|
|
||||||
|
if (windowSelector.matchType == xcb_xorg::window_search::MatchType::ID) {
|
||||||
|
os << formatWindowId(windowSelector.windowId);
|
||||||
|
} else {
|
||||||
|
os << '"' << actualWindowName << '"';
|
||||||
|
if (windowSelector.matchType ==
|
||||||
|
xcb_xorg::window_search::MatchType::SUBSTRING &&
|
||||||
|
actualWindowName != windowSelector.windowName)
|
||||||
|
{
|
||||||
|
os << " (matched substring '"
|
||||||
|
<< windowSelector.windowName << "')";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachedWindow::~AttachedWindow()
|
||||||
|
{
|
||||||
|
if (xcbConnectionShared && xcbXorg.fns.dereferenceConnection) {
|
||||||
|
(*xcbXorg.fns.dereferenceConnection)(xcbConnectionShared);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xcb_window
|
||||||
|
|
||||||
|
// SenseApi functions
|
||||||
|
static int xcbWindow_initializeInd(void)
|
||||||
|
{
|
||||||
|
if (!smoHooksPtr)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__) + ": SMO hooks "
|
||||||
|
"pointers not filled in.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load libxcbXorg using the search path hook
|
||||||
|
auto libPath = smoHooksPtr->searchForLibInSmoSearchPaths("libxcbXorg.so");
|
||||||
|
xcbXorg.dlopenHandle = dlopen(
|
||||||
|
libPath.value_or("libxcbXorg.so").c_str(),
|
||||||
|
RTLD_LAZY);
|
||||||
|
|
||||||
|
if (!xcbXorg.dlopenHandle)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("xcbWindow:" + std::string(__func__) +
|
||||||
|
": Failed to load libxcbXorg: " + std::string(dlerror()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in function pointers from libxcbXorg.
|
||||||
|
xcbXorg.fns.getOrCreateConnection =
|
||||||
|
reinterpret_cast<get_or_create_connection_fn*>(
|
||||||
|
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_get_or_create_connection"));
|
||||||
|
xcbXorg.fns.cleanupConnections = reinterpret_cast<cleanup_connections_fn*>(
|
||||||
|
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_cleanup_connections"));
|
||||||
|
xcbXorg.fns.findWindowById = reinterpret_cast<find_window_by_id_fn*>(
|
||||||
|
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_id"));
|
||||||
|
xcbXorg.fns.findWindowByName = reinterpret_cast<find_window_by_name_fn*>(
|
||||||
|
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_find_window_by_name"));
|
||||||
|
xcbXorg.fns.dereferenceConnection =
|
||||||
|
reinterpret_cast<dereference_connection_fn*>(
|
||||||
|
dlsym(xcbXorg.dlopenHandle, "xcb_xorg_dereference_connection"));
|
||||||
|
|
||||||
|
if (!xcbXorg.fns.getOrCreateConnection || !xcbXorg.fns.cleanupConnections
|
||||||
|
|| !xcbXorg.fns.findWindowById || !xcbXorg.fns.findWindowByName
|
||||||
|
|| !xcbXorg.fns.dereferenceConnection)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("xcbWindow:") + __func__ +
|
||||||
|
": Failed to get required function pointers from libxcbXorg");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xcbWindow_finalizeInd(void)
|
||||||
|
{
|
||||||
|
g_attachedWindows.clear();
|
||||||
|
|
||||||
|
if (xcbXorg.dlopenHandle)
|
||||||
|
{
|
||||||
|
dlclose(xcbXorg.dlopenHandle);
|
||||||
|
xcbXorg.dlopenHandle = nullptr;
|
||||||
|
xcbXorg.fns = { nullptr, nullptr, nullptr, nullptr, nullptr };
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xcbWindow_attachDeviceReq(
|
||||||
|
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& desc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
g_attachedWindows.emplace_back(
|
||||||
|
std::make_unique<xcb_window::AttachedWindow>(desc));
|
||||||
|
|
||||||
|
std::cout << __func__ << ": Attached X11 window:\n "
|
||||||
|
<< g_attachedWindows.back()->stringify()
|
||||||
|
<< "\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int xcbWindow_detachDeviceReq(
|
||||||
|
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& spec
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(g_attachedWindows.begin(), g_attachedWindows.end(),
|
||||||
|
[&spec](const std::unique_ptr<xcb_window::AttachedWindow>& window) {
|
||||||
|
return window->getDeviceAttachmentSpec() == spec;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (it == g_attachedWindows.end())
|
||||||
|
{
|
||||||
|
std::cerr << __func__ << ": Device not found for detachment:\n"
|
||||||
|
<< spec->stringify() << "\n";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_attachedWindows.erase(it);
|
||||||
|
std::cout << __func__ << ": Detached X11 window device:\n"
|
||||||
|
<< spec->stringify() << "\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SenseApi descriptor
|
||||||
|
static smo::sense_api::SenseApiDesc xcbWindowApiDesc = {
|
||||||
|
.name = "xcb",
|
||||||
|
.exportedImplexorApis = { { "video-implexor" } },
|
||||||
|
.sal_mgmt_libOps = {
|
||||||
|
.initializeInd = xcbWindow_initializeInd,
|
||||||
|
.finalizeInd = xcbWindow_finalizeInd,
|
||||||
|
.attachDeviceReq = xcbWindow_attachDeviceReq,
|
||||||
|
.detachDeviceReq = xcbWindow_detachDeviceReq
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exported function
|
||||||
|
extern "C" smo::sense_api::SMO_GET_SENSE_API_DESC_FN_TYPEDEF
|
||||||
|
SMO_GET_SENSE_API_DESC_FN_NAME;
|
||||||
|
|
||||||
|
const smo::sense_api::SenseApiDesc& SMO_GET_SENSE_API_DESC_FN_NAME(
|
||||||
|
const smo::sense_api::SalmanoffCallbacks& callbacks)
|
||||||
|
{
|
||||||
|
smoHooksPtr = &callbacks;
|
||||||
|
return xcbWindowApiDesc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef XCB_WINDOW_SENSE_API_H
|
||||||
|
#define XCB_WINDOW_SENSE_API_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <user/senseApiDesc.h>
|
||||||
|
#include <user/deviceAttachmentSpec.h>
|
||||||
|
#include <xcbXorg/xcbXorg.h>
|
||||||
|
|
||||||
|
namespace xcb_window {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Window selector for X11 windows
|
||||||
|
*/
|
||||||
|
struct WindowSelector
|
||||||
|
{
|
||||||
|
xcb_xorg::window_search::MatchType matchType;
|
||||||
|
int display;
|
||||||
|
int screen;
|
||||||
|
uint32_t windowId;
|
||||||
|
std::string windowName;
|
||||||
|
|
||||||
|
std::string stringify() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represents an attached X11 window device
|
||||||
|
*/
|
||||||
|
class AttachedWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AttachedWindow(
|
||||||
|
const std::shared_ptr<smo::device::DeviceAttachmentSpec>& spec);
|
||||||
|
~AttachedWindow();
|
||||||
|
|
||||||
|
const std::shared_ptr<smo::device::DeviceAttachmentSpec>&
|
||||||
|
getDeviceAttachmentSpec() const
|
||||||
|
{ return deviceAttachmentSpec; }
|
||||||
|
const WindowSelector& getWindowSelector() const { return windowSelector; }
|
||||||
|
const std::string& getActualWindowName() const { return actualWindowName; }
|
||||||
|
void* getXcbConnection() const { return xcbConnectionShared.get(); }
|
||||||
|
std::string stringify() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void parseWindowSelector(const smo::device::DeviceAttachmentSpec& spec);
|
||||||
|
int getRequiredParamAsInt(
|
||||||
|
const smo::device::DeviceAttachmentSpec& spec,
|
||||||
|
const std::string& paramName);
|
||||||
|
|
||||||
|
std::shared_ptr<smo::device::DeviceAttachmentSpec> deviceAttachmentSpec;
|
||||||
|
WindowSelector windowSelector;
|
||||||
|
std::string actualWindowName;
|
||||||
|
std::shared_ptr<xcb_xorg::XcbConnection> xcbConnectionShared;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xcb_window
|
||||||
|
|
||||||
|
#endif // XCB_WINDOW_SENSE_API_H
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
pkglib_LTLIBRARIES=libxcbXorg.la
|
|
||||||
libxcbXorg_la_SOURCES=xcbXorg.cpp
|
|
||||||
libxcbXorg_la_LDFLAGS=$(XCB_LIBS)
|
|
||||||
|
|
||||||
xcbXorg.$(OBJEXT): CPPFLAGS+=$(XCB_CFLAGS) -Wno-c++20-extensions
|
|
||||||
xcbXorg.l$(OBJEXT): CPPFLAGS+=$(XCB_CFLAGS) -Wno-c++20-extensions
|
|
||||||
@@ -1,527 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
#include <map>
|
|
||||||
#include <atomic>
|
|
||||||
#include <user/senseDeviceSpec.h>
|
|
||||||
#include <user/senseApiDesc.h>
|
|
||||||
#include <xcb/xcb.h>
|
|
||||||
#include "xcbXorg.h"
|
|
||||||
|
|
||||||
// Key for identifying unique X server connections
|
|
||||||
struct XcbConnection
|
|
||||||
{
|
|
||||||
struct XConnectionIdentifier
|
|
||||||
{
|
|
||||||
int display;
|
|
||||||
int screen;
|
|
||||||
|
|
||||||
bool operator<(const XConnectionIdentifier& other) const
|
|
||||||
{
|
|
||||||
if (display != other.display) return display < other.display;
|
|
||||||
return screen < other.screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string stringify() const
|
|
||||||
{
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "display=" << display << ", screen=" << screen;
|
|
||||||
return os.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief RAII guard for managing X server connection lifetime
|
|
||||||
*
|
|
||||||
* This guard ensures proper cleanup of X server connections in case of
|
|
||||||
* errors during attachDeviceReq. If a connection is created but the device
|
|
||||||
* attachment fails, and the connection's refcount is 0, this guard will
|
|
||||||
* automatically remove the connection from the connections map.
|
|
||||||
*
|
|
||||||
* The guard can be "committed" using commit() to indicate successful
|
|
||||||
* device attachment, in which case it will not perform cleanup on destruction.
|
|
||||||
*/
|
|
||||||
class ConnectionGuard
|
|
||||||
{
|
|
||||||
std::shared_ptr<XcbConnection> conn;
|
|
||||||
bool committed = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ConnectionGuard(std::shared_ptr<XcbConnection> c)
|
|
||||||
: conn(std::move(c))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void commit(void) { committed = true; }
|
|
||||||
|
|
||||||
~ConnectionGuard()
|
|
||||||
{
|
|
||||||
if (!committed && conn && conn->refCount == 0) {
|
|
||||||
XcbConnection::connections.erase(conn->connectionIdentifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
XcbConnection(const XConnectionIdentifier& id)
|
|
||||||
: connection(nullptr, &xcb_disconnect),
|
|
||||||
connectionIdentifier(id), refCount(0)
|
|
||||||
{
|
|
||||||
// Convert to X display string format (e.g., ":0.1")
|
|
||||||
std::string displayString = ":" + std::to_string(id.display)
|
|
||||||
+ "." + std::to_string(id.screen);
|
|
||||||
|
|
||||||
int screenNum;
|
|
||||||
connection.reset(xcb_connect(displayString.c_str(), &screenNum));
|
|
||||||
if (xcb_connection_has_error(connection.get()))
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Failed to connect to X server "
|
|
||||||
+ connectionIdentifier.stringify());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify we got the screen we asked for
|
|
||||||
if (screenNum != id.screen)
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(__func__) + ": Connected to wrong screen. "
|
|
||||||
"Requested " + connectionIdentifier.stringify()
|
|
||||||
+ " but got screen " + std::to_string(screenNum));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete copy/move operations - we'll manage instances through pointers
|
|
||||||
XcbConnection(const XcbConnection&) = delete;
|
|
||||||
XcbConnection& operator=(const XcbConnection&) = delete;
|
|
||||||
XcbConnection(XcbConnection&&) = delete;
|
|
||||||
XcbConnection& operator=(XcbConnection&&) = delete;
|
|
||||||
|
|
||||||
std::unique_ptr<xcb_connection_t, decltype(&xcb_disconnect)> connection;
|
|
||||||
XConnectionIdentifier connectionIdentifier;
|
|
||||||
std::atomic<int> refCount;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static std::map<XConnectionIdentifier, std::shared_ptr<XcbConnection>>
|
|
||||||
connections;
|
|
||||||
|
|
||||||
static std::shared_ptr<XcbConnection> getOrCreateConnection(
|
|
||||||
const XConnectionIdentifier& id)
|
|
||||||
{
|
|
||||||
auto it = connections.find(id);
|
|
||||||
if (it != connections.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto conn = std::make_shared<XcbConnection>(id);
|
|
||||||
connections.emplace(id, conn);
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace xcb_window_search {
|
|
||||||
|
|
||||||
// Custom deleters for XCB reply types
|
|
||||||
struct XcbReplyDeleter {
|
|
||||||
void operator()(xcb_query_tree_reply_t* p) { free(p); }
|
|
||||||
void operator()(xcb_get_property_reply_t* p) { free(p); }
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MatchType { SUBSTRING, EXACT, ID };
|
|
||||||
|
|
||||||
static xcb_window_t findById(
|
|
||||||
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId);
|
|
||||||
|
|
||||||
static xcb_window_t findByName(
|
|
||||||
xcb_connection_t* conn, xcb_window_t root,
|
|
||||||
const std::string& targetName, std::string& outWindowName,
|
|
||||||
MatchType matchType);
|
|
||||||
}
|
|
||||||
|
|
||||||
class AttachedDevice
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct WindowSelector
|
|
||||||
{
|
|
||||||
xcb_window_search::MatchType matchType;
|
|
||||||
|
|
||||||
XcbConnection::XConnectionIdentifier xconn;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32_t id;
|
|
||||||
std::string name;
|
|
||||||
} window;
|
|
||||||
|
|
||||||
std::string stringify() const
|
|
||||||
{
|
|
||||||
std::ostringstream os;
|
|
||||||
os << "Display: " << xconn.display
|
|
||||||
<< ", Screen: " << xconn.screen << ", Window: ";
|
|
||||||
if (matchType == xcb_window_search::MatchType::ID) {
|
|
||||||
os << window.id;
|
|
||||||
} else {
|
|
||||||
os << "\"" << window.name << "\"";
|
|
||||||
}
|
|
||||||
os << " (matchType="
|
|
||||||
<< (matchType == xcb_window_search::MatchType::EXACT
|
|
||||||
? "exact" :
|
|
||||||
(matchType == xcb_window_search::MatchType::SUBSTRING)
|
|
||||||
? "substring" : "id")
|
|
||||||
<< ")";
|
|
||||||
return os.str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AttachedDevice(const hk::device::SenseDeviceSpec &spec,
|
|
||||||
std::shared_ptr<XcbConnection> conn)
|
|
||||||
: deviceSpec(spec)
|
|
||||||
// This std::move is moving ownership from a shared_ptr to a shared_ptr
|
|
||||||
, connection(std::move(conn))
|
|
||||||
{
|
|
||||||
windowSelector.xconn.display = getRequiredParamAsInt(spec, "display");
|
|
||||||
windowSelector.xconn.screen = getRequiredParamAsInt(spec, "screen");
|
|
||||||
parseWindowSelector(spec, windowSelector);
|
|
||||||
|
|
||||||
// Get the root window
|
|
||||||
const xcb_setup_t* setup = xcb_get_setup(connection->connection.get());
|
|
||||||
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
|
|
||||||
for (int i = 0; i < windowSelector.xconn.screen; ++i) {
|
|
||||||
xcb_screen_next(&iter);
|
|
||||||
}
|
|
||||||
xcb_window_t root = iter.data->root;
|
|
||||||
|
|
||||||
// Search for window
|
|
||||||
xcb_window_t targetWindow = 0;
|
|
||||||
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
|
|
||||||
{
|
|
||||||
targetWindow = xcb_window_search::findById(
|
|
||||||
connection->connection.get(), root, windowSelector.window.id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetWindow = xcb_window_search::findByName(
|
|
||||||
connection->connection.get(), root,
|
|
||||||
windowSelector.window.name, actualWindowName,
|
|
||||||
windowSelector.matchType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetWindow)
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Failed to find window "
|
|
||||||
+ (windowSelector.matchType == xcb_window_search::MatchType::ID
|
|
||||||
? std::to_string(windowSelector.window.id)
|
|
||||||
: "\"" + windowSelector.window.name + "\"")
|
|
||||||
+ " on display " + std::to_string(windowSelector.xconn.display)
|
|
||||||
+ ", screen " + std::to_string(windowSelector.xconn.screen));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hk::device::SenseDeviceSpec deviceSpec;
|
|
||||||
WindowSelector windowSelector;
|
|
||||||
std::shared_ptr<XcbConnection> connection;
|
|
||||||
std::string actualWindowName;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static int getRequiredParamAsInt(
|
|
||||||
const hk::device::SenseDeviceSpec& spec,
|
|
||||||
const std::string& paramName)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(
|
|
||||||
spec.providerParams.begin(),
|
|
||||||
spec.providerParams.end(),
|
|
||||||
[¶mName](const auto& param) {
|
|
||||||
return param.first == paramName;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (it == spec.providerParams.end())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"No " + paramName + " specified in provider params");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return std::stoi(it->second);
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Failed to parse '" + paramName + "' param value '"
|
|
||||||
+ it->second + "' as integer: " + e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parseWindowSelector(
|
|
||||||
const hk::device::SenseDeviceSpec& spec,
|
|
||||||
WindowSelector& windowSelector)
|
|
||||||
{
|
|
||||||
// Default match type
|
|
||||||
windowSelector.matchType = xcb_window_search::MatchType::SUBSTRING;
|
|
||||||
|
|
||||||
// Check if 'dev-id', 'dev-string', or 'dev-substring' is specified
|
|
||||||
for (const auto& param : spec.apiParams)
|
|
||||||
{
|
|
||||||
if (param.first == "dev-id" || param.first == "devid")
|
|
||||||
{
|
|
||||||
windowSelector.matchType = xcb_window_search::MatchType::ID;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (param.first == "dev-string" || param.first == "dev-str"
|
|
||||||
|| param.first == "devstr" || param.first == "devstring")
|
|
||||||
{
|
|
||||||
windowSelector.matchType = xcb_window_search::MatchType::EXACT;
|
|
||||||
}
|
|
||||||
if (param.first == "dev-substring" || param.first == "dev-substr"
|
|
||||||
|| param.first == "devsubstr" || param.first == "devsubstring")
|
|
||||||
{
|
|
||||||
windowSelector.matchType = xcb_window_search::
|
|
||||||
MatchType::SUBSTRING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windowSelector.matchType == xcb_window_search::MatchType::ID)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
windowSelector.window.id = std::stoul(
|
|
||||||
spec.deviceSelector, nullptr, 0);
|
|
||||||
} catch (const std::exception&) {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Window selector: 'dev-id' present, but selector is not "
|
|
||||||
"numeric");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
windowSelector.window.name = spec.deviceSelector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define the static member
|
|
||||||
std::map<XcbConnection::XConnectionIdentifier, std::shared_ptr<XcbConnection>>
|
|
||||||
XcbConnection::connections;
|
|
||||||
|
|
||||||
static std::vector<AttachedDevice> attachedDevices;
|
|
||||||
|
|
||||||
namespace xcb_window_search {
|
|
||||||
|
|
||||||
static xcb_window_t findById(
|
|
||||||
xcb_connection_t* conn, xcb_window_t root, uint32_t targetId)
|
|
||||||
{
|
|
||||||
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
|
|
||||||
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
|
|
||||||
xcb_query_tree_reply(conn, cookie, nullptr));
|
|
||||||
if (!reply) return 0;
|
|
||||||
|
|
||||||
// First check if current window is the target
|
|
||||||
if (root == targetId) {
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then check all children
|
|
||||||
xcb_window_t* children = xcb_query_tree_children(reply.get());
|
|
||||||
int num_children = xcb_query_tree_children_length(reply.get());
|
|
||||||
|
|
||||||
for (int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
if (children[i] == targetId) {
|
|
||||||
return children[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively search this child's subtree
|
|
||||||
if (xcb_window_t result = findById(
|
|
||||||
conn, children[i], targetId))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static xcb_window_t findByName(
|
|
||||||
xcb_connection_t* conn, xcb_window_t root,
|
|
||||||
const std::string& targetName, std::string& outWindowName,
|
|
||||||
MatchType matchType)
|
|
||||||
{
|
|
||||||
xcb_query_tree_cookie_t cookie = xcb_query_tree(conn, root);
|
|
||||||
std::unique_ptr<xcb_query_tree_reply_t, XcbReplyDeleter> reply(
|
|
||||||
xcb_query_tree_reply(conn, cookie, nullptr));
|
|
||||||
if (!reply) return 0;
|
|
||||||
|
|
||||||
// First check current window
|
|
||||||
xcb_get_property_cookie_t prop_cookie = xcb_get_property(
|
|
||||||
conn, 0, root, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
|
|
||||||
|
|
||||||
std::unique_ptr<xcb_get_property_reply_t, XcbReplyDeleter> prop_reply(
|
|
||||||
xcb_get_property_reply(conn, prop_cookie, nullptr));
|
|
||||||
|
|
||||||
if (prop_reply)
|
|
||||||
{
|
|
||||||
int len = xcb_get_property_value_length(prop_reply.get());
|
|
||||||
char* name = static_cast<char*>(
|
|
||||||
xcb_get_property_value(prop_reply.get()));
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
std::string windowName(name, len);
|
|
||||||
if ((matchType == MatchType::EXACT
|
|
||||||
&& windowName == targetName)
|
|
||||||
|| (matchType == MatchType::SUBSTRING
|
|
||||||
&& windowName.find(targetName) != std::string::npos))
|
|
||||||
{
|
|
||||||
outWindowName = windowName;
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then check all children
|
|
||||||
xcb_window_t* children = xcb_query_tree_children(reply.get());
|
|
||||||
int num_children = xcb_query_tree_children_length(reply.get());
|
|
||||||
|
|
||||||
for (int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
prop_cookie = xcb_get_property(
|
|
||||||
conn, 0, children[i],
|
|
||||||
XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 0, 1024);
|
|
||||||
|
|
||||||
prop_reply.reset(xcb_get_property_reply(conn, prop_cookie, nullptr));
|
|
||||||
if (prop_reply)
|
|
||||||
{
|
|
||||||
int len = xcb_get_property_value_length(prop_reply.get());
|
|
||||||
char* name = static_cast<char*>(xcb_get_property_value(
|
|
||||||
prop_reply.get()));
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
std::string windowName(name, len);
|
|
||||||
if ((matchType == MatchType::EXACT
|
|
||||||
&& windowName == targetName)
|
|
||||||
|| (matchType == MatchType::SUBSTRING
|
|
||||||
&& windowName.find(targetName) != std::string::npos))
|
|
||||||
{
|
|
||||||
outWindowName = windowName;
|
|
||||||
return children[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively search this child's subtree
|
|
||||||
if (xcb_window_t result = findByName(
|
|
||||||
conn, children[i], targetName, outWindowName, matchType))
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xcb_window_search
|
|
||||||
|
|
||||||
static hk::sense_api::sal_mlo_initializeIndFn xcbXorg_initializeInd;
|
|
||||||
static hk::sense_api::sal_mlo_finalizeIndFn xcbXorg_finalizeInd;
|
|
||||||
static hk::sense_api::sal_mlo_attachDeviceReqFn xcbXorg_attachDeviceReq;
|
|
||||||
static hk::sense_api::sal_mlo_detachDeviceReqFn xcbXorg_detachDeviceReq;
|
|
||||||
|
|
||||||
static hk::sense_api::SenseApiDesc xcbXorgApiDesc =
|
|
||||||
{
|
|
||||||
.name = "xcb",
|
|
||||||
.exportedImplexorApis = { { "video-implexor" } },
|
|
||||||
.sal_mgmt_libOps = {
|
|
||||||
.initializeInd = xcbXorg_initializeInd,
|
|
||||||
.finalizeInd = xcbXorg_finalizeInd,
|
|
||||||
.attachDeviceReq = xcbXorg_attachDeviceReq,
|
|
||||||
.detachDeviceReq = xcbXorg_detachDeviceReq
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern HK_UNMANGLED hk::sense_api::getSenseApiDescFn
|
|
||||||
HK_GET_SENSE_API_DESC_FN_NAME;
|
|
||||||
|
|
||||||
const hk::sense_api::SenseApiDesc &HK_GET_SENSE_API_DESC_FN_NAME(void)
|
|
||||||
{
|
|
||||||
return xcbXorgApiDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xcbXorg_initializeInd(void)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xcbXorg_finalizeInd(void)
|
|
||||||
{
|
|
||||||
XcbConnection::connections.clear();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xcbXorg_attachDeviceReq(const hk::device::SenseDeviceSpec &desc)
|
|
||||||
{
|
|
||||||
// Ensure connection exists before creating device. Create conn'tion if not.
|
|
||||||
XcbConnection::XConnectionIdentifier id{
|
|
||||||
AttachedDevice::getRequiredParamAsInt(desc, "display"),
|
|
||||||
AttachedDevice::getRequiredParamAsInt(desc, "screen")
|
|
||||||
};
|
|
||||||
auto conn = XcbConnection::getOrCreateConnection(id);
|
|
||||||
// RAII protection in case AttachDevice construction below fails
|
|
||||||
XcbConnection::ConnectionGuard guard(conn);
|
|
||||||
|
|
||||||
// Create device and increment connection refcount
|
|
||||||
attachedDevices.emplace_back(desc, conn);
|
|
||||||
// Successfully attached device, so decouple guard from RAII cleanup
|
|
||||||
conn->refCount++;
|
|
||||||
guard.commit();
|
|
||||||
|
|
||||||
std::cout << "Attaching X11 window:\n "
|
|
||||||
<< attachedDevices.back().windowSelector.stringify() << "\n"
|
|
||||||
<< " Actual window name: \""
|
|
||||||
<< attachedDevices.back().actualWindowName << "\"\n"
|
|
||||||
<< " Using " << (conn->refCount > 1 ? "existing" : "new")
|
|
||||||
<< " connection to X server\n";
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int xcbXorg_detachDeviceReq(const hk::device::SenseDeviceSpec &spec)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(attachedDevices.begin(), attachedDevices.end(),
|
|
||||||
[&spec](const AttachedDevice &device) {
|
|
||||||
return device.deviceSpec == spec;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (it == attachedDevices.end())
|
|
||||||
{
|
|
||||||
auto displayIt = std::find_if(
|
|
||||||
spec.providerParams.begin(), spec.providerParams.end(),
|
|
||||||
[](const auto& param) { return param.first == "display"; });
|
|
||||||
auto screenIt = std::find_if(
|
|
||||||
spec.providerParams.begin(), spec.providerParams.end(),
|
|
||||||
[](const auto& param) { return param.first == "screen"; });
|
|
||||||
|
|
||||||
std::cerr << __func__ << ": Device not attached: "
|
|
||||||
<< "display=" << (displayIt != spec.providerParams.end()
|
|
||||||
? displayIt->second : "not specified")
|
|
||||||
<< ", screen=" << (screenIt != spec.providerParams.end()
|
|
||||||
? screenIt->second : "not specified")
|
|
||||||
<< ", selector=" << spec.deviceSelector << "\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
XcbConnection::XConnectionIdentifier id{
|
|
||||||
it->windowSelector.xconn.display,
|
|
||||||
it->windowSelector.xconn.screen
|
|
||||||
};
|
|
||||||
|
|
||||||
// Atomic decrement refcount
|
|
||||||
int newCount = --it->connection->refCount;
|
|
||||||
|
|
||||||
// If no more references, close the connection
|
|
||||||
if (newCount == 0)
|
|
||||||
{
|
|
||||||
XcbConnection::connections.erase(id);
|
|
||||||
std::cout << "Closed X server connection (display="
|
|
||||||
<< id.display << ", screen=" << id.screen << ")\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
attachedDevices.erase(it);
|
|
||||||
std::cout << __func__ << ": Detached device\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef X11_XCB_API_H
|
|
||||||
#define X11_XCB_API_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <user/senseApiDesc.h>
|
|
||||||
|
|
||||||
class Xcb_XorgApi
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Xcb_XorgApi(const std::string& _displayName)
|
|
||||||
: displayName(_displayName)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~Xcb_XorgApi() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string displayName;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // X11_XCB_API_H
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Core library
|
||||||
|
add_library(smocore STATIC
|
||||||
|
mind.cpp
|
||||||
|
opts.cpp
|
||||||
|
componentThread.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(smocore PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link against pthread for CPU affinity functions
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
target_link_libraries(smocore PRIVATE Threads::Threads)
|
||||||
|
|
||||||
|
add_subdirectory(marionette)
|
||||||
|
add_subdirectory(deviceManager)
|
||||||
|
add_subdirectory(senseApis)
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <mind.h>
|
||||||
|
#include <componentThread.h>
|
||||||
|
#include <marionette/marionette.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
thread_local std::shared_ptr<ComponentThread> thisComponentThread;
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
extern std::shared_ptr<ComponentThread> mrntt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of static method
|
||||||
|
std::shared_ptr<ComponentThread> ComponentThread::getMrntt()
|
||||||
|
{
|
||||||
|
return mrntt::mrntt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::initializeTls(void)
|
||||||
|
{
|
||||||
|
thisComponentThread = shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<ComponentThread> ComponentThread::getSelf(void)
|
||||||
|
{
|
||||||
|
if (!thisComponentThread)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": TLS not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
return thisComponentThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::main(ComponentThread& self)
|
||||||
|
{
|
||||||
|
std::cout << self.name << ":" << __func__ << ": Waiting for JOLT" <<"\n";
|
||||||
|
self.getIoService().run();
|
||||||
|
self.initializeTls();
|
||||||
|
|
||||||
|
std::cout << self.name << ":" << __func__ << ": Entering event loop" <<"\n";
|
||||||
|
|
||||||
|
/* We loop here because when an exception is caught, we need to first catch
|
||||||
|
* it in the catch blocks. We bubble the exception to mrntt in the catch
|
||||||
|
* blocks, and then we loop here to await control messages from mrntt.
|
||||||
|
*
|
||||||
|
* We can't just exit on our own. Rather, we must wait for mrntt to tell us
|
||||||
|
* to exit. When we wish to finally exit, we set keepLooping to false.
|
||||||
|
*/
|
||||||
|
for (self.keepLooping = true; self.keepLooping;)
|
||||||
|
{
|
||||||
|
bool sendExceptionInd = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
self.getIoService().reset();
|
||||||
|
self.getIoService().run();
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
sendExceptionInd = true;
|
||||||
|
std::cerr << self.name << ":" << __func__
|
||||||
|
<< ": Exception occurred: " << e.what() << "\n";
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
sendExceptionInd = true;
|
||||||
|
std::cerr << self.name << ":" << __func__
|
||||||
|
<< ": Unknown exception occurred" << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendExceptionInd) { mrntt::mrntt->exceptionInd(self); }
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << self.name << ":" << __func__ << ": Exited event loop" << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread management method implementations
|
||||||
|
void ComponentThread::startThreadReq(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling startThread." << "\n";
|
||||||
|
|
||||||
|
// Execute private setup sequence here
|
||||||
|
// This is where each thread would implement its specific initialization
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
caller->getIoService().post(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::cleanup(void)
|
||||||
|
{
|
||||||
|
this->keepLooping = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::exitThreadReq(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
// Post to the main io_service
|
||||||
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling exitThread "
|
||||||
|
"(main queue)." << std::endl;
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
// Stop the main io_service to exit the thread
|
||||||
|
io_service.stop();
|
||||||
|
if (callback) { caller->getIoService().post(callback); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also post to the pause io_service
|
||||||
|
this->pause_io_service.post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling exitThread "
|
||||||
|
"(pause queue)." << std::endl;
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
// Stop both io_services to exit the thread
|
||||||
|
pause_io_service.stop();
|
||||||
|
io_service.stop();
|
||||||
|
if (callback) { caller->getIoService().post(callback); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::pauseThreadReq(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling pauseThread."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
caller->getIoService().post(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the pause io_service before running to ensure it can run again
|
||||||
|
pause_io_service.reset();
|
||||||
|
// Run the pause io_service to block this thread
|
||||||
|
pause_io_service.run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::resumeThreadReq(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
// Post to the pause_io_service to unblock the paused thread
|
||||||
|
pause_io_service.post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling resumeThread."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
caller->getIoService().post(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the pause_io_service to unblock the thread
|
||||||
|
pause_io_service.stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::joltThreadReq(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
||||||
|
{
|
||||||
|
std::cout << "Thread '" << name << "': handling JOLT request." << "\n";
|
||||||
|
|
||||||
|
// Stop the main io_service to jolt the thread
|
||||||
|
io_service.stop();
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
caller->getIoService().post(callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This shouldn't take a callback because the caller shouldn't expect to
|
||||||
|
* Mrntt to send a reply signal to it. Sending this Indication means that
|
||||||
|
* Mrntt will send the calling thread an exitThreadReq. When the caller
|
||||||
|
* processes that exitThreadReq(), the caller will exit its event loop and then
|
||||||
|
* terminate.
|
||||||
|
*
|
||||||
|
* Even if Mrntt sent a RDY response, the caller shouldn't actually be executing
|
||||||
|
* any longer to receive it anyway.
|
||||||
|
*/
|
||||||
|
void ComponentThread::exceptionInd(ComponentThread& thread)
|
||||||
|
{
|
||||||
|
if (this->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": invoked on non-mrntt thread " + thread.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post the exception to the mrntt thread.
|
||||||
|
this->getIoService().post(
|
||||||
|
[&thread]()
|
||||||
|
{
|
||||||
|
std::cerr << "Mrntt: Exception occurred: in thread "
|
||||||
|
<< thread.name << ". Killing Salmanoff." << "\n";
|
||||||
|
|
||||||
|
/** EXPLANATION:
|
||||||
|
* An exception has occurred in one of a mind's threads. We need to
|
||||||
|
* shut down all of that particular mind's threads.
|
||||||
|
*/
|
||||||
|
thread.parent.finalizeReq([]() {
|
||||||
|
/** FIXME:
|
||||||
|
* When we eventually support multiple minds, we should remove this
|
||||||
|
* since it causes marionette to exit, even if there are other minds
|
||||||
|
* that are still running.
|
||||||
|
*/
|
||||||
|
smo::mrntt::exitMarionetteLoop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::userShutdownInd()
|
||||||
|
{
|
||||||
|
if (this->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": invoked on non-mrntt thread " + this->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post the user shutdown to the mrntt thread.
|
||||||
|
this->getIoService().post(
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
std::cerr << "Mrntt: User requested shutdown (SIGINT)."
|
||||||
|
<< " Killing Salmanoff." << "\n";
|
||||||
|
|
||||||
|
/** EXPLANATION:
|
||||||
|
* A user has requested a shutdown. We need to shut down all of the
|
||||||
|
* threads in all running Minds.
|
||||||
|
*/
|
||||||
|
parent.finalizeReq([]() {
|
||||||
|
/** FIXME:
|
||||||
|
* When we eventually support multiple minds, we should remove this
|
||||||
|
* since it causes marionette to exit, even if there are other minds
|
||||||
|
* that are still running.
|
||||||
|
*/
|
||||||
|
smo::mrntt::exitMarionetteLoop();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPU management method implementations
|
||||||
|
int ComponentThread::getAvailableCpuCount()
|
||||||
|
{
|
||||||
|
int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (cpuCount <= 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Failed to determine CPU count");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if std::thread::hardware_concurrency() matches sysconf result
|
||||||
|
unsigned int hwConcurrency = std::thread::hardware_concurrency();
|
||||||
|
if (hwConcurrency != static_cast<unsigned int>(cpuCount))
|
||||||
|
{
|
||||||
|
std::cerr << "Warning: CPU count mismatch - "
|
||||||
|
"std::thread::hardware_concurrency() = "
|
||||||
|
<< hwConcurrency << ", sysconf(_SC_NPROCESSORS_ONLN) = "
|
||||||
|
<< cpuCount << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpuCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentThread::pinToCpu(int cpuId)
|
||||||
|
{
|
||||||
|
if (cpuId < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Invalid CPU ID: " + std::to_string(cpuId));
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_set_t cpuset;
|
||||||
|
CPU_ZERO(&cpuset);
|
||||||
|
CPU_SET(cpuId, &cpuset);
|
||||||
|
|
||||||
|
int result = pthread_setaffinity_np(
|
||||||
|
thread.native_handle(), sizeof(cpu_set_t), &cpuset);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Failed to pin thread to CPU " + std::to_string(cpuId)
|
||||||
|
+ ": " + std::strerror(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
pinnedCpuId = cpuId;
|
||||||
|
std::cout << name << ": Pinned to CPU " << cpuId << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Flex/Bison generated files
|
||||||
|
set(LEX_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/deviceAttachmentPipeSpecl.cc)
|
||||||
|
set(YACC_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/deviceAttachmentPipeSpecp.cc)
|
||||||
|
set(YACC_HEADER ${CMAKE_CURRENT_BINARY_DIR}/deviceAttachmentPipeSpecp.hh)
|
||||||
|
|
||||||
|
# Generate Flex/Bison files using custom commands
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${LEX_OUTPUT}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/deviceAttachmentPipeSpecl.ll ${YACC_HEADER}
|
||||||
|
COMMAND ${FLEX_EXECUTABLE} --header-file=${CMAKE_CURRENT_BINARY_DIR}/deviceAttachmentPipeSpecl.hh -o ${LEX_OUTPUT} ${CMAKE_CURRENT_SOURCE_DIR}/deviceAttachmentPipeSpecl.ll
|
||||||
|
COMMENT "Generating deviceAttachmentPipeSpecl.cc from deviceAttachmentPipeSpecl.ll"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${YACC_OUTPUT} ${YACC_HEADER}
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/deviceAttachmentPipeSpecp.yy
|
||||||
|
COMMAND ${BISON_EXECUTABLE} -p deviceAttachmentPipeSpecp --header=${YACC_HEADER} -o ${YACC_OUTPUT} ${CMAKE_CURRENT_SOURCE_DIR}/deviceAttachmentPipeSpecp.yy
|
||||||
|
COMMENT "Generating deviceAttachmentPipeSpecp.cc and deviceAttachmentPipeSpecp.hh from deviceAttachmentPipeSpecp.yy"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Device manager library
|
||||||
|
add_library(deviceManager STATIC
|
||||||
|
deviceManager.cpp
|
||||||
|
deviceAttachmentPipeSpecParser.cpp
|
||||||
|
${LEX_OUTPUT}
|
||||||
|
${YACC_OUTPUT}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(deviceManager PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <deviceManager/deviceManager.h>
|
||||||
|
#include "deviceAttachmentPipeSpecp.hh"
|
||||||
|
#include "deviceAttachmentPipeSpecl.hh"
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace device {
|
||||||
|
|
||||||
|
std::string DeviceManager::readDapSpecFile(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::ifstream file(filename);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(__func__) + ": Couldn't open DAP spec file: "
|
||||||
|
+ filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string content(
|
||||||
|
(std::istreambuf_iterator<char>(file)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::collateAllDapSpecs(void)
|
||||||
|
{
|
||||||
|
OptionParser &options = OptionParser::getOptions();
|
||||||
|
allDapSpecs = options.dapSpecs;
|
||||||
|
|
||||||
|
for (const auto& file : options.dapSpecFiles)
|
||||||
|
{
|
||||||
|
std::string fileContent = readDapSpecFile(file);
|
||||||
|
if (!allDapSpecs.empty()) {
|
||||||
|
allDapSpecs += "||";
|
||||||
|
}
|
||||||
|
allDapSpecs += fileContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::parseAllDapSpecs(void)
|
||||||
|
{
|
||||||
|
auto file_deleter = [](FILE* f) { if (f) fclose(f); };
|
||||||
|
std::unique_ptr<FILE, decltype(file_deleter)> input(
|
||||||
|
fmemopen((void*)allDapSpecs.c_str(), allDapSpecs.size(), "r"),
|
||||||
|
file_deleter);
|
||||||
|
|
||||||
|
if (!input)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(__func__) + ": Failed to fmemopen() a FILE* for "
|
||||||
|
"parsing DAP specs");
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceAttachmentPipeSpeclin = input.get();
|
||||||
|
if (deviceAttachmentPipeSpecpparse())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(__func__) + ": Failed to parse DAP specs. "
|
||||||
|
"Check specs for errors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace device
|
||||||
|
} // namespace smo
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
%option prefix="deviceAttachmentPipeSpecl"
|
||||||
|
%option nounput
|
||||||
|
%option noinput
|
||||||
|
%{
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <deviceManager/deviceManager.h>
|
||||||
|
#include "deviceAttachmentPipeSpecp.hh"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
"+adev" {
|
||||||
|
deviceAttachmentPipeSpecplval.chr = yytext[1];
|
||||||
|
return KEYWORD_SPECTYPE_ACTUATOR;
|
||||||
|
}
|
||||||
|
"+edev" {
|
||||||
|
deviceAttachmentPipeSpecplval.chr = yytext[1];
|
||||||
|
return KEYWORD_SPECTYPE_EXTROSPECTOR;
|
||||||
|
}
|
||||||
|
"+idev" {
|
||||||
|
deviceAttachmentPipeSpecplval.chr = yytext[1];
|
||||||
|
return KEYWORD_SPECTYPE_INTEROSPECTOR;
|
||||||
|
}
|
||||||
|
"||" { return DOUBLE_PIPE; }
|
||||||
|
"|" { return PIPE; }
|
||||||
|
"(" { return LPAREN; }
|
||||||
|
")" { return RPAREN; }
|
||||||
|
"=" { return EQUALS; }
|
||||||
|
(\\.|[^=\|\(\) \t\r\n])+ {
|
||||||
|
std::string token(yytext);
|
||||||
|
std::string unescaped;
|
||||||
|
unescaped.reserve(token.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < token.size(); ++i)
|
||||||
|
{
|
||||||
|
if (token[i] != '\\')
|
||||||
|
{
|
||||||
|
unescaped.push_back(token[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a backslash is the final char before EOF, just continue so it gets
|
||||||
|
* dropped as a side effect.
|
||||||
|
*/
|
||||||
|
if (i + 1 >= token.size()) { continue; }
|
||||||
|
|
||||||
|
// Else push the char following the backslash.
|
||||||
|
unescaped.push_back(token[++i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceAttachmentPipeSpecplval.str = strdup(unescaped.c_str());
|
||||||
|
return STRING;
|
||||||
|
}
|
||||||
|
[ \t\r\n]+ { /* ignore all whitespace, including newlines */ }
|
||||||
|
. { return yytext[0]; }
|
||||||
|
%%
|
||||||
|
|
||||||
|
int deviceAttachmentPipeSpeclwrap(void)
|
||||||
|
{
|
||||||
|
return 1; // Indicate end of input
|
||||||
|
}
|
||||||
+29
-28
@@ -7,13 +7,13 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <user/senseDeviceSpec.h>
|
#include <user/deviceAttachmentSpec.h>
|
||||||
#include <deviceManager/deviceManager.h>
|
#include <deviceManager/deviceManager.h>
|
||||||
|
|
||||||
#ifndef yylex
|
#ifndef yylex
|
||||||
/* We use different prefixes for the lexer and parser.
|
/* We use different prefixes for the lexer and parser.
|
||||||
* * Our lexer's prefix is deviceSpecl.
|
* * Our lexer's prefix is deviceAttachmentPipeSpecl.
|
||||||
* * Our parser's prefix is deviceSpecp.
|
* * Our parser's prefix is deviceAttachmentPipeSpecp.
|
||||||
*
|
*
|
||||||
* Yacc and Bison don't have a way to handle the scenario where the lexer has
|
* Yacc and Bison don't have a way to handle the scenario where the lexer has
|
||||||
* a different prefix from the parser that they generate. They assume that the
|
* a different prefix from the parser that they generate. They assume that the
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
#error "Yacc should have defined yylex as a preprocessor token, and we need to override it to tell yacc the name of our lex function."
|
#error "Yacc should have defined yylex as a preprocessor token, and we need to override it to tell yacc the name of our lex function."
|
||||||
#endif
|
#endif
|
||||||
#undef yylex
|
#undef yylex
|
||||||
#define yylex deviceSpecllex
|
#define yylex deviceAttachmentPipeSpecllex
|
||||||
|
|
||||||
#ifdef yytext
|
#ifdef yytext
|
||||||
#undef yytext
|
#undef yytext
|
||||||
#endif
|
#endif
|
||||||
#define yytext deviceSpecltext
|
#define yytext deviceAttachmentPipeSpecltext
|
||||||
|
|
||||||
// Declare the symbols that our lexer will export.
|
// Declare the symbols that our lexer will export.
|
||||||
int yylex(void);
|
int yylex(void);
|
||||||
@@ -36,7 +36,7 @@ extern char* yytext; // Declare yytext to access the current token text
|
|||||||
void yyerror(const char *message)
|
void yyerror(const char *message)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("deviceSpec parser error: ")
|
std::string("deviceAttachmentPipeSpec parser error: ")
|
||||||
+ std::string(message)
|
+ std::string(message)
|
||||||
+ " at token: " + std::string(yytext));
|
+ " at token: " + std::string(yytext));
|
||||||
}
|
}
|
||||||
@@ -46,9 +46,9 @@ void yyerror(const char *message)
|
|||||||
%union {
|
%union {
|
||||||
char* str;
|
char* str;
|
||||||
char chr;
|
char chr;
|
||||||
hk::device::SenseDeviceSpec* sensorSpec;
|
smo::device::DeviceAttachmentSpec* sensorSpec;
|
||||||
hk::device::InteroceptorDeviceSpec* interoceptorSpec;
|
smo::device::InteroceptorDevAttachmentSpec* interoceptorSpec;
|
||||||
hk::device::ExtrospectorDeviceSpec* extrospectorSpec;
|
smo::device::ExtrospectorDevAttachmentSpec* extrospectorSpec;
|
||||||
std::vector<std::pair<std::string,std::string>>* paramVector;
|
std::vector<std::pair<std::string,std::string>>* paramVector;
|
||||||
std::pair<std::string,std::string>* param;
|
std::pair<std::string,std::string>* param;
|
||||||
}
|
}
|
||||||
@@ -83,12 +83,12 @@ sensor_spec:
|
|||||||
|
|
||||||
interoceptor_spec:
|
interoceptor_spec:
|
||||||
KEYWORD_SPECTYPE_INTEROSPECTOR PIPE spec_body {
|
KEYWORD_SPECTYPE_INTEROSPECTOR PIPE spec_body {
|
||||||
auto spec = std::make_shared<hk::device::InteroceptorDeviceSpec>(
|
auto spec = std::make_shared<smo::device::InteroceptorDevAttachmentSpec>(
|
||||||
*static_cast<hk::device::InteroceptorDeviceSpec *>($3));
|
*static_cast<smo::device::InteroceptorDevAttachmentSpec *>($3));
|
||||||
|
|
||||||
spec->sensorType = $1;
|
spec->sensorType = $1;
|
||||||
hk::device::DeviceManager::interoceptorDeviceSpecs.push_back(spec);
|
smo::device::DeviceManager::interoceptorDeviceSpecs.push_back(spec);
|
||||||
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
|
smo::device::DeviceManager::deviceAttachmentSpecs.push_back(spec);
|
||||||
|
|
||||||
delete $3;
|
delete $3;
|
||||||
}
|
}
|
||||||
@@ -96,29 +96,30 @@ interoceptor_spec:
|
|||||||
|
|
||||||
extrospector_spec:
|
extrospector_spec:
|
||||||
KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body {
|
KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body {
|
||||||
auto spec = std::make_shared<hk::device::ExtrospectorDeviceSpec>(
|
auto spec = std::make_shared<smo::device::ExtrospectorDevAttachmentSpec>(
|
||||||
*static_cast<hk::device::ExtrospectorDeviceSpec *>($3));
|
*static_cast<smo::device::ExtrospectorDevAttachmentSpec *>($3));
|
||||||
|
|
||||||
spec->sensorType = $1;
|
spec->sensorType = $1;
|
||||||
hk::device::DeviceManager::extrospectorDeviceSpecs.push_back(spec);
|
smo::device::DeviceManager::extrospectorDeviceSpecs.push_back(spec);
|
||||||
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
|
smo::device::DeviceManager::deviceAttachmentSpecs.push_back(spec);
|
||||||
|
|
||||||
delete $3;
|
delete $3;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
spec_body:
|
spec_body:
|
||||||
STRING PIPE STRING LPAREN opt_params RPAREN PIPE STRING LPAREN opt_params RPAREN PIPE STRING {
|
STRING PIPE STRING PIPE STRING LPAREN opt_params RPAREN PIPE STRING LPAREN opt_params RPAREN PIPE STRING {
|
||||||
$$ = new hk::device::SenseDeviceSpec();
|
$$ = new smo::device::DeviceAttachmentSpec();
|
||||||
$$->sensorType = '\0';
|
$$->deviceIdentifier = std::string($1);
|
||||||
$$->implexor = std::string($1);
|
$$->sensorType = '\0'; // This will be set by the parent rule
|
||||||
$$->api = std::string($3);
|
$$->implexor = std::string($3);
|
||||||
$$->apiParams = std::move(*$5);
|
$$->api = std::string($5);
|
||||||
$$->provider = std::string($8);
|
$$->apiParams = std::move(*$7);
|
||||||
$$->providerParams = std::move(*$10);
|
$$->provider = std::string($10);
|
||||||
$$->deviceSelector = std::string($13);
|
$$->providerParams = std::move(*$12);
|
||||||
delete $5;
|
$$->deviceSelector = std::string($15);
|
||||||
delete $10;
|
delete $7;
|
||||||
|
delete $12;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <opts.h>
|
||||||
|
#include <deviceManager/deviceManager.h>
|
||||||
|
#include <senseApis/senseApiManager.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace device {
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<InteroceptorDevAttachmentSpec>>
|
||||||
|
DeviceManager::interoceptorDeviceSpecs;
|
||||||
|
std::vector<std::shared_ptr<ExtrospectorDevAttachmentSpec>>
|
||||||
|
DeviceManager::extrospectorDeviceSpecs;
|
||||||
|
std::vector<std::shared_ptr<DeviceAttachmentSpec>>
|
||||||
|
DeviceManager::deviceAttachmentSpecs;
|
||||||
|
std::vector<std::shared_ptr<Device>>
|
||||||
|
DeviceManager::devices;
|
||||||
|
|
||||||
|
// Async continuation structure
|
||||||
|
struct DeviceAttachmentContinuation {
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> spec;
|
||||||
|
std::function<void(
|
||||||
|
bool success, std::shared_ptr<Device> device,
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec)
|
||||||
|
> callback;
|
||||||
|
|
||||||
|
DeviceAttachmentContinuation(
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> s,
|
||||||
|
std::function<void(
|
||||||
|
bool success, std::shared_ptr<Device> device,
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec)
|
||||||
|
> cb)
|
||||||
|
: spec(s), callback(cb)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string DeviceManager::stringifyDeviceSpecs(void)
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
for (const auto& spec : DeviceManager::interoceptorDeviceSpecs) {
|
||||||
|
oss << "Interoceptor " << spec->stringify();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& spec : DeviceManager::extrospectorDeviceSpecs) {
|
||||||
|
oss << "Extrospector " << spec->stringify();
|
||||||
|
}
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceManager::newDeviceAttachmentSpecInd(
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> spec,
|
||||||
|
std::function<void(
|
||||||
|
bool success, std::shared_ptr<Device> device,
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec)
|
||||||
|
> callback)
|
||||||
|
{
|
||||||
|
// Create async continuation
|
||||||
|
auto continuation = std::make_shared<DeviceAttachmentContinuation>(
|
||||||
|
spec, callback);
|
||||||
|
|
||||||
|
// Check if a DeviceAttachmentSpec already matches
|
||||||
|
for (const auto& existingSpec : deviceAttachmentSpecs)
|
||||||
|
{
|
||||||
|
if (!(*existingSpec == *spec)) { continue; }
|
||||||
|
// Already exists, callback with error
|
||||||
|
callback(false, nullptr, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to attach the sense device
|
||||||
|
try {
|
||||||
|
sense_api::SenseApiManager::getInstance().attachSenseDevice(spec);
|
||||||
|
|
||||||
|
// Look for existing Device with same identifier
|
||||||
|
std::shared_ptr<Device> device = nullptr;
|
||||||
|
for (const auto& existingDevice : devices)
|
||||||
|
{
|
||||||
|
if (existingDevice->deviceIdentifier != spec->deviceIdentifier)
|
||||||
|
{ continue; }
|
||||||
|
|
||||||
|
device = existingDevice;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If device doesn't exist, create a new one and add it
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
device = std::make_shared<Device>(spec->deviceIdentifier);
|
||||||
|
devices.push_back(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add DeviceAttachmentSpec to device's list
|
||||||
|
device->deviceAttachmentSpecs.push_back(spec);
|
||||||
|
|
||||||
|
// Add DeviceAttachmentSpec to DeviceManager's list
|
||||||
|
deviceAttachmentSpecs.push_back(spec);
|
||||||
|
|
||||||
|
// Callback with success
|
||||||
|
callback(true, device, spec);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
// Attach failed, callback with error
|
||||||
|
callback(false, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace device
|
||||||
|
} // namespace smo
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef _ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
|
#define _ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
|
|
||||||
|
#include <mentenon.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class FogArtificedMentalPhenomenon
|
||||||
|
: public ArtificedMentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef FogArtificedMentalPhenomenon Fogenon;
|
||||||
|
|
||||||
|
class IdyllicArtificedMentalPhenomenon
|
||||||
|
: public ArtificedMentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IdyllicArtificedMentalPhenomenon Idyllenon;
|
||||||
|
|
||||||
|
class FantasyArtificedMentalPhenomenon
|
||||||
|
: public ArtificedMentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef FantasyArtificedMentalPhenomenon Fantanon;
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
#ifndef COMPONENT_THREAD_H
|
||||||
|
#define COMPONENT_THREAD_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <queue>
|
||||||
|
#include <functional>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind; // Forward declaration
|
||||||
|
|
||||||
|
class ComponentThread
|
||||||
|
: public std::enable_shared_from_this<ComponentThread>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ThreadId
|
||||||
|
{
|
||||||
|
MRNTT = 0,
|
||||||
|
DIRECTOR,
|
||||||
|
SIMULATOR,
|
||||||
|
SUBCONSCIOUS,
|
||||||
|
BODY,
|
||||||
|
WORLD,
|
||||||
|
N_ITEMS
|
||||||
|
};
|
||||||
|
|
||||||
|
ComponentThread(ThreadId _id, Mind& parent)
|
||||||
|
: id(_id), name(getThreadName(_id)), parent(parent),
|
||||||
|
work(io_service), pause_work(pause_io_service),
|
||||||
|
pinnedCpuId(-1),
|
||||||
|
thread(
|
||||||
|
((id == MRNTT) ? marionetteMain : main),
|
||||||
|
std::ref(*this))
|
||||||
|
{}
|
||||||
|
|
||||||
|
void cleanup(void);
|
||||||
|
|
||||||
|
boost::asio::io_service& getIoService(void) { return io_service; }
|
||||||
|
|
||||||
|
void initializeTls(void);
|
||||||
|
static const std::shared_ptr<ComponentThread> getSelf(void);
|
||||||
|
|
||||||
|
static std::shared_ptr<ComponentThread> getMrntt();
|
||||||
|
Mind& getParent() const { return parent; }
|
||||||
|
|
||||||
|
typedef void (mainFn)(ComponentThread &self);
|
||||||
|
static mainFn main, marionetteMain;
|
||||||
|
|
||||||
|
// Thread management methods
|
||||||
|
void startThreadReq(std::function<void()> callback = nullptr);
|
||||||
|
void exitThreadReq(std::function<void()> callback = nullptr);
|
||||||
|
void pauseThreadReq(std::function<void()> callback = nullptr);
|
||||||
|
void resumeThreadReq(std::function<void()> callback = nullptr);
|
||||||
|
/**
|
||||||
|
* JOLTs this thread to begin processing after global initialization.
|
||||||
|
*
|
||||||
|
* JOLTing is the mechanism that allows threads to enter their main
|
||||||
|
* event loops and set up TLS vars after all global constructors have
|
||||||
|
* completed. This prevents race conditions during system startup.
|
||||||
|
*/
|
||||||
|
void joltThreadReq(std::function<void()> callback = nullptr);
|
||||||
|
|
||||||
|
// CPU management methods
|
||||||
|
static int getAvailableCpuCount();
|
||||||
|
void pinToCpu(int cpuId);
|
||||||
|
|
||||||
|
enum class ThreadOp
|
||||||
|
{
|
||||||
|
START,
|
||||||
|
PAUSE,
|
||||||
|
RESUME,
|
||||||
|
EXIT,
|
||||||
|
JOLT,
|
||||||
|
N_ITEMS
|
||||||
|
};
|
||||||
|
|
||||||
|
// Intentionally doesn't take a callback.
|
||||||
|
void exceptionInd(ComponentThread& thread);
|
||||||
|
// Intentionally doesn't take a callback.
|
||||||
|
void userShutdownInd();
|
||||||
|
|
||||||
|
public:
|
||||||
|
ThreadId id;
|
||||||
|
std::string name;
|
||||||
|
Mind &parent;
|
||||||
|
boost::asio::io_service io_service;
|
||||||
|
boost::asio::io_service::work work;
|
||||||
|
boost::asio::io_service pause_io_service;
|
||||||
|
boost::asio::io_service::work pause_work;
|
||||||
|
std::atomic<bool> keepLooping;
|
||||||
|
int pinnedCpuId;
|
||||||
|
|
||||||
|
|
||||||
|
/* Always ensure that this is last so that the thread is spawned after
|
||||||
|
* everything else is constructed.
|
||||||
|
*/
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
|
static const std::string getThreadName(ThreadId id)
|
||||||
|
{
|
||||||
|
if (id < 0 || id >= ComponentThread::N_ITEMS)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Invalid thread ID");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use function-local static to ensure proper initialization order
|
||||||
|
static const std::string threadNames[N_ITEMS] = {
|
||||||
|
"mrntt",
|
||||||
|
"director",
|
||||||
|
"simulator",
|
||||||
|
"subconscious",
|
||||||
|
"body",
|
||||||
|
"world"
|
||||||
|
};
|
||||||
|
|
||||||
|
return threadNames[id];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
extern std::shared_ptr<ComponentThread> mrntt;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // COMPONENT_THREAD_H
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef _CONCEPT_H
|
||||||
|
#define _CONCEPT_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <logic.h>
|
||||||
|
#include <mentalEntity.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace concepts {
|
||||||
|
|
||||||
|
class Comparator
|
||||||
|
: public MentalEntity, public logic::Operand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** EXPLANATION:
|
||||||
|
* The reference for a Comparator is the fixed mentity or range of mentities
|
||||||
|
* that this comparator is intended to validate a match against.
|
||||||
|
*
|
||||||
|
* There are several mentities against which a comparator can match. At the
|
||||||
|
* time of writing, we're fairly sure that these will be at minimum,
|
||||||
|
* qualia, chronomena and mentena.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<MentalEntity> reference;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ComparatorExpression
|
||||||
|
: public logic::UnaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComparatorExpression(
|
||||||
|
logic::Operator &op, std::shared_ptr<Comparator> &comparator
|
||||||
|
)
|
||||||
|
: logic::UnaryExpression(
|
||||||
|
op, std::static_pointer_cast<logic::Operand>(comparator))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CombinatorialLogicExpression
|
||||||
|
: public MentalEntity, public logic::Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef CombinatorialLogicExpression Concept;
|
||||||
|
|
||||||
|
} // namespace concept
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef DEVICE_H
|
||||||
|
#define DEVICE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
#include <user/deviceAttachmentSpec.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace device {
|
||||||
|
|
||||||
|
class Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string deviceIdentifier;
|
||||||
|
std::vector<std::shared_ptr<DeviceAttachmentSpec>> deviceAttachmentSpecs;
|
||||||
|
|
||||||
|
Device(const std::string& identifier) : deviceIdentifier(identifier) {}
|
||||||
|
|
||||||
|
std::string stringify() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "Device Identifier: " << deviceIdentifier
|
||||||
|
<< ", Attachment Specs: " << deviceAttachmentSpecs.size() << std::endl;
|
||||||
|
for (const auto& spec : deviceAttachmentSpecs) {
|
||||||
|
os << " " << spec->stringify();
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace device
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // DEVICE_H
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#ifndef DEVICEMANAGER_H
|
||||||
|
#define DEVICEMANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <opts.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <iostream>
|
||||||
|
#include <user/deviceAttachmentSpec.h>
|
||||||
|
#include <deviceManager/device.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace device {
|
||||||
|
|
||||||
|
class DeviceManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static DeviceManager& getInstance()
|
||||||
|
{
|
||||||
|
static DeviceManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string readDapSpecFile(const std::string& filename);
|
||||||
|
void collateAllDapSpecs(void);
|
||||||
|
void parseAllDapSpecs(void);
|
||||||
|
|
||||||
|
static const std::string stringifyDeviceSpecs(void);
|
||||||
|
|
||||||
|
// New async function for device attachment
|
||||||
|
void newDeviceAttachmentSpecInd(
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> spec,
|
||||||
|
std::function<void(bool success, std::shared_ptr<Device> device, std::shared_ptr<DeviceAttachmentSpec> deviceSpec)> callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeviceManager() = default;
|
||||||
|
~DeviceManager() = default;
|
||||||
|
DeviceManager(const DeviceManager&) = delete;
|
||||||
|
DeviceManager& operator=(const DeviceManager&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string allDapSpecs;
|
||||||
|
static std::vector<std::shared_ptr<InteroceptorDevAttachmentSpec>>
|
||||||
|
interoceptorDeviceSpecs;
|
||||||
|
static std::vector<std::shared_ptr<ExtrospectorDevAttachmentSpec>>
|
||||||
|
extrospectorDeviceSpecs;
|
||||||
|
static std::vector<std::shared_ptr<DeviceAttachmentSpec>>
|
||||||
|
deviceAttachmentSpecs;
|
||||||
|
static std::vector<std::shared_ptr<Device>> devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace device
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // DEVICEMANAGER_H
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <mentalEntity.h>
|
#include <mentalEntity.h>
|
||||||
|
|
||||||
namespace hk {
|
namespace smo {
|
||||||
namespace director {
|
namespace director {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,6 +74,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace director
|
} // namespace director
|
||||||
} // namespace hk
|
} // namespace smo
|
||||||
|
|
||||||
#endif // DIRECTOR_COMMANDLIST_H
|
#endif // DIRECTOR_COMMANDLIST_H
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef DIRECTOR_H
|
||||||
|
#define DIRECTOR_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <goal.h>
|
||||||
|
#include <lruLifo.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace director {
|
||||||
|
|
||||||
|
class Director {
|
||||||
|
public:
|
||||||
|
Director() = default;
|
||||||
|
~Director() = default;
|
||||||
|
|
||||||
|
/** EXPLANATION:
|
||||||
|
* We allow SMO to prioritize negtrins over injected goals, so that it can
|
||||||
|
* prioritize pain mitigation. We may decide to change this in the future.
|
||||||
|
*
|
||||||
|
* NB: Prioritizing negtrins is not the same as priortizing
|
||||||
|
* self-preservation...at least we don't think so at the moment of writing.
|
||||||
|
* It is definitely not desirable for SMO to prioritize self-preservation
|
||||||
|
* over our injected goals.
|
||||||
|
*/
|
||||||
|
LruLifo negtrins;
|
||||||
|
/** EXPLANATION:
|
||||||
|
* These are goals injected by Mrntt. This is how Mrntt is able to inject
|
||||||
|
* goals into the director.
|
||||||
|
*/
|
||||||
|
LruLifo injectedGoals;
|
||||||
|
/** EXPLANATION:
|
||||||
|
* These are goals chosen by the running mind. Director will always
|
||||||
|
* prioritize injected goals over chosen goals.
|
||||||
|
*/
|
||||||
|
LruLifo chosenGoals;
|
||||||
|
LruLifo postrins;
|
||||||
|
LruLifo nontrins;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace director
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // DIRECTOR_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _FANTASY_ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
|
#define _FANTASY_ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
|
|
||||||
|
#include <artificedMentalPhenomenon.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class FictionalFantasyArtificedMentalPhenomenon
|
||||||
|
: public FantasyArtificedMentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef FictionalFantasyArtificedMentalPhenomenon Fictenon;
|
||||||
|
|
||||||
|
class AspirationalFantasyArtificedMentalPhenomenon
|
||||||
|
: public FantasyArtificedMentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef AspirationalFantasyArtificedMentalPhenomenon Aspanon;
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _FANTASY_ARTIFICED_MENTAL_PHENOMENON_H
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
#ifndef _GOAL_H
|
#ifndef _GOAL_H
|
||||||
#define _GOAL_H
|
#define _GOAL_H
|
||||||
|
|
||||||
#include <simulator/scene.h>
|
#include <concept.h>
|
||||||
|
|
||||||
namespace hk {
|
namespace smo {
|
||||||
|
|
||||||
class Goal
|
class Goal
|
||||||
: public simulator::Scene {
|
: public concepts::Concept {
|
||||||
public:
|
public:
|
||||||
Goal() = default;
|
Goal() = default;
|
||||||
~Goal() = default;
|
~Goal() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace hk
|
} // namespace smo
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef IMPLIX_H
|
#ifndef IMPLIX_H
|
||||||
#define IMPLIX_H
|
#define IMPLIX_H
|
||||||
|
|
||||||
namespace hk {
|
namespace smo {
|
||||||
namespace implix {
|
namespace implix {
|
||||||
|
|
||||||
class Implix
|
class Implix
|
||||||
@@ -12,6 +12,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace implix
|
} // namespace implix
|
||||||
} // namespace hk
|
} // namespace smo
|
||||||
|
|
||||||
#endif // IMPLIX_H
|
#endif // IMPLIX_H
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef _LOGIC_H
|
||||||
|
#define _LOGIC_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace logic {
|
||||||
|
|
||||||
|
class ExpressionPart
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class Operator
|
||||||
|
: public ExpressionPart
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class OperatorAnd
|
||||||
|
: public Operator
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class OperatorOr
|
||||||
|
: public Operator
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class OperatorNot
|
||||||
|
: public Operator
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class Operand
|
||||||
|
: public ExpressionPart
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnaryExpression
|
||||||
|
: public ExpressionPart
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UnaryExpression(Operator &op, const std::shared_ptr<Operand> &operand)
|
||||||
|
: parts(std::make_pair(op, operand))
|
||||||
|
{}
|
||||||
|
public:
|
||||||
|
std::pair<Operator, std::shared_ptr<Operand>> parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Expressions can be chained as parts of a larger expression
|
||||||
|
class Expression
|
||||||
|
: public ExpressionPart
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// This will eventually take in some data to be evaluated for a match.
|
||||||
|
virtual bool evaluate(void) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<std::shared_ptr<ExpressionPart>> parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace logic
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef _LRU_LIFO_H
|
||||||
|
#define _LRU_LIFO_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <mentalEntity.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
/** EXPLANATION:
|
||||||
|
* LruLifo is a Last In First Out (LIFO) buffer with Least Recently Used (LRU)
|
||||||
|
* eviction. It is used to store a limited number of items, and the oldest item
|
||||||
|
* is removed when the buffer is full.
|
||||||
|
*
|
||||||
|
* This is used to store the most recent qualia to be processed by drctr.
|
||||||
|
* Drctr pops objects off the LruLifos in its main loop.
|
||||||
|
*
|
||||||
|
* Naturally since a mind is operating in dynamic world, we may very well be
|
||||||
|
* flooded with with too many qualia to process. Some qualia may just have to be
|
||||||
|
* dropped. So we may very well literally forget those qualia that get dropped
|
||||||
|
* from the LruLifos. (Because LruLifos have a fixed size.)
|
||||||
|
*/
|
||||||
|
|
||||||
|
class LruLifo {
|
||||||
|
public:
|
||||||
|
LruLifo() = default;
|
||||||
|
~LruLifo() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef _BODY_H
|
||||||
|
#define _BODY_H
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class Body
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Body() = default;
|
||||||
|
~Body() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
#endif // _BODY_H
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef MRNTT_BODY_BODYMAP_H
|
||||||
|
#define MRNTT_BODY_BODYMAP_H
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <body/limb.h>
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class BodyMap {
|
||||||
|
public:
|
||||||
|
BodyMap() = default;
|
||||||
|
~BodyMap() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::set<uint32_t, Limb> limbs;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
#endif // MRNTT_BODY_BODYMAP_H
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef MRNTT_BODY_BODYMESSAGE_H
|
||||||
|
#define MRNTT_BODY_BODYMESSAGE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <body/limb.h>
|
||||||
|
#include <body/part.h>
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class BodyMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BodyMessage() = default;
|
||||||
|
~BodyMessage() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpotImpactEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class ReportType
|
||||||
|
{
|
||||||
|
PRESSURE,
|
||||||
|
PAIN,
|
||||||
|
PLEASURE,
|
||||||
|
HEAT,
|
||||||
|
COLD
|
||||||
|
};
|
||||||
|
|
||||||
|
SpotImpactEntry(uint32_t _spot, ReportType _type, uint32_t _value)
|
||||||
|
: spot(_spot), type(_type), value(_value)
|
||||||
|
{}
|
||||||
|
~SpotImpactEntry() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t spot;
|
||||||
|
ReportType type;
|
||||||
|
uint32_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SpotImpactInd : public BodyMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SpotImpactInd(Part &_part) : part(_part) {}
|
||||||
|
~SpotImpactInd() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Part ∂
|
||||||
|
std::vector<SpotImpactEntry> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PartMsg : public BodyMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PartMsg(const Part& _part) : part(_part) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Part& part;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
#endif // MRNTT_BODY_BODYMESSAGE_H
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef MRNTT_BODY_LIMB_H
|
||||||
|
#define MRNTT_BODY_LIMB_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <body/part.h>
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class Limb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Limb(uint32_t _id) : id(_id) {}
|
||||||
|
Limb(uint32_t _id,
|
||||||
|
const std::string& _name, const std::string& _desc,
|
||||||
|
const std::string& _loc)
|
||||||
|
: id(_id), name(_name), description(_desc), location(_loc)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~Limb() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint32_t id;
|
||||||
|
std::string name, description, location;
|
||||||
|
std::set<uint32_t, Part> parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
#endif // MRNTT_BODY_LIMB_H
|
||||||
@@ -6,12 +6,18 @@
|
|||||||
|
|
||||||
#include <body/limb.h>
|
#include <body/limb.h>
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
class BodyMap {
|
class BodyMap {
|
||||||
public:
|
public:
|
||||||
BodyMap() = default;
|
BodyMap() = default;
|
||||||
~BodyMap() = default;
|
~BodyMap() = default;
|
||||||
|
|
||||||
std::set<uint32_t, BodyLimb> limbs;
|
std::set<uint32_t, Limb> limbs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
#endif // _BODY_MAP_H
|
#endif // _BODY_MAP_H
|
||||||
@@ -7,14 +7,17 @@
|
|||||||
|
|
||||||
#include <sensors/interoceptor.h>
|
#include <sensors/interoceptor.h>
|
||||||
|
|
||||||
class BodySpot
|
namespace mrntt {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class Spot
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BodySpot(uint32_t _id, std::string _description)
|
Spot(uint32_t _id, std::string _description)
|
||||||
: id(_id), description(_description)
|
: id(_id), description(_description)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~BodySpot() = default;
|
~Spot() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
@@ -22,21 +25,24 @@ public:
|
|||||||
std::set<uint32_t, Interoceptor> interoceptors;
|
std::set<uint32_t, Interoceptor> interoceptors;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BodyPart
|
class Part
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BodyPart(uint32_t _partId, std::string _partName,
|
Part(uint32_t _partId, std::string _partName,
|
||||||
std::string _partDesc, std::string _partLoc)
|
std::string _partDesc, std::string _partLoc)
|
||||||
: id(_partId), name(_partName),
|
: id(_partId), name(_partName),
|
||||||
description(_partDesc), location(_partLoc)
|
description(_partDesc), location(_partLoc)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~BodyPart() = default;
|
~Part() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const uint32_t id;
|
const uint32_t id;
|
||||||
std::string name, description, location;
|
std::string name, description, location;
|
||||||
std::set<uint32_t, BodySpot> spots;
|
std::set<uint32_t, Spot> spots;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
#endif // BODYPART_H
|
#endif // BODYPART_H
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef _MARIONETTE_H
|
||||||
|
#define _MARIONETTE_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace mrntt {
|
||||||
|
|
||||||
|
extern std::atomic<int> exitCode;
|
||||||
|
|
||||||
|
class Marionette
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
void exitMarionetteLoop();
|
||||||
|
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
struct CrtCommandLineArgs
|
||||||
|
{
|
||||||
|
CrtCommandLineArgs(int argc, char *argv[], char *envp[])
|
||||||
|
: argc(argc), argv(argv), envp(envp)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
char **envp;
|
||||||
|
|
||||||
|
static void set(int argc, char *argv[], char *envp[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _MARIONETTE_H
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef _MENTAL_ENTITY_H
|
||||||
|
#define _MENTAL_ENTITY_H
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MentalEntities refer to all mental content that needs to be persistently
|
||||||
|
* stored to represent cognitive and personna state. This includes such things
|
||||||
|
* as value judgements, comparators, logical ops, DB links, etc.
|
||||||
|
*
|
||||||
|
* Mental Existents are a narrower subset of MentalEntities that represent
|
||||||
|
* implicit existents and perceptual data, both implexed and artificed.
|
||||||
|
*/
|
||||||
|
class MentalEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Id = uint32_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MentalEntity(const Id id) : id(id) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Id id;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#ifndef _MENTENON_H
|
||||||
|
#define _MENTENON_H
|
||||||
|
|
||||||
|
#include "mentalEntity.h"
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MentalPhenomena are content of the mind that specifically represents
|
||||||
|
* phenomena. I.e: perceptual data, whether structural or implicative. All
|
||||||
|
* Menten are Mentities, but not all Mentities are Menten.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct MentalPhenomenon
|
||||||
|
: public MentalEntity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MentalPhenomenon(const MentalEntity::Id id)
|
||||||
|
: MentalEntity(id)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef MentalPhenomenon Mentenon;
|
||||||
|
|
||||||
|
class ImplexedMentalPhenomenon
|
||||||
|
: public MentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ImplexedMentalPhenomenon Implexon;
|
||||||
|
|
||||||
|
class ArtificedMentalPhenomenon
|
||||||
|
: public MentalPhenomenon
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ArtificedMentalPhenomenon Artifenon;
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _MENTENON_H
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef _MIND_H
|
||||||
|
#define _MIND_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <director/director.h>
|
||||||
|
#include <simulator/simulator.h>
|
||||||
|
#include <componentThread.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind : public std::enable_shared_from_this<Mind>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mind(void);
|
||||||
|
~Mind(void) = default;
|
||||||
|
|
||||||
|
void initialize(void);
|
||||||
|
void execute(void);
|
||||||
|
void finalizeReq(std::function<void()> callback);
|
||||||
|
|
||||||
|
// ComponentThread access methods
|
||||||
|
std::shared_ptr<ComponentThread> getComponentThread(
|
||||||
|
ComponentThread::ThreadId id) const;
|
||||||
|
std::shared_ptr<ComponentThread> getComponentThread(
|
||||||
|
const std::string& name) const;
|
||||||
|
// Get all this Mind's component threads.
|
||||||
|
std::vector<std::shared_ptr<ComponentThread>> getMindThreads() const;
|
||||||
|
|
||||||
|
// Thread management methods (moved from ComponentThread)
|
||||||
|
void startAllMindThreadsReq(std::function<void()> callback = nullptr);
|
||||||
|
void pauseAllMindThreadsReq(std::function<void()> callback = nullptr);
|
||||||
|
void resumeAllMindThreadsReq(std::function<void()> callback = nullptr);
|
||||||
|
void exitAllMindThreadsReq(std::function<void()> callback = nullptr);
|
||||||
|
void joltAllMindThreadsReq(std::function<void()> callback = nullptr);
|
||||||
|
|
||||||
|
// CPU distribution method
|
||||||
|
void distributeAndPinThreadsAcrossCpus();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::thread directorThread;
|
||||||
|
std::thread simulatorThread;
|
||||||
|
std::thread subconsciousThread;
|
||||||
|
|
||||||
|
director::Director director;
|
||||||
|
simulator::Simulator canvas;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Indicates whether all mind threads have been JOLTed at least once.
|
||||||
|
*
|
||||||
|
* JOLTing serves two critical purposes:
|
||||||
|
*
|
||||||
|
* 1. **Global Constructor Sequencing**: Since pthreads begin executing while
|
||||||
|
* global constructors are still being executed, globally defined pthreads
|
||||||
|
* cannot depend on global objects having been constructed. JOLTing is done
|
||||||
|
* by the CRT's main thread within main(), which provides a sequencing
|
||||||
|
* guarantee that global constructors have been called.
|
||||||
|
*
|
||||||
|
* 2. **shared_from_this Safety**: shared_from_this() requires a prior
|
||||||
|
* shared_ptr handle to be established. The global list of
|
||||||
|
* shared_ptr<ComponentThread> guarantees that at least one shared_ptr to
|
||||||
|
* each ComponentThread has been initialized before JOLTing occurs.
|
||||||
|
*
|
||||||
|
* This flag ensures that JOLTing happens exactly once and provides
|
||||||
|
* a synchronization point for the entire system initialization.
|
||||||
|
*/
|
||||||
|
bool threadsHaveBeenJolted = false;
|
||||||
|
// Collection of ComponentThread instances (excluding marionette)
|
||||||
|
std::vector<std::shared_ptr<ComponentThread>> componentThreads;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global Mind instance will be defined in marionette.cpp
|
||||||
|
extern std::shared_ptr<Mind> globalMind;
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef OPTS_H
|
||||||
|
#define OPTS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
// Define a class to hold the options and parse arguments
|
||||||
|
class OptionParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionParser() : verbose(false), printUsage(false) {}
|
||||||
|
~OptionParser() = default;
|
||||||
|
|
||||||
|
void parseArguments(int argc, char *argv[], char **envp);
|
||||||
|
std::string stringifyOptions(void) const;
|
||||||
|
std::string getUsage() const;
|
||||||
|
|
||||||
|
static OptionParser &getOptions(void)
|
||||||
|
{
|
||||||
|
static OptionParser options;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Exception : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Exception() = default;
|
||||||
|
~Exception() override = default;
|
||||||
|
const char* what() const noexcept override = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string argv0;
|
||||||
|
std::vector<std::string> senseApiLibPath;
|
||||||
|
std::vector<std::string> senseApiLibs;
|
||||||
|
std::string dapSpecs;
|
||||||
|
std::vector<std::string> dapSpecFiles;
|
||||||
|
bool verbose, printUsage;
|
||||||
|
|
||||||
|
static struct option longOptions[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class OptionsParserError
|
||||||
|
: public std::invalid_argument, public OptionParser::Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OptionsParserError(
|
||||||
|
const std::string& errorMessage, const OptionParser& parser);
|
||||||
|
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JustPrintUsageNoError
|
||||||
|
: public OptionParser::Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit JustPrintUsageNoError(const OptionParser& parser);
|
||||||
|
const char* what() const noexcept override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string message;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // OPTS_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user