22 #ifndef SPINNAKER_PROXY_H
23 #define SPINNAKER_PROXY_H
25 #include <boost/python.hpp>
27 #include <nlohmann/json.hpp>
32 #include <SpynnakerLiveSpikesConnection.h>
36 namespace bpy = boost::python;
38 #define use(x) do {} while ((x)!=(x))
41 #define VOLTAGE_INT_TO_S1615 32768.0f
50 SpikesStartCallbackInterface, PayloadReceiveCallbackInterface {
76 std::lock_guard<std::mutex> lk(runningMutex);
83 void spikes_start(
char *label, SpynnakerLiveSpikesConnection *connection) {
88 if (n_send_warnings > 0) {
95 char **charReceiveLabels =
new char*[receiveLabels.size()];
96 char **charSendLabels =
new char*[sendLabels.size()];
98 for (std::size_t i = 0; i < receiveLabels.size(); i++) {
99 charReceiveLabels[i] = (
char *) receiveLabels[i].c_str();
100 a_label = charReceiveLabels[i];
102 for (std::size_t i = 0; i < sendLabels.size(); i++) {
103 charSendLabels[i] = (
char *) sendLabels[i].c_str();
104 a_label = charSendLabels[i];
107 if (a_label == NULL) {
111 connection =
new SpynnakerLiveSpikesConnection(
112 receiveLabels.size(), charReceiveLabels,
113 sendLabels.size(), charSendLabels);
114 for (std::size_t i = 0; i < receiveLabels.size(); i++) {
115 connection->add_receive_callback(
116 (
char *) receiveLabels[i].c_str(), (SpikeReceiveCallbackInterface *)
this);
117 connection->add_receive_callback(
118 (
char *) receiveLabels[i].c_str(), (PayloadReceiveCallbackInterface *)
this);
120 connection->add_start_callback(a_label,
this);
124 PyGILState_STATE gstate = PyGILState_Ensure();
127 if (connection != NULL) {
129 pySpinnakerExt.attr(
"add_database_socket_address")(
130 NULL, connection->get_local_port(), NULL);
133 pySpinnakerExt.attr(
"run_forever")();
136 catch (bpy::error_already_set
const &)
141 PyGILState_Release(gstate);
146 std::lock_guard<std::mutex> lk(runningMutex);
152 PyGILState_STATE gstate = PyGILState_Ensure();
155 pySpinnakerExt.attr(
"request_stop")();
157 catch (bpy::error_already_set
const &) {
160 PyGILState_Release(gstate);
162 gstate = PyGILState_Ensure();
165 pySpinnaker.attr(
"end")();
167 catch (bpy::error_already_set
const &) {
170 PyGILState_Release(gstate);
177 NRPLogger::error(
"A new sender cannot be added when SpiNNaker is already running!");
179 if (std::find(sendLabels.begin(), sendLabels.end(), label) == sendLabels.end()) {
180 sendLabels.push_back(label);
188 NRPLogger::error(
"A new receiver cannot be added when SpiNNaker is already running!");
190 auto label_callbacks = callbacks.find(label);
191 if (label_callbacks == callbacks.end()) {
192 callbacks[label] = std::vector<SpiNNakerJsonReceiveCallbackInterface *>();
193 receiveLabels.push_back(label);
195 callbacks[label].push_back(callback);
201 if (n_send_warnings == 0) {
208 if(n_send_warnings > 0) {
213 std::vector<int> spikes;
214 if (data->contains(
"neuron_ids")) {
216 for (
size_t i = 0; i < neuron_ids.size(); i++) {
217 spikes.push_back(neuron_ids[i]);
220 std::vector<rate_details> rates_to_send;
221 if (data->contains(
"rates")) {
223 for (
size_t i = 0; i < rates.size(); i++) {
224 int neuron_id = rates[i].at(
"neuron_id");
225 float rate = rates[i].at(
"rate");
226 rates_to_send.push_back({.neuron_id=neuron_id, .rate=rate});
227 NRPLogger::debug(
"Sending rate of neuron {} to {} in {}", neuron_id, rate, label);
230 if ((spikes.size() > 0 && rates_to_send.size() > 0)
231 || (spikes.size() == 0 && rates_to_send.size() == 0)) {
233 " use neuron_ids to send spikes to a SpikeInjector or"
234 " rates to set the rates of a SpikeSourcePoisson");
236 if (spikes.size() > 0) {
237 connection->send_spikes((
char *) label.c_str(), spikes);
239 connection->send_rates((
char *) label.c_str(), rates_to_send);
245 std::string strLabel(label);
246 auto recvCallbacks = callbacks[strLabel];
248 for (
int i = 0; i < n_spikes; i++) {
249 keyArray.push_back(spikes[i]);
256 for (std::size_t i = 0; i < recvCallbacks.size(); i++) {
257 recvCallbacks[i]->new_msg_callback(data);
262 std::string strLabel(label);
263 auto recvCallbacks = callbacks[strLabel];
265 for (
int i = 0; i < n_payloads; i++) {
267 {
"neuron_id", payloads[i].neuron_id},
270 payloadArray.push_back(payload);
274 {
"voltages", payloadArray}
276 for (std::size_t i = 0; i < recvCallbacks.size(); i++) {
277 recvCallbacks[i]->new_msg_callback(data);
282 bpy::object pySpinnaker;
283 bpy::object pySpinnakerExt;
284 std::future<void> _runFuture;
285 bool started =
false;
286 bool running =
false;
287 std::mutex runningMutex;
288 std::map<std::string,
289 std::vector<SpiNNakerJsonReceiveCallbackInterface *>> callbacks;
290 SpynnakerLiveSpikesConnection *connection = NULL;
291 std::vector<std::string> receiveLabels;
292 std::vector<std::string> sendLabels;
293 int n_send_warnings = 0;
299 pySpinnaker = bpy::import(
"pyNN.spiNNaker");
300 pySpinnakerExt = pySpinnaker.attr(
"external_devices");
302 catch (bpy::error_already_set
const &)
308 static std::unique_ptr<NRPSpinnakerProxy> _instance;
312 #endif //SPINNAKER_PROXY_H