Rename hcore=>smocore

This commit is contained in:
2025-07-22 06:15:12 -04:00
parent 9c16aeeb55
commit 756571b9b4
54 changed files with 6 additions and 6 deletions
+14
View File
@@ -0,0 +1,14 @@
# Core library
add_library(smocore STATIC
mind.cpp
opts.cpp
componentThread.cpp
)
target_include_directories(smocore PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
add_subdirectory(deviceManager)
add_subdirectory(senseApis)
add_subdirectory(marionette)
+98
View File
@@ -0,0 +1,98 @@
#include <iostream>
#include <componentThread.h>
namespace hk {
namespace director {
/* The director is the seat of volition in Harikoff. It receives sensor
* events from the body and world, and uses them to direct its implexors
* to implex new menties. It then loads the menties into canvas for simulation
* and correlation with intrins, in order to form new attrimotions and
* menties.
*/
ComponentThread director;
}
namespace simulator {
/* The canvas is the simulation engine in Harikoff. It receives menties and
* simulates them in accordance with the instructions from director. It then
* re-renders them into perception for director to get feedback.
*/
ComponentThread canvas;
}
namespace subconscious {
/* The subconscious is the seat of memory in Harikoff. It receives menties
* from director and stores them in memory for later recall.
*/
ComponentThread subconscious;
}
namespace body {
/* The body is a thread that polls, processes, and sends interoceptive sensor
* events to director. It enables these events to occur asynchronously,
* indepdendent any actions that the other threads are taking.
*/
ComponentThread body;
}
namespace world {
/* The world performs the same functions as the body, but for extrospective
* sensor events.
*/
ComponentThread world;
}
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},
{body::body.thread.get_id(), body::body},
{world::world.thread.get_id(), world::world}
};
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
+29
View File
@@ -0,0 +1,29 @@
# Flex/Bison generated files
set(LEX_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/deviceSpecl.cc)
set(YACC_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/deviceSpecp.cc)
set(YACC_HEADER ${CMAKE_CURRENT_BINARY_DIR}/deviceSpecp.hh)
# Generate Flex/Bison files using custom commands
add_custom_command(
OUTPUT ${LEX_OUTPUT}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/deviceSpecl.ll ${YACC_HEADER}
COMMAND ${FLEX_EXECUTABLE} --header-file=${CMAKE_CURRENT_BINARY_DIR}/deviceSpecl.hh -o ${LEX_OUTPUT} ${CMAKE_CURRENT_SOURCE_DIR}/deviceSpecl.ll
COMMENT "Generating deviceSpecl.cc from deviceSpecl.ll"
)
add_custom_command(
OUTPUT ${YACC_OUTPUT} ${YACC_HEADER}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/deviceSpecp.yy
COMMAND ${BISON_EXECUTABLE} -p deviceSpecp --header=${YACC_HEADER} -o ${YACC_OUTPUT} ${CMAKE_CURRENT_SOURCE_DIR}/deviceSpecp.yy
COMMENT "Generating deviceSpecp.cc and deviceSpecp.hh from deviceSpecp.yy"
)
# Device manager library
add_library(deviceManager STATIC
deviceManager.cpp
deviceSpecParser.cpp
${LEX_OUTPUT}
${YACC_OUTPUT}
)
target_include_directories(deviceManager PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
+37
View File
@@ -0,0 +1,37 @@
#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
@@ -0,0 +1,71 @@
#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
+62
View File
@@ -0,0 +1,62 @@
%option prefix="deviceSpecl"
%option nounput
%option noinput
%{
#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; }
"=" { 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]);
}
deviceSpecplval.str = strdup(unescaped.c_str());
return STRING;
}
[ \t\r\n]+ { /* ignore all whitespace, including newlines */ }
. { return yytext[0]; }
%%
int deviceSpeclwrap(void)
{
return 1; // Indicate end of input
}
+155
View File
@@ -0,0 +1,155 @@
%{
#include <vector>
#include <utility>
#include <string>
#include <cstring>
#include <cstdlib>
#include <stdexcept>
#include <memory>
#include <functional>
#include <user/senseDeviceSpec.h>
#include <deviceManager/deviceManager.h>
#ifndef yylex
/* We use different prefixes for the lexer and parser.
* * Our lexer's prefix is deviceSpecl.
* * Our parser's prefix is deviceSpecp.
*
* 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
* lexer must have the same prefix as the parser they generate. So we just use
* this #define below to override yacc/bison's presumed prefix for the lexer.
*/
#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
#undef yylex
#define yylex deviceSpecllex
#ifdef yytext
#undef yytext
#endif
#define yytext deviceSpecltext
// Declare the symbols that our lexer will export.
int yylex(void);
extern char* yytext; // Declare yytext to access the current token text
void yyerror(const char *message)
{
throw std::runtime_error(
std::string("deviceSpec parser error: ")
+ std::string(message)
+ " at token: " + std::string(yytext));
}
%}
%union {
char* str;
char chr;
hk::device::SenseDeviceSpec* sensorSpec;
hk::device::InteroceptorDeviceSpec* interoceptorSpec;
hk::device::ExtrospectorDeviceSpec* extrospectorSpec;
std::vector<std::pair<std::string,std::string>>* paramVector;
std::pair<std::string,std::string>* param;
}
%token <str> STRING
%token PIPE DOUBLE_PIPE LPAREN RPAREN
%token <chr> KEYWORD_SPECTYPE_ACTUATOR
%token <chr> KEYWORD_SPECTYPE_EXTROSPECTOR KEYWORD_SPECTYPE_INTEROSPECTOR
%token EQUALS // Add new token for '='
%type <paramVector> params opt_params
%type <param> param
%type <sensorSpec> spec_body
%type <interoceptorSpec> interoceptor_spec
%type <extrospectorSpec> extrospector_spec
%%
file: /* NOTHING */
| sensor_specs
;
sensor_specs:
sensor_spec
| sensor_specs DOUBLE_PIPE sensor_spec
;
sensor_spec:
interoceptor_spec
| extrospector_spec
;
interoceptor_spec:
KEYWORD_SPECTYPE_INTEROSPECTOR PIPE spec_body {
auto spec = std::make_shared<hk::device::InteroceptorDeviceSpec>(
*static_cast<hk::device::InteroceptorDeviceSpec *>($3));
spec->sensorType = $1;
hk::device::DeviceManager::interoceptorDeviceSpecs.push_back(spec);
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
delete $3;
}
;
extrospector_spec:
KEYWORD_SPECTYPE_EXTROSPECTOR PIPE spec_body {
auto spec = std::make_shared<hk::device::ExtrospectorDeviceSpec>(
*static_cast<hk::device::ExtrospectorDeviceSpec *>($3));
spec->sensorType = $1;
hk::device::DeviceManager::extrospectorDeviceSpecs.push_back(spec);
hk::device::DeviceManager::senseDeviceSpecs.push_back(spec);
delete $3;
}
;
spec_body:
STRING PIPE STRING LPAREN opt_params RPAREN PIPE STRING LPAREN opt_params RPAREN PIPE STRING {
$$ = new hk::device::SenseDeviceSpec();
$$->sensorType = '\0';
$$->implexor = std::string($1);
$$->api = std::string($3);
$$->apiParams = std::move(*$5);
$$->provider = std::string($8);
$$->providerParams = std::move(*$10);
$$->deviceSelector = std::string($13);
delete $5;
delete $10;
}
;
opt_params:
params
| /* empty */ { $$ = new std::vector<std::pair<std::string,std::string>>(); }
;
params:
param {
$$ = new std::vector<std::pair<std::string,std::string>>();
$$->push_back(*$1);
delete $1;
}
| params PIPE param {
$$ = $1;
$$->push_back(*$3);
delete $3;
}
;
param:
STRING {
$$ = new std::pair<std::string,std::string>($1, "");
}
| STRING EQUALS {
$$ = new std::pair<std::string,std::string>($1, "");
}
| STRING EQUALS STRING {
$$ = new std::pair<std::string,std::string>($1, $3);
}
;
%%
+15
View File
@@ -0,0 +1,15 @@
#ifndef _ASSOCIATION_H
#define _ASSOCIATION_H
#include <chronomenon.h>
#include <existent.h>
class Association
{
public:
Association(Quale quale, Chronomenon chron);
Association(Quale quale, Existent ex);
Association(Quale quale, Existent ex);
};
#endif
+25
View File
@@ -0,0 +1,25 @@
#ifndef _ATTENTION_GRABBER_H
#define _ATTENTION_GRABBER_H
#include <cstdbool>
#include <attentionTrigger.h>
#include <chronomenon.h>
class AttentionGrabber
{
public:
AttentionGrabber(AttentionTrigger cause, Chronomenon chron)
: isNull(false)
{
}
void setNull(void) { isNull = true; }
int operator!(void) { return isNull; }
public:
AttentionTrigger cause;
Chronomenon chron;
bool isNull;
};
#endif
+7
View File
@@ -0,0 +1,7 @@
#ifndef _ATTENTION_TRIGGER_H
#define _ATTENTION_TRIGGER_H
class AttentionTrigger
{};
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef _CHRONOMENON_H
#define _CHRONOMENON_H
#include <vector>
#include <qualeBundle.h>
#include <mentalEntity.h>
class Chronomenon
: public MentalEntity
{
public:
class Timestamp
{
uintptr_t value;
};
class Duration
{
uintptr_t value;
};
public:
Chronomenon extract(Timestamp start, Duration len);
public:
std::vector<QualeBundle> qualia;
};
#endif
+69
View File
@@ -0,0 +1,69 @@
#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
@@ -0,0 +1,11 @@
#ifndef _CONCEPT_H
#define _CONCEPT_H
#include <mentalEntity.h>
class Concept
: public MentalEntity
{
};
#endif
@@ -0,0 +1,48 @@
#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
+79
View File
@@ -0,0 +1,79 @@
#ifndef DIRECTOR_COMMANDLIST_H
#define DIRECTOR_COMMANDLIST_H
#include <vector>
#include <cstdint>
#include <mentalEntity.h>
namespace hk {
namespace director {
/**
* @brief Base class for all commands, storing a reference to a mental entity ID.
*
* Derived classes can extend this to include additional command-specific
* data and behavior.
*/
class Command
{
public:
Command(const MentalEntity::Id menty) : menty(menty) {}
public:
const MentalEntity::Id menty;
};
class CommandList
{
public:
CommandList() = default;
/**
* @brief Used by Director to point to the currently executing command.
*
* director::Director maintains an internal cursor. As it executes commands
* from its internal command list, it advances the cursor to the current
* command before executing it.
*/
class Cursor
{
public:
Cursor(CommandList& commandList)
: commandList(commandList), iter(commandList.commands.begin())
{}
void reset() { iter = commandList.commands.begin(); }
bool hasNext() const { return iter != commandList.commands.end(); }
Cursor next() { return ++(*this); }
Cursor& operator++() {
++iter;
return *this;
}
private:
Cursor(
CommandList& commandList,
std::vector<Command>::iterator iter)
: commandList(commandList), iter(iter)
{}
public:
CommandList& commandList;
std::vector<Command>::iterator iter;
};
Cursor getCursor() { return Cursor(*this); }
void addCommand(const Command& command)
{
commands.push_back(command);
}
public:
std::vector<Command> commands;
};
} // namespace director
} // namespace hk
#endif // DIRECTOR_COMMANDLIST_H
+21
View File
@@ -0,0 +1,21 @@
#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
+17
View File
@@ -0,0 +1,17 @@
#ifndef _GOAL_H
#define _GOAL_H
#include <simulator/scene.h>
namespace hk {
class Goal
: public simulator::Scene {
public:
Goal() = default;
~Goal() = default;
};
} // namespace hk
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef IMPLIX_H
#define IMPLIX_H
namespace hk {
namespace implix {
class Implix
{
public:
Implix() = default;
~Implix() = default;
};
} // namespace implix
} // namespace hk
#endif // IMPLIX_H
+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
+23
View File
@@ -0,0 +1,23 @@
#ifndef _BODY_MAP_H
#define _BODY_MAP_H
#include <set>
#include <cstdint>
#include <body/limb.h>
namespace mrntt {
namespace body {
class BodyMap {
public:
BodyMap() = default;
~BodyMap() = default;
std::set<uint32_t, Limb> limbs;
};
} // namespace body
} // namespace mrntt
#endif // _BODY_MAP_H
+48
View File
@@ -0,0 +1,48 @@
#ifndef BODYPART_H
#define BODYPART_H
#include <cstdint>
#include <string>
#include <set>
#include <sensors/interoceptor.h>
namespace mrntt {
namespace body {
class Spot
{
public:
Spot(uint32_t _id, std::string _description)
: id(_id), description(_description)
{}
~Spot() = default;
public:
uint32_t id;
std::string description;
std::set<uint32_t, Interoceptor> interoceptors;
};
class Part
{
public:
Part(uint32_t _partId, std::string _partName,
std::string _partDesc, std::string _partLoc)
: id(_partId), name(_partName),
description(_partDesc), location(_partLoc)
{}
~Part() = default;
public:
const uint32_t id;
std::string name, description, location;
std::set<uint32_t, Spot> spots;
};
} // namespace body
} // namespace mrntt
#endif // BODYPART_H
+14
View File
@@ -0,0 +1,14 @@
#ifndef _MARIONETTE_H
#define _MARIONETTE_H
#include <cstdint>
namespace mrntt {
class Marionette
{
};
} // namespace mrntt
#endif // _MARIONETTE_H
+14
View File
@@ -0,0 +1,14 @@
#ifndef _MENTAL_ENTITY_H
#define _MENTAL_ENTITY_H
namespace hk {
class MentalEntity
{
public:
using Id = uint32_t;
};
} // namespace hk
#endif
+28
View File
@@ -0,0 +1,28 @@
#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
+20
View File
@@ -0,0 +1,20 @@
#ifndef _NON_NEUTRAL_QUALIA_H
#define _NON_NEUTRAL_QUALIA_H
#include <quale.h>
class PleasurableQuale
: public NonNeutralQuale
{
public:
virtual void eventInd(void);
};
class PainfulQuale
: public NonNeutralQuale
{
public:
virtual void eventInd(void);
};
#endif
+36
View File
@@ -0,0 +1,36 @@
#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
@@ -0,0 +1,39 @@
#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
+16
View File
@@ -0,0 +1,16 @@
#ifndef _QUALE_BUNDLE_H
#define _QUALE_BUNDLE_H
#include <config.h>
#include <array>
#include <quale.h>
#define CONFIG_NUM_SENSORS 5
typedef std::array<Quale, CONFIG_NUM_SENSORS> QualeBundle_t;
class QualeBundle
{
QualeBundle_t qualia;
};
#endif
+85
View File
@@ -0,0 +1,85 @@
#ifndef SENSE_API_PROVIDER_DESC_H
#define SENSE_API_PROVIDER_DESC_H
#include <string>
#include <memory>
#include <vector>
#include <dlfcn.h>
#include <functional>
#include <user/senseApiDesc.h>
namespace hk {
namespace sense_api {
class SenseApiLib
{
private:
friend class SenseApiManager;
struct DlCloser
{
void operator()(void* handle) const
{
if (handle) {
dlclose(handle);
}
}
};
public:
SenseApiLib(
const std::string& path, void *_dlopen_handle,
HK_GET_SENSE_API_DESC_FN_TYPEDEF *descFn)
: libraryPath(path),
dlopen_handle(_dlopen_handle, DlCloser()),
HK_GET_SENSE_API_DESC_FN_NAME(descFn)
{}
void setSenseApiDesc(const SenseApiDesc &desc)
{
if (!SenseApiDesc::sanityCheck(desc))
{
throw std::runtime_error(
std::string(__func__) + ": Sanity check failed for sense API "
"descriptor in library '" + libraryPath + "'");
}
senseApiDesc = desc;
}
public:
std::string libraryPath;
std::unique_ptr<void, DlCloser> dlopen_handle;
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
* sense api lib's behaviour globally.
*/
std::vector<std::string> options;
/**
* @brief Every sense API lib is required to provide a function that returns
* a SenseApiDesc struct. This struct states which API the lib uses to
* connect Harikoff to the sense provider it supports.
*
* This getter function should be visible to dlsym() so that Harikoff can
* find it in the lib after loading it, and call it.
*/
std::function<HK_GET_SENSE_API_DESC_FN_TYPEDEF>
HK_GET_SENSE_API_DESC_FN_NAME;
/**
* @brief Harikoff will call the `HK_GET_SENSE_API_DESC_FN_NAME` getter
* function and use the data it provides in order to fill out this
* descriptor.
*/
SenseApiDesc senseApiDesc;
std::string stringify() const {
std::string result = "Library Path: " + libraryPath + "\n";
result += "Sense API Descriptor: " + senseApiDesc.stringify() + "\n";
return result;
}
};
} // namespace sense_api
} // namespace hk
#endif // SENSE_API_PROVIDER_DESC_H
@@ -0,0 +1,60 @@
#ifndef SENSE_API_MANAGER_H
#define SENSE_API_MANAGER_H
#include <config.h>
#include <memory>
#include <vector>
#include <string>
#include <optional>
#include <functional>
#include <senseApis/senseApiLib.h>
#include <user/senseDeviceSpec.h>
namespace hk {
namespace sense_api {
class SenseApiManager
{
public:
static SenseApiManager& getInstance()
{
static SenseApiManager instance;
return instance;
}
SenseApiLib& loadSenseApiLib(const std::string& libraryPath);
std::optional<std::reference_wrapper<SenseApiLib>> getSenseApiLib(
const std::string& libraryPath);
std::optional<std::reference_wrapper<SenseApiLib>> getSenseApiLibByApiName(
const std::string& apiName);
void unloadSenseApiLib(const std::string& libraryPath);
void initializeSenseApiLib(SenseApiLib& lib);
void finalizeSenseApiLib(SenseApiLib& lib);
void loadAllSenseApiLibsFromOptions(void);
void unloadAllSenseApiLibs(void);
void initializeAllSenseApiLibs(void);
void finalizeAllSenseApiLibs(void);
void attachAllSenseDevicesFromSpecs(void);
void attachSenseDevice(const device::SenseDeviceSpec& spec);
void detachSenseDevice(const device::SenseDeviceSpec& spec);
void detachAllSenseDevices(void);
std::string stringifyLibs() const;
private:
SenseApiManager() = default;
~SenseApiManager() = default;
SenseApiManager(const SenseApiManager&) = delete;
SenseApiManager& operator=(const SenseApiManager&) = delete;
std::vector<std::unique_ptr<SenseApiLib>> senseApiLibs;
};
} // namespace sense_api
} // namespace hk
#endif // SENSE_API_MANAGER_H
+23
View File
@@ -0,0 +1,23 @@
#ifndef _EXTROSPECTOR_H
#define _EXTROSPECTOR_H
#include <cstdint>
#include <sensors/sensor.h>
namespace hk {
namespace sensors {
class Extrospector
: public Sensor
{
public:
Extrospector(void) = default;
~Extrospector() = default;
public:
};
} // namespace sensors
} // namespace hk
#endif // _EXTROSPECTOR_H
+109
View File
@@ -0,0 +1,109 @@
#ifndef _INTEROCEPTOR_H
#define _INTEROCEPTOR_H
#include <cstdint>
#include <sensors/sensor.h>
namespace hk {
namespace sensors {
class Interoceptor
: public Sensor
{
public:
Interoceptor(uint32_t _id, uint32_t _value = 0)
: id(_id), value(_value)
{}
~Interoceptor() = default;
public:
uint32_t id;
uint64_t value;
};
class NeutrinTeroceptor
: public Interoceptor
{
public:
NeutrinTeroceptor(uint32_t _id, uint32_t _value = 0)
: Interoceptor(_id, _value)
{}
};
class IntrinTeroceptor
: public Interoceptor
{
public:
static constexpr uint32_t DEFAULT_INDICATION_THRESHOLD = 1;
static constexpr uint32_t DEFAULT_ALERT_THRESHOLD = 5;
static constexpr uint32_t DEFAULT_OVERLOAD_THRESHOLD = 9;
IntrinTeroceptor(
uint32_t _id,
uint32_t _value = 0,
uint32_t _indicationThreshold = DEFAULT_INDICATION_THRESHOLD,
uint32_t _alertThreshold = DEFAULT_ALERT_THRESHOLD,
uint32_t _overloadThreshold = DEFAULT_OVERLOAD_THRESHOLD)
: Interoceptor(_id, _value),
indicationThreshold(_indicationThreshold),
alertThreshold(_alertThreshold),
overloadThreshold(_overloadThreshold)
{}
~IntrinTeroceptor() = default;
public:
uint32_t indicationThreshold;
uint32_t alertThreshold;
uint32_t overloadThreshold;
};
/**
* Negtrin and Postrin interoceptors are specialized intrinsic interoceptors
* that, unlike neutral interoceptors, have activation thresholds for different
* response levels (indication, alert, and overload). These thresholds allow
* them to trigger graduated responses based on stimulus intensity.
*
* While neutral interoceptors simply record a binary state or basic value,
* Negtrin and Postrin Interoceptors can model complex sensory responses with
* multiple activation levels, similar to biological pain/pleasure responses.
* Each threshold represents a different level of urgency or intensity in the
* sensory input.
*
* @see IntrinTeroceptor for the threshold values and implementation details
******************************************************************************/
class NegtrinTeroceptor
: public IntrinTeroceptor
{
public:
NegtrinTeroceptor(
uint32_t _id,
uint32_t _value = 0,
uint32_t _indicationThreshold = DEFAULT_INDICATION_THRESHOLD,
uint32_t _alertThreshold = DEFAULT_ALERT_THRESHOLD,
uint32_t _overloadThreshold = DEFAULT_OVERLOAD_THRESHOLD)
: IntrinTeroceptor(_id, _value,
_indicationThreshold, _alertThreshold, _overloadThreshold)
{}
};
class PostrinTeroceptor
: public IntrinTeroceptor
{
public:
PostrinTeroceptor(
uint32_t _id,
uint32_t _value = 0,
uint32_t _indicationThreshold = DEFAULT_INDICATION_THRESHOLD,
uint32_t _alertThreshold = DEFAULT_ALERT_THRESHOLD,
uint32_t _overloadThreshold = DEFAULT_OVERLOAD_THRESHOLD)
: IntrinTeroceptor(_id, _value,
_indicationThreshold, _alertThreshold, _overloadThreshold)
{}
};
} // namespace sensors
} // namespace hk
#endif // _INTEROCEPTOR_H
+21
View File
@@ -0,0 +1,21 @@
#ifndef _SENSOR_H
#define _SENSOR_H
#include <cstdint>
namespace hk {
namespace sensors {
class Sensor
{
public:
Sensor() = default;
~Sensor() = default;
public:
};
} // namespace sensors
} // namespace hk
#endif // _SENSOR_H
+79
View File
@@ -0,0 +1,79 @@
#ifndef SIMULATOR_COMMANDLIST_H
#define SIMULATOR_COMMANDLIST_H
#include <vector>
#include <cstdint>
#include <mentalEntity.h>
namespace hk {
namespace simulator {
/**
* @brief Base class for all commands, storing a reference to a mental entity ID.
*
* Derived classes can extend this to include additional command-specific
* data and behavior.
*/
class Command
{
public:
Command(const MentalEntity::Id menty) : menty(menty) {}
public:
const MentalEntity::Id menty;
};
class CommandList
{
public:
CommandList() = default;
/**
* @brief Used by Scene to point to the currently executing command.
*
* simulator::Scene maintains an internal cursor. As it executes commands
* from its internal command list, it advances the cursor to the current
* command before executing it.
*/
class Cursor
{
public:
Cursor(CommandList& commandList)
: commandList(commandList), iter(commandList.commands.begin())
{}
void reset() { iter = commandList.commands.begin(); }
bool hasNext() const { return iter != commandList.commands.end(); }
Cursor next() { return ++(*this); }
Cursor& operator++() {
++iter;
return *this;
}
private:
Cursor(
CommandList& commandList,
std::vector<Command>::iterator iter)
: commandList(commandList), iter(iter)
{}
public:
CommandList& commandList;
std::vector<Command>::iterator iter;
};
Cursor getCursor() { return Cursor(*this); }
void addCommand(const Command& command)
{
commands.push_back(command);
}
public:
std::vector<Command> commands;
};
} // namespace simulator
} // namespace hk
#endif // SIMULATOR_COMMANDLIST_H
+40
View File
@@ -0,0 +1,40 @@
#ifndef _SCENE_H
#define _SCENE_H
#include <cstdint>
#include <map>
#include <mentalEntity.h>
#include <simulator/commandList.h>
namespace hk {
namespace simulator {
class Scene
{
public:
using Id = uint32_t;
Scene(void) :
cursor(commands)
{}
~Scene() = default;
bool hasMentalEntity(const MentalEntity::Id menty) const;
MentalEntity::Id addMentalEntity(const MentalEntity& menty);
void replaceMentalEntity(const MentalEntity::Id menty, const MentalEntity& newMenty);
void removeMentalEntity(const MentalEntity::Id menty);
void executeInd(void);
CommandList::Cursor haltInd(void);
private:
std::map<MentalEntity::Id, MentalEntity &> menties;
CommandList commands;
CommandList::Cursor cursor;
};
} // namespace simulator
} // namespace hk
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef SIMULATOR_H
#define SIMULATOR_H
#include <config.h>
#include <simulator/scene.h>
namespace hk {
namespace simulator {
class Simulator {
public:
Simulator() = default;
~Simulator() = default;
void initialize();
void loadScene(Scene::Id sceneId, Scene &scene);
private:
Scene::Id sceneId;
Scene scene;
};
} // namespace simulator
} // namespace hk
#endif // SIMULATOR_H
+19
View File
@@ -0,0 +1,19 @@
#ifndef _SINGLECEPT_H
#define _SINGLECEPT_H
#include <mentalEntity.h>
#include <implix/implix.h>
class Singlecept
: public MentalEntity
{
public:
Singlecept() = default;
~Singlecept() = default;
Singlecept(const implix::Implix&) {
// Conversion logic from Implix to Singlecept
}
};
#endif
+30
View File
@@ -0,0 +1,30 @@
#ifndef STUPEFIER_H
#define STUPEFIER_H
#include <cstdint>
class Stupefier {
public:
Stupefier();
~Stupefier();
void up(uint32_t);
void down(uint32_t);
public:
uint32_t focus;
};
class SoftStupefier : public Stupefier {
public:
SoftStupefier();
~SoftStupefier();
};
class HardStupefier : public Stupefier {
public:
HardStupefier();
~HardStupefier();
};
#endif // STUPEFIER_H
+11
View File
@@ -0,0 +1,11 @@
#ifndef _SUBCONSCIOUS_H
#define _SUBCONSCIOUS_H
#include <thoughtContentSource.h>
class Subconscious
: public ThoughtContentSource
{
};
#endif
+60
View File
@@ -0,0 +1,60 @@
#ifndef _THOUGHT_H
#define _THOUGHT_H
#include <iostream>
#include <scene.h>
#include <attentionGrabber.h>
#include <goal.h>
class Thought
{
public:
Thought(void)
{
setGoal(thought::Goal::DRIFT);
}
public:
void walk(void)
{
for (;;)
{
step();
}
};
void step(void) { std::cout <<"Step\n"; }
void setGoal(thought::Goal g)
{ goal = g; }
public:
Scene scene;
thought::Goal goal;
};
class ActiveThought
: public Thought
{
public:
ActiveThought(AttentionGrabber ag)
: currFocus(ag)
{
setGoal(thought::Goal
::ASSOCIATE_CAUSAL_QUALE_WITH_INTRINSIC_MOTIVATORS);
}
public:
AttentionGrabber currFocus;
};
class IdleThought
: public Thought
{
public:
IdleThought(void)
{}
};
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef _THOUGHT_CONTENT_SOURCE_H
#define _THOUGHT_CONTENT_SOURCE_H
class ThoughtContentSource
{
};
#endif
+26
View File
@@ -0,0 +1,26 @@
#ifndef _VALUE_JUDGEMENT_H
#define _VALUE_JUDGEMENT_H
#include <cstdint>
class ValueJdgmnt
{
uint32_t intensity;
};
class PosValueJdgmnt
: public ValueJdgmnt
{
};
class NegValueJdgmnt
: public ValueJdgmnt
{
};
class NtrlValueJdgmnt
: public ValueJdgmnt
{
};
#endif
+7
View File
@@ -0,0 +1,7 @@
add_library(marionette STATIC
marionette.cpp
)
target_include_directories(marionette PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
+9
View File
@@ -0,0 +1,9 @@
namespace mrntt {
int main(int argc, char *argv[])
{
return 0;
}
} // namespace mrntt
+2
View File
@@ -0,0 +1,2 @@
#include <mind.h>
+120
View File
@@ -0,0 +1,120 @@
#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();
}
+2
View File
@@ -0,0 +1,2 @@
#include <nonNeutralQualia.h>
+5
View File
@@ -0,0 +1,5 @@
add_library(senseApis STATIC
senseApiManager.cpp
)
target_include_directories(senseApis PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
+268
View File
@@ -0,0 +1,268 @@
#include <iostream>
#include <stdexcept>
#include <optional>
#include <filesystem>
#include <senseApis/senseApiManager.h>
#include <senseApis/senseApiLib.h>
#include <opts.h>
#include <user/senseApiDesc.h>
#include <deviceManager/deviceManager.h>
namespace fs = std::filesystem;
namespace hk {
namespace sense_api {
/**
* @brief Searches for a library in predefined locations
* @param libraryPath The name or path of the library to find
* @return Optional containing the full path if found in search paths, nullopt
* if not
*
* Searches for the library in the following locations in order:
* 1. Custom path specified by --sense-api-lib-path option (if provided)
* 2. Current working directory
* 3. Directory containing the executable
*
* If the library is not found in any of these locations, returns nullopt and
* falls back to system default library search paths (LD_LIBRARY_PATH, etc.)
*/
static std::optional<std::string> findLibraryPath(
const std::string& libraryPath)
{
std::vector<std::string> searchPaths = {
fs::current_path().string(),
fs::path("/proc/self/exe").parent_path().string()
};
if (!OptionParser::getOptions().senseApiLibPath.empty())
{
searchPaths.insert(
searchPaths.begin(), OptionParser::getOptions().senseApiLibPath);
}
for (const auto& path : searchPaths)
{
fs::path fullPath = fs::path(path) / libraryPath;
if (fs::exists(fullPath))
{
return fullPath.string();
}
}
std::cerr << std::string(__func__) + ": library '"
+ libraryPath + "' isn't in search bespoke search paths: ";
for (const auto& path : searchPaths) {
std::cerr << path << " ";
}
std::cerr << std::endl;
std::cerr << "Trying to load " + libraryPath + " from system default "
"search paths\n";
return std::nullopt;
}
SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath)
{
std::optional<std::string> fullPath = findLibraryPath(libraryPath);
std::string resolvedPath = fullPath.value_or(libraryPath);
// Clear any existing error
dlerror();
auto dlopen_handle = std::unique_ptr<void, SenseApiLib::DlCloser>(
dlopen(resolvedPath.c_str(), RTLD_LAZY));
if (!dlopen_handle && fullPath.has_value())
{
// Fallback to using the supplied libraryPath
dlerror();
dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY));
}
if (!dlopen_handle)
{
const char *dlerr = dlerror();
std::string error = (dlerr
? dlerr
: "Unknown error while opening shlib");
throw std::runtime_error(
std::string(__func__) + ": Cannot load library '"
+ libraryPath + "': "
+ error);
}
// Initialize getSenseApiDescriptor
auto func = reinterpret_cast<HK_GET_SENSE_API_DESC_FN_TYPEDEF *>(
dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR));
if (!func)
{
throw std::runtime_error(
std::string(__func__) + ": dlsym('"
HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '"
+ libraryPath + "'");
}
const SenseApiDesc &libApiDesc = func();
auto lib = std::make_unique<SenseApiLib>(
libraryPath, dlopen_handle.release(), func);
lib->setSenseApiDesc(libApiDesc);
senseApiLibs.push_back(std::move(lib));
return *senseApiLibs.back();
}
std::optional<std::reference_wrapper<SenseApiLib>>
SenseApiManager::getSenseApiLib(const std::string& libraryPath)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&libPath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
return lib->libraryPath == libPath;
}
);
if (it != senseApiLibs.end()) { return **it; }
return std::nullopt;
}
std::optional<std::reference_wrapper<SenseApiLib>>
SenseApiManager::getSenseApiLibByApiName(const std::string& apiName)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&apiName](const std::unique_ptr<SenseApiLib>& lib) {
return lib->senseApiDesc.name == apiName;
}
);
if (it != senseApiLibs.end()) { return **it; }
return std::nullopt;
}
void SenseApiManager::unloadSenseApiLib(const std::string& libraryPath)
{
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
[&lpath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
return lib->libraryPath == lpath;
}
);
if (it != senseApiLibs.end())
{
senseApiLibs.erase(it);
return;
}
std::cerr << std::string(__func__) + ": Library not found: "
<< libraryPath << '\n';
}
void SenseApiManager::unloadAllSenseApiLibs(void)
{
senseApiLibs.clear();
}
void SenseApiManager::loadAllSenseApiLibsFromOptions()
{
const auto& options = OptionParser::getOptions();
for (const auto& libPath : options.senseApiLibs) {
loadSenseApiLib(libPath);
}
}
std::string SenseApiManager::stringifyLibs() const
{
std::string result;
for (const auto& lib : senseApiLibs) {
result += lib->stringify() + "\n";
}
return result;
}
void SenseApiManager::initializeSenseApiLib(SenseApiLib& lib)
{
if (!lib.senseApiDesc.sal_mgmt_libOps.initializeInd)
{
throw std::runtime_error(
std::string(__func__) + ": initializeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.initializeInd();
}
void SenseApiManager::finalizeSenseApiLib(SenseApiLib& lib)
{
if (!lib.senseApiDesc.sal_mgmt_libOps.finalizeInd)
{
throw std::runtime_error(
std::string(__func__) + ": finalizeInd() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.finalizeInd();
}
void SenseApiManager::initializeAllSenseApiLibs(void)
{
for (auto& lib : senseApiLibs) {
initializeSenseApiLib(*lib);
}
}
void SenseApiManager::finalizeAllSenseApiLibs(void)
{
for (auto& lib : senseApiLibs) {
finalizeSenseApiLib(*lib);
}
}
void SenseApiManager::attachSenseDevice(const device::SenseDeviceSpec& spec)
{
auto libOpt = getSenseApiLibByApiName(spec.api);
if (!libOpt)
{
throw std::runtime_error(
std::string(__func__) + ": No library found for API '"
+ spec.api + "'");
}
auto& lib = libOpt.value().get();
if (!lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq)
{
throw std::runtime_error(
std::string(__func__) + ": attachDeviceReq() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq(spec);
}
void SenseApiManager::detachSenseDevice(const device::SenseDeviceSpec& spec)
{
auto libOpt = getSenseApiLibByApiName(spec.api);
if (!libOpt)
{
throw std::runtime_error(
std::string(__func__) + ": No library found for API '"
+ spec.api + "'");
}
auto& lib = libOpt.value().get();
if (!lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq)
{
throw std::runtime_error(
std::string(__func__) + ": detachDeviceReq() is NULL for library '"
+ lib.libraryPath + "'");
}
lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq(spec);
}
void SenseApiManager::attachAllSenseDevicesFromSpecs(void)
{
for (const auto& spec : device::DeviceManager::senseDeviceSpecs) {
attachSenseDevice(*spec);
}
}
void SenseApiManager::detachAllSenseDevices(void)
{
for (const auto& spec : device::DeviceManager::senseDeviceSpecs) {
detachSenseDevice(*spec);
}
}
} // namespace sense_api
} // namespace hk