diff --git a/docker-compose.yml b/docker-compose.yml index 8e9725fc64ce0e4eb249ce8034d3f4d97c41f67f..cda4fee09f6081577824edf446fe2b0a23cf65a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,5 +15,6 @@ services: - ./scripts:/scripts/ ports: - "9000-9005:9000-9005" + - "9100:9100" environment: - SCRIPT_NAME=stim.py diff --git a/nest-module/src/insitemodule.cpp b/nest-module/src/insitemodule.cpp index dbdcaef3eb1005a95fdb0296610b016aa50ea5a9..d3f18932e574c243321d93edefdf538c67906861 100644 --- a/nest-module/src/insitemodule.cpp +++ b/nest-module/src/insitemodule.cpp @@ -74,10 +74,9 @@ const std::string InsiteModule::name(void) const { //------------------------------------------------------------------------------------- void InsiteModule::init(SLIInterpreter* i) { + nest::kernel().io_manager.register_stimulation_backend<StimulationBackendInsite>("insiteStim"); nest::kernel().io_manager.register_recording_backend<RecordingBackendInsite>( "insite"); - nest::kernel().io_manager.register_stimulation_backend<StimulationBackendInsite>("insiteStim"); - std::cout << "Valid Stim: " << nest::kernel().io_manager.is_valid_stimulation_backend("insiteStim") << std::endl; } // InsiteModule::init() } // namespace insite diff --git a/nest-module/src/stimulation_backend_insite.cpp b/nest-module/src/stimulation_backend_insite.cpp index 425840cfb9c86db5684589db3ff50e8a0c854772..9080ea582dc0681af0d36a5742637fe27f157120 100644 --- a/nest-module/src/stimulation_backend_insite.cpp +++ b/nest-module/src/stimulation_backend_insite.cpp @@ -25,6 +25,7 @@ #include <fstream> #include <vector> #include <algorithm> +#include "rapidjson/document.h" // Includes from nestkernel: #include "stimulation_backend.h" @@ -32,84 +33,148 @@ #include "kernel_manager.h" #include "stimulation_device.h" +using namespace rapidjson; +using namespace std; + + + insite::StimulationBackendInsite::StimulationBackendInsite() : enrolled_( false ) , prepared_( false ) + , http_listener_{"http://0.0.0.0:9100"} { + http_listener_.support([this](web::http::http_request request){ + if (request.method() == "POST" && request.relative_uri().path() == "/stim") + { + auto req = request.extract_string().get(); + Document document; + document.Parse(req.c_str()); + + if (not (document.HasMember("nodeIds") && document.HasMember("spikeTimes"))) + { + std::cout << "[insite] Either nodeIds or spikeTimes is missing" << std::endl; + + web::http::http_response response(web::http::status_codes::BadRequest); + request.reply(response); + return; + } + else if(not (document["nodeIds"].IsArray() && document["spikeTimes"].IsArray())) + { + std::cout << "[insite] Either nodeIds or spikeTimes not an array" << std::endl; + web::http::http_response response(web::http::status_codes::BadRequest); + request.reply(response); + return; + } + else if (not (document["nodeIds"].Size() == document["spikeTimes"].Size())) + { + std::cout << "[insite] NodeIds and spikeTimes did not have the same length!" << std::endl; + web::http::http_response response(web::http::status_codes::BadRequest); + request.reply(response); + return; + } + + for (int i = 0; i < document["nodeIds"].Size(); ++i) + { + std::uint64_t nodeId = document["nodeIds"][i].GetInt(); + double time = document["spikeTimes"][i].GetDouble(); + std::cout << "[insite] " << nodeId << " - " << time << std::endl; + + const auto stimulation_device_spikes = stimulation_spikes.find(nodeId); + if(stimulation_device_spikes != stimulation_spikes.end()) + { + stimulation_device_spikes->second.push_back(time); + } + } + + std::cout << "[insite] Spikes stored in stimulation vector: " << std::endl; + for (const auto& m : stimulation_spikes) + { + for (const auto& v : m.second) + { + std::cout << "[insite] " << m.first << " - " << v << std::endl; + } + } + + web::http::http_response response(web::http::status_codes::OK); + request.reply(response); + } + + + }); + + http_listener_.open().wait(); + std::cout << "[insite] Started stimulation HTTP server" << std::endl; } insite::StimulationBackendInsite::~StimulationBackendInsite() noexcept { - std::cout << "[insite] stim backend ctor" << std::endl; + std::cout << "[insite] Stimulation backend ctor" << std::endl; } void insite::StimulationBackendInsite::initialize() { - std::cout << "[insite] stim backend init" << std::endl; + std::cout << "[insite] Stimulation backend init" << std::endl; } void insite::StimulationBackendInsite::finalize() { - std::cout << "[insite] stim backend finalize" << std::endl; + std::cout << "[insite] Stimulation backend finalize" << std::endl; } void insite::StimulationBackendInsite::enroll( nest::StimulationDevice& device, const DictionaryDatum& ) { - std::cout << "[insite] stim backend enroll" << std::endl; - dev = &device; + const std::uint64_t node_id = device.get_node_id(); + if (stimulation_devices_.find(node_id) == stimulation_devices_.end()) + { + std::cout << "[insite] Enrolled Stimulation device with id: " << node_id << std::endl; + stimulation_devices_.insert(std::make_pair(node_id,&device)); + stimulation_spikes.insert(std::make_pair(node_id,std::vector<double>())); + } } void insite::StimulationBackendInsite::disenroll( nest::StimulationDevice& device ) { - std::cout << "[insite] stim backend disenroll" << std::endl; + std::cout << "[insite] Stimulation backend disenroll" << std::endl; } void insite::StimulationBackendInsite::prepare() { - std::cout << "[insite] stim backend prepare" << std::endl; + std::cout << "[insite] Stimulation backend prepare" << std::endl; } void insite::StimulationBackendInsite::pre_run_hook() { - std::cout << "[insite] stim backend pre run hook" << std::endl; - std::vector<double> spikes; - for (int i = 0; i < 10; i++) - { - double f = (double)rand() / RAND_MAX; - spikes.push_back(f * 30); - } - std::cout << "generated values: " << std::endl; - for (const auto& val : spikes) - std::cout << val << std::endl; - std::sort(spikes.begin(),spikes.end()); - std::cout << "generated values: " << std::endl; - for (const auto& val : spikes) - std::cout << val << std::endl; - if(dev) - { - std::cout << "Set new stimuli" << std::endl; - dev->set_data_from_stimulation_backend(spikes); + std::cout << "[insite] Stimulation backend pre run hook" << std::endl; + for (const auto& stimulation_device : stimulation_devices_) + { + auto device_id = stimulation_device.first; + std::cout << "[insite] Set stimuli for device: " << device_id << std::endl; + auto& spikes = stimulation_spikes[device_id]; + std::sort(spikes.begin(),spikes.end()); + for (const auto& spike : spikes) + std::cout << device_id << " - " << spike << std::endl; + stimulation_device.second->set_data_from_stimulation_backend(spikes); } } void insite::StimulationBackendInsite::post_run_hook() { - std::cout << "[insite] stim backend post run hook" << std::endl; + std::cout << "[insite] Stimulation backend post run hook" << std::endl; } void insite::StimulationBackendInsite::cleanup() { - std::cout << "[insite] stim backend cleanup" << std::endl; + std::cout << "[insite] Stimulation backend cleanup" << std::endl; } diff --git a/nest-module/src/stimulation_backend_insite.h b/nest-module/src/stimulation_backend_insite.h index 41afa3f0bf4ab611d93aee38f61aeeb02dc00c96..ac94c703386050a153efdb652c95cb0ac2e68bda 100644 --- a/nest-module/src/stimulation_backend_insite.h +++ b/nest-module/src/stimulation_backend_insite.h @@ -13,6 +13,8 @@ #include <unistd.h> #include <mpi.h> +#include <cpprest/http_client.h> +#include <cpprest/http_listener.h> namespace insite { @@ -52,7 +54,10 @@ private: bool enrolled_; bool prepared_; nest::StimulationDevice* dev = nullptr; - + web::http::experimental::listener::http_listener http_listener_; + std::vector<double> spikes; + std::unordered_map<std::uint64_t, std::vector<double>> stimulation_spikes; + std::unordered_map<std::uint64_t, nest::StimulationDevice*> stimulation_devices_; }; } // namespace