102 Commits

Author SHA1 Message Date
hayodea 0559d9ea42 Build: Update CMake project version: v0.00.004 2025-09-03 15:30:30 -04:00
hayodea 1c78fc5c31 Cmdline: Update specs to mention DAP 2025-09-03 15:28:58 -04:00
hayodea 3b224501c7 VSCode: Add launch tasks for debugging in vscode 2025-09-03 14:56:49 -04:00
hayodea 0dc8abaa28 Rework: Modularize Mind
Now we have modularized the Mind class to contain all of its
ComponentThreads. This enables us to run multiple mind instances
within the same SMO process, at least in theory.

We probably won't actually do this, but we want to ensure that the
design is clean enough to enable it.
2025-09-03 14:56:00 -04:00
hayodea eb069c4a96 LRU-LIFO: Add Lufos, add LUFOs to Director
This represents our realization that we can represent qualia
inputs using LRU LIFOs
2025-09-02 17:02:50 -04:00
hayodea 32e76c2ca5 Goal: Goals are now Comblogic exprs 2025-09-02 17:01:47 -04:00
hayodea 4827177703 Add combinational logic and concept classes 2025-09-02 17:01:01 -04:00
hayodea d36d03dcc3 Logic/Concepts.h: Add combinational logic expr classes 2025-09-02 13:04:54 -04:00
hayodea 6362298016 Rename senseApiXcbWindow=>xcbWindow 2025-08-29 20:24:04 -04:00
hayodea 6314b0182a VSCode config: indentation should be 4-width tabs 2025-08-29 20:23:44 -04:00
hayodea 0fefa5be7f Add synchronization notes for queuespin mechanism 2025-08-29 19:59:22 -04:00
hayodea 7ea31cdb8d DAPSpecParser: Get rid of this warning 2025-08-29 17:52:39 -04:00
hayodea d217354689 Add our first async thread sequence
Gave me some ideas about how things should be structured. Apparently
merely using region-data-locked threads doesn't eliminate the need
for synchronization/locking. It just means your synchronization is much
lighter, in the form of localized variables.

It seems we'll need to maintain boolean trackers for certain
operations that shouldn't be performed concomitantly, and deny
the caller access to those operations in order to preserve
data sanity.

I guess we still ended up using locking after all. Tbh, I'm not even
sure this will make things end up being lighter: we may have to bounce
requests off, or perhaps re-enqueue them into the queue?

So maybe instead of bouncing requests off, we could re-add them to the
rear of the queue when they conflict with an ongoing request.
2025-08-29 17:42:13 -04:00
hayodea bb7be7fb3c Rename: senseDeviceSpecs => deviceAttachmentSpecs 2025-08-29 16:33:17 -04:00
hayodea ee8fca3008 Add todo 2025-08-29 16:13:03 -04:00
hayodea 525af45fd4 VSCode config: use 8-width tabs 2025-08-29 16:12:47 -04:00
hayodea 3ff329a553 Rename: DeviceSpec=>DAP Spec 2025-08-29 16:12:30 -04:00
hayodea 66257bcd0e Rename DSL: DeviceAttachmentSpec => deviceAttachmentPipeSpec
The new name is nicer and more distinguishing.
2025-08-29 15:55:11 -04:00
hayodea 6ef86eea05 Rename DSL: deviceSpec => deviceAttachmentSpec
This language is used broadly to specify how to attach (and thus
also how to detach) devices to/from Salmanoff. The next bit of work
we'll do is split off the DSL parsing from the management of the
list of parsed binary attached spec objects.

We'll be creating a PipeDeviceAttachmentParser, and later on when
we support URDF, we'll create a URDFDeviceAttachmentParser.
2025-08-29 15:16:11 -04:00
hayodea 8f41e164a2 Rename readDeviceFile=>readDeviceSpecFile 2025-08-29 13:29:18 -04:00
hayodea b9ca38bff1 Make senseApiLibs a vector<sh_ptr>; getters return sh_ptr
Proper reference and object lifetime management.
2025-08-29 13:20:15 -04:00
hayodea e024ccdf95 Add todo 2025-08-29 12:51:52 -04:00
hayodea f3f2384f9b SenseApiMgr: Refcount device spec objects 2025-08-29 09:50:26 -04:00
hayodea cd63593ae5 CMake: Add support for cross compiling to aarch64-linux-gnu 2025-08-23 20:59:39 -04:00
hayodea 58dbc7e320 Gitignore: Ignore all build dirs 2025-08-23 19:38:52 -04:00
hayodea e3795c4233 Fix includes to use angle brackets 2025-08-15 14:01:46 -04:00
hayodea edc198dd00 Document the purpose and mechanics behind JOLTing 2025-08-15 13:16:23 -04:00
hayodea 2bf7390f97 Rename implexa.h => mentenon.h 2025-08-15 09:43:38 -04:00
hayodea 1ea1b4b9f6 Fix typo 2025-08-15 09:41:34 -04:00
hayodea c14208f6ce Ignore /build dir 2025-08-15 09:38:43 -04:00
hayodea f4ff8f0e40 Delete superfluous files 2025-08-15 09:36:24 -04:00
hayodea ba3841c30b Rename classes from MentalExistent=>MentalPhenomenon 2025-08-13 16:06:34 -04:00
hayodea 4a8cb12294 Mrntt: initializeSalmanoff exceptions handled in outermode catch block
We don't post a message to the event loop telling it to execute
initializeSalmanoff anymore. We now execute it in the main control
flow.

Also, we've unified the logic to call finalizeReq() in response to
exceptions in the outermost try block.
2025-08-13 10:03:18 -04:00
hayodea b6b2ce7ada Cmdline: use exceptions for control flow
This is generally frowned upon but it makes this code 10x cleaner.
We handle commandLine usage msg printing by using exceptions for
control flow. This allows us to centralize the logic for killing
the Mind threads in one place. At least with respect to printing
the usage msg.
2025-08-13 09:49:54 -04:00
hayodea 7bee9b07ae Mrntt: Don't call Mind::initialize after exiting loop. 2025-08-13 09:08:57 -04:00
hayodea d26b791dd2 Handle SIGINT (CTL+C) by gracefully shutting down 2025-08-10 14:07:27 -04:00
hayodea 7579446388 Mrntt: set Mrntt::exitCode = EXIT_FAILURE for all exceptions 2025-08-10 13:40:13 -04:00
hayodea 099d60bcc4 Moved JOLT state tracking into ComponentThread:: 2025-08-10 13:29:34 -04:00
hayodea 42b32f27e6 Remove test exception 2025-08-10 13:17:11 -04:00
hayodea c457ee7aca smo::Mind instance now global; track & manage JOLT state in Mind
We moved the instance of smo::Mind to global scope. I suppose we'll
only support one instance of Mind per SMO process at least for now.

We now track the state of Mind threads' JOLT-waiting. This allows us
to centralize the Mind thread shutdown logic. Mind::finalizeReq()
now takes care of all Mind thread shutdown state logic by tracking
whether Mind threads need to be JOLTed first before being told to
exit.
2025-08-10 13:12:17 -04:00
hayodea e2e589dc17 ExceptionInd: Remove duplicate invocations 2025-08-03 10:33:34 -04:00
hayodea d4898bbca1 Add comments 2025-08-03 10:22:28 -04:00
hayodea e836b2bf32 Cmdline: Suppress getopt stderr msg, bubble exception upward instead 2025-08-03 10:19:22 -04:00
hayodea fef73692f7 Mrntt: Shut down mind threads before printing usage & exiting 2025-08-03 09:57:29 -04:00
hayodea 285b63b618 Mind: Distribute and pin Mind threads to CPUs
At startup, Marionette will distribute and pin the Mind
threads across the available CPUs, warning if it couldn't
do so.
2025-08-03 09:18:45 -04:00
hayodea 1deb92a416 CompThreads: create execOpOnAllMindThreads common helper
This allows us to execute an op on all mind threads without having
to repeatedly write loops. We've implemented wrappers to handle
start, pause, resume, exit and JOLT sequences.
2025-08-03 08:22:45 -04:00
hayodea 6f6fa77498 Get rid of enum Quale::Type, create BoundingQuale; use typeid()
We just learned about typeid. Apparently it was either not mentioned
in the Stroupstrup book or we totally missed it.
2025-08-03 05:23:05 -04:00
hayodea 79825e4da3 Make Quale derive from MentalExistent. 2025-08-03 05:06:14 -04:00
hayodea 6114a2648d Add MentalExistent hierarchy of classes.
These differ from the MentalEntity class hierarchy in that
MentalExistents are a narrower subset of MentalEntities. MentalEntities
refer to all mental content that needs to be persistently stored to
represent cognitive and personna state.

MentalExistents are content of the mind that specifically represents
existents. I.e: perceptual data, whether structural or implicative.
2025-08-03 05:06:14 -04:00
hayodea 4a3daaf403 Update README.md 2025-08-02 01:26:06 +00:00
hayodea 49c8b5bca1 SenseApiMgr: Print dev info when detaching, use early return pattern 2025-07-30 10:33:50 -04:00
hayodea a2598e80fd Mrntt: Call mind.finalize() on mind object. 2025-07-30 10:14:18 -04:00
hayodea 4fde28dad8 Mrntt: Call shutdownSalmanoff after exiting main loop
We moved initializeSalmanoff and shutdownSalmanoff into
salmanoff.cpp. Now we also invoke shutdownSalmanoff when exiting
to destroy subsystems and components gracefully.

This fixes the segfault that was thrown on every program exit
when xcbWindow had captured a window.
2025-07-30 10:09:25 -04:00
hayodea e276fcbdce Mrntt: use keepLooping after exception; Mind: split code from mrntt
Mrntt now has the event loop structure required to orderly shut itself
down when it itself generates an exception. We can now post a message
within the catch{} blocks for Mrntt's event loop, telling Mrntt
to shut down the Mind threads and then shut itself down.

We also split the code to initialize threads etc out of mrntt and
put it into the Mind:: namespace.
2025-07-30 09:09:38 -04:00
hayodea 36c79f3a2e Threading: run all code in PThreads, add JOLTing & exception bubbling
This commit significantly restructures the way we setup threading in
SMO. We now don't use the CRT main() thread at all. It's only used
as a mechanism to ensure that Marionette doesn't execute before
global constructors have been executed.

JOLTing:

This is a simple ASIO post()ed message that makes each thread setup
its thread-local data pointer to its own ComponentThread object,
and then enter its main ASIO run() loop to await commands from
Marionette.

Exception bubbling:

We now cleanly cause mind threads to report their exceptions
to marionette, so that marionette can cleanly shut the mind down
in an orderly fashion.

Thread Control messaging API:

A namespace of asynchronous messages to be post()ed to threads to
control them. It enables us to pause and resume threads. This will
be very useful for Marionette when we add the ability for it to
suspend Salmanoff's running mind, inject new goals, inspect current
state, etc; and then resume the mind's execution.
2025-07-28 07:20:44 -04:00
hayodea 513405a831 Cmdline: Rename senseApiLibs, senseApiPaths to apiLibs, apiLibPaths 2025-07-25 01:51:36 -04:00
hayodea 7b962a75d3 VSCode: update config 2025-07-25 01:22:13 -04:00
hayodea 270437fdd4 xcbOrg/Window: Destroy connections when no longer in use 2025-07-25 01:21:26 -04:00
hayodea a17c940377 xcbWindow: Use angle bracketed includes 2025-07-24 06:15:09 -04:00
hayodea b28239550e xcbWindow: Group xcbXorg DLL state together 2025-07-24 06:14:08 -04:00
hayodea 1e17b83061 Split xcbXorg into xcbXorg and xcbWindow 2025-07-24 06:00:35 -04:00
hayodea 1bf5f46404 Provide dlopen() path searching hook to senseApi libs 2025-07-24 02:12:31 -04:00
hayodea 064dc43fbc SenseApiMgr: Permit multiple lib search paths 2025-07-23 00:12:50 -04:00
hayodea 020a4968e5 CMake: Add config.h.in 2025-07-22 23:28:59 -04:00
hayodea d0aa8e2306 Rename hk=>smo 2025-07-22 06:48:04 -04:00
hayodea 79f3e84ff8 CMake: update include path here? 2025-07-22 06:17:18 -04:00
hayodea 756571b9b4 Rename hcore=>smocore 2025-07-22 06:15:12 -04:00
hayodea 9c16aeeb55 Docs: rename harikoff=>salmanoff 2025-07-22 06:03:47 -04:00
hayodea d6a0b0301e Build: Rename Harikoff=>Salmanoff 2025-07-22 06:00:00 -04:00
hayodea e87656fd12 Fix build error from non-POD initializer list 2025-07-22 05:50:19 -04:00
hayodea f06aeb6c9b Formatting 2025-07-22 05:48:39 -04:00
hayodea c58d422158 Add images 2025-07-22 05:47:33 -04:00
hayodea 8dfb1e5b2f Use smaller PNG 2025-07-22 05:46:02 -04:00
hayodea 50b8aaf34d Update README for logo 2025-07-22 05:40:51 -04:00
hayodea 0f5e499d7c Add new logo for Salmanoff 2025-07-22 05:39:19 -04:00
hayodea 710749c399 Delete the autotools build system 2025-07-22 05:28:42 -04:00
hayodea 3503cce0db CMake: Check for libDl, conditionally check for libXCB 2025-07-22 05:19:26 -04:00
hayodea 90a0eebdd8 Add cscope ignore to .gitignore 2025-07-22 03:08:50 -04:00
hayodea 1540af1e74 Add temporary gitignore for the old autotools build dir 2025-07-22 02:46:43 -04:00
hayodea 065b2593f4 Add new CMake build system 2025-07-22 02:46:16 -04:00
hayodea e7974db324 Add Marionette 2025-07-22 02:03:45 -04:00
hayodea 336094ef90 Marionette: Create include dir and move body map headers in 2025-07-22 02:03:45 -04:00
hayodea d43a8af6bd Build: Print out the enabled common and wilzor libs 2025-07-22 02:03:45 -04:00
hayodea 37ad6995c3 Build: Add SenseApi DeepLIO2 Lidar fusion algo 2025-07-22 02:03:45 -04:00
hayodea c9e8a9f1fb Build: senseApis: Update help messages 2025-07-22 02:03:45 -04:00
hayodea dacc050bf9 Livox and R3Live shouldn't be over Eth intrinsically 2025-07-22 02:03:45 -04:00
hayodea f8825942b1 Add senseApis for Lidar devs and fusion APIs 2025-07-22 02:03:45 -04:00
hayodea e201b5e695 Build: Support common+sense+wilzor API libs; Move xcbXorg into commonLibs
xcbXorg is a connection manager lib that'll be used in common by all of
the xcb API frontends: xcbMouse, xcbWindow and xcbKeyboard. We moved
it into commonLibs to make it make more sense.

We also cleaned up the M4 scripting around AC_ARG_VAR-ing new common
libs as well as sense/wilzor libs.
2025-07-22 02:03:45 -04:00
hayodea 29a1e1ecf2 Docs:negtrin path: Add new thoughts 2025-07-22 02:03:45 -04:00
hayodea a5c2f47e9f Add design thoughts for intrins, compartmentalization, value-judgment 2025-07-22 02:03:45 -04:00
hayodea 42f55bb324 SenseApiDesc: Delete Sal_Mgmt_HkOps & document iface
We don't need the Sal_Mgmt_HkOps anymore because we won't
be using a callback model anymore. We'll be enqueuing messages.
2025-07-22 02:03:45 -04:00
hayodea 1450d745ab SenseApiDesc: use CPP concat to reduce typos 2025-07-22 02:03:45 -04:00
hayodea 76141e3a92 Fix indentation 2025-07-22 02:03:45 -04:00
hayodea 36592293dd DevSpec:lex: fix indentation 2025-07-22 02:03:45 -04:00
hayodea f1696f8272 DevSpec:lex: Remove annotation comment by GPT 2025-07-22 02:03:45 -04:00
hayodea 99c126a08c DevSpec:lex: Fix whitespace around EQUALS, fix backslash at EOF
* We had a prior issue where EQUALS would require that there be no
  whitespace between itself and its operands on either side. We got
  a bad solution from ChatGPT 4o. We got a proper solution now from
  o1.
* Previously, if a string ended with a backslash right before EOF, the
  backslash would be included. Now it will be dropped.
* Merge the two regexes for ignoring whitespace into one.
2025-07-22 02:03:45 -04:00
hayodea 293c1054d1 ComponentThreads: Add 2 new threads: body, world; comment threads.
We add 2 new threads for handling the interoceptors and extrospector
events. Also add comments explaining the purpose and role of each of
these major threads.
2025-07-22 02:03:45 -04:00
hayodea 38298a8ef8 DevSpec:Lex: silence warning about yyinput 2025-07-22 02:03:45 -04:00
hayodea 2b8b176038 xcbXorg: Add comments to major classes and funcs 2025-07-22 02:03:45 -04:00
hayodea 76e465bd1d devSpec:lex: Allow backslash escaping of strings
Now we can escape special characters without issue.
2025-07-22 02:03:45 -04:00
latentprion ead7d8ff5f Add findxwindow script 2025-07-21 23:24:53 -04:00
hayodea 9cc7a6685c Build: Add -Woverride with AM_INIT_AUTOMAKE 2025-01-31 14:45:52 -04:00
128 changed files with 4197 additions and 11311 deletions
+5 -1
View File
@@ -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
+1 -1
View File
@@ -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"
+145 -11
View File
@@ -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"
} }
] ]
} }
+6 -2
View File
@@ -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
} }
+53 -43
View File
@@ -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"
}
} }
] ]
} }
+67
View File
@@ -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)
-9
View File
@@ -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
+9 -4
View File
@@ -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! ![Salmanoff project](docs/img/salmanoff-logo-dark-512.png)
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.
+37
View File
@@ -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")
+1
View File
@@ -0,0 +1 @@
add_subdirectory(xcbXorg)
+20
View File
@@ -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()
+292
View File
@@ -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());
}
}
+184
View File
@@ -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
-88
View File
@@ -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
+1 -1
View File
@@ -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.
+116
View File
@@ -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,9 +37,9 @@ 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`:
If there's more than one parameter item in a list of `api-params` or If there's more than one parameter item in a list of `api-params` or
`provider-params`, then the individual items in a list of `api-param` or `provider-params`, then the individual items in a list of `api-param` or
@@ -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

-6
View File
@@ -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
-69
View File
@@ -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
-18
View File
@@ -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
-37
View File
@@ -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
-69
View File
@@ -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
-43
View File
@@ -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
}
-64
View File
@@ -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 &part;
std::vector<BodySpotImpactEntry> entries;
};
class BodyPartMsg
: public BodyMessage
{
public:
BodyPartMsg(const BodyPart& _part)
:part(_part)
{}
public:
const BodyPart& part;
};
#endif // BODY_MESSAGE_H
-28
View File
@@ -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
-69
View File
@@ -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
-11
View File
@@ -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
-21
View File
@@ -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
-14
View File
@@ -1,14 +0,0 @@
#ifndef _MENTAL_ENTITY_H
#define _MENTAL_ENTITY_H
namespace hk {
class MentalEntity
{
public:
using Id = uint32_t;
};
} // namespace hk
#endif
-28
View File
@@ -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
-36
View File
@@ -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
-39
View File
@@ -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
-2
View File
@@ -1,2 +0,0 @@
#include <mind.h>
-120
View File
@@ -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();
}
-4
View File
@@ -1,4 +0,0 @@
AM_CPPFLAGS+= -I"$(top_srcdir)/hcore/include"
noinst_LIBRARIES=libsenseApis.a
libsenseApis_a_SOURCES=senseApiManager.cpp
+47
View File
@@ -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 */
+8 -6
View File
@@ -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
View File
@@ -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__
-18
View File
@@ -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
])
-18
View File
@@ -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
])
-95
View File
@@ -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
])
-305
View File
@@ -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"
])
-8427
View File
File diff suppressed because it is too large Load Diff
-437
View File
@@ -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])])
-124
View File
@@ -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
])
-24
View File
@@ -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)
])
-99
View File
@@ -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])])
-22
View File
@@ -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]
)
+19 -100
View File
@@ -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 '"
catch (const std::exception& e) << smo::mrntt::exitCode << "'\n";
{ return smo::mrntt::exitCode;
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
+54
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
add_subdirectory(xcbWindow)
-1
View File
@@ -1 +0,0 @@
SUBDIRS = @SENSEAPIS_ENABLED@
+27
View File
@@ -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()
+355
View File
@@ -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(),
[&paramName](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;
}
+59
View File
@@ -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
-6
View File
@@ -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
-527
View File
@@ -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(),
[&paramName](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;
}
-22
View File
@@ -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
+18
View File
@@ -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)
+300
View File
@@ -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
+29
View File
@@ -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
}
@@ -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;
} }
; ;
+114
View File
@@ -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
+135
View File
@@ -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
+51
View File
@@ -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
+36
View File
@@ -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
+43
View File
@@ -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
+65
View File
@@ -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
+32
View File
@@ -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
+17
View File
@@ -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
+23
View File
@@ -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 &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
+34
View File
@@ -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
+35
View File
@@ -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
+28
View File
@@ -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
+41
View File
@@ -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
+83
View File
@@ -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
+67
View File
@@ -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