CereConn.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071
  1. #include "spdlog/spdlog.h"
  2. #include "spdlog/async.h"
  3. #include "spdlog/sinks/stdout_color_sinks.h"
  4. #include "CereConn.h"
  5. #include "CereConnHelpers.h"
  6. #include <algorithm>
  7. #include <cstdio>
  8. #include <functional>
  9. namespace cc
  10. {
  11. CereConn::CereConn(uint32_t instance, bool withSRE, bool withSBPE)
  12. : m_msgQ (20)
  13. , m_conType (CBSDKCONNECTION_DEFAULT)
  14. , m_instance (instance)
  15. , m_state (State::Closed)
  16. , m_keep_going(true)
  17. , m_with_SRE(withSRE)
  18. , m_with_SBPE(withSBPE)
  19. {
  20. std::fill(std::begin(m_sgroup_changed), std::end(m_sgroup_changed), true);
  21. auto l = spdlog::get("CereConn");
  22. if (l)
  23. {
  24. m_console = l;
  25. }
  26. else
  27. {
  28. m_console = spdlog::stdout_color_mt<spdlog::async_factory>("CereConn");
  29. }
  30. l = spdlog::get("CereConnAcq");
  31. if (l)
  32. {
  33. m_acq = l;
  34. }
  35. else
  36. {
  37. m_acq = std::make_shared<spdlog::logger>("CereConnAcq", begin(m_console->sinks()), end(m_console->sinks()));
  38. spdlog::register_logger(m_acq);
  39. }
  40. m_pRb = std::make_unique<SampleGroupRingBufferCollection>();
  41. m_pSRb = std::make_unique<SpikeRingBuffer>();
  42. m_pCRb = std::make_unique<CommentRingBuffer>();
  43. m_pDIRb = std::make_unique<DigInEvRingBuffer>();
  44. mp_rateRB = std::make_shared<sre::SpikeRateEstimator::rate_ring_buffer_type>();
  45. mp_sbpRB = std::make_shared<sbpe::SpikeBandPowerEstimator::sbp_ring_buffer_type>();
  46. #if defined(CC_LOG_LEVEL_DEBUG)
  47. spdlog::set_level(spdlog::level::debug);
  48. #else
  49. spdlog::set_level(spdlog::level::info);
  50. #endif
  51. spikeRateEstimatorSetUp();
  52. spikeBandPowerEstimatorSetUp();
  53. m_console->info("Welcome to CereConn!");
  54. m_sample_groups_enabled.fill(false);
  55. startThread();
  56. }
  57. CereConn::~CereConn()
  58. {
  59. spikeRateEstimatorStop();
  60. spikeBandPowerEstimatorStop();
  61. m_keep_going.store(false);
  62. sendMessage(Instruction::Close);
  63. if (m_thread.joinable())
  64. {
  65. m_thread.join();
  66. }
  67. }
  68. void CereConn::startThread()
  69. {
  70. m_console->debug("Starting NSP Thread from outside {}...", std::hash<std::thread::id>()(std::this_thread::get_id()));
  71. if (m_thread.joinable())
  72. {
  73. m_keep_going.store(false);
  74. sendMessage(Instruction::Close);
  75. m_thread.join();
  76. }
  77. while (m_msgQ.sizeGuess())
  78. {
  79. m_msgQ.popFront();
  80. }
  81. m_thread = std::thread(&CereConn::threadFun, this);
  82. }
  83. void CereConn::sendMessage(Instruction instruction)
  84. {
  85. std::unique_lock<std::mutex> locker(m_msg_lock);
  86. m_console->info("CereConnMsg thread sending {} ...", static_cast<int>(instruction));
  87. m_msgQ.write(instruction);
  88. m_msg_queue_not_empty.notify_one();
  89. }
  90. void CereConn::ccOpen()
  91. {
  92. sendMessage(Instruction::Open);
  93. }
  94. void CereConn::ccRecord()
  95. {
  96. sendMessage(Instruction::Record);
  97. }
  98. void CereConn::ccIdle()
  99. {
  100. sendMessage(Instruction::Idle);
  101. }
  102. void CereConn::ccClose()
  103. {
  104. sendMessage(Instruction::Close);
  105. }
  106. CereConn::ReturnCode CereConn::getSampleGroupData(SampleGroupList &sgl, uint32_t &cbTime)
  107. {
  108. if (m_state != State::Recording)
  109. {
  110. m_console->warn("CereConn::getSampleGroupData called while not recording.");
  111. return ReturnCode::NotRecording;
  112. }
  113. m_pRb->consume(sgl);
  114. cbSdkResult res;
  115. res = cbSdkGetTime(m_instance, &cbTime);
  116. if (res != 0)
  117. {
  118. m_acq->error("cbSdkGetTime returned {}", res);
  119. return ReturnCode::NoValidTimestamp;
  120. }
  121. sgl.timestamp = cbTime;
  122. return ReturnCode::Success;
  123. }
  124. void CereConn::threadFun()
  125. {
  126. m_acq->debug("Starting NSP Thread {}...", std::hash<std::thread::id>()(std::this_thread::get_id()));
  127. CereConn::Instruction my_instruction;
  128. m_keep_going.store(true);
  129. while (m_keep_going.load())
  130. {
  131. std::unique_lock<std::mutex> locker(m_msg_lock);
  132. // ensure queue is not empty when we wake up
  133. m_msg_queue_not_empty.wait(locker, std::bind(std::logical_not<bool>(), std::bind(&folly::ProducerConsumerQueue<Instruction>::isEmpty, &m_msgQ)));
  134. if (! m_msgQ.read(my_instruction))
  135. {
  136. continue;
  137. }
  138. m_acq->info("Got message {}", static_cast<int> (my_instruction));
  139. switch (my_instruction)
  140. {
  141. case Instruction::Open:
  142. if (m_state == State::Closed || m_state == State::Invalid)
  143. {
  144. cbOpen();
  145. }
  146. break;
  147. case Instruction::Close:
  148. if (m_state == State::Idle || m_state == State::Recording)
  149. {
  150. cbClose();
  151. }
  152. break;
  153. case Instruction::Record:
  154. if (m_state == State::Idle)
  155. {
  156. cbStartRecording();
  157. }
  158. break;
  159. case Instruction::Idle:
  160. if (m_state == State::Recording)
  161. {
  162. cbStopRecording();
  163. }
  164. break;
  165. case Instruction::Invalid:
  166. default:
  167. break;
  168. }
  169. }
  170. }
  171. void CereConn::cbOpen()
  172. {
  173. m_acq->debug("Opening cbSDK ...");
  174. cbSdkResult res = cbSdkOpen(m_instance, m_conType);
  175. if (res == 0)
  176. {
  177. m_acq->debug("cbSdkOpen returned: {}", res);
  178. m_state = State::Idle;
  179. // Hard-coding of sample periods. TODO: make this dynamic by interrogating CereLink
  180. for (unsigned int i = 0; i < constants::NSampleGroups; ++i)
  181. {
  182. m_pRb->setSamplePeriodForGroup(i + 1, constants::SampleGroupPeriods[i]);
  183. }
  184. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_GROUPINFO, CereConn::cbSdkCallbackGroupInfo, this);
  185. if (res != 0)
  186. {
  187. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_GROUPINFO returned {}", res);
  188. return;
  189. }
  190. updateGroupChannelLists();
  191. }
  192. else
  193. {
  194. m_acq->error("cbSdkOpen returned {}", res);
  195. m_state = State::Invalid;
  196. return;
  197. }
  198. }
  199. void CereConn::cbStartRecording()
  200. {
  201. cbSdkResult res;
  202. if (m_with_SRE)
  203. {
  204. spikeRateEstimatorStart();
  205. }
  206. if (m_with_SBPE)
  207. {
  208. spikeBandPowerEstimatorStart();
  209. }
  210. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_CONTINUOUS, CereConn::cbSdkCallbackContinuous, this);
  211. if (res != 0)
  212. {
  213. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_CONTINUOUS returned {}", res);
  214. return;
  215. }
  216. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_SPIKE, CereConn::cbSdkCallbackSpike, this);
  217. if (res != 0)
  218. {
  219. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_SPIKE returned {}", res);
  220. return;
  221. }
  222. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_COMMENT, CereConn::cbSdkCallbackComment, this);
  223. if (res != 0)
  224. {
  225. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_COMMENT returned {}", res);
  226. return;
  227. }
  228. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_DIGITAL, CereConn::cbSdkCallbackDigInEv, this);
  229. if (res != 0)
  230. {
  231. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_DIGITAL returned {}", res);
  232. return;
  233. }
  234. res = cbSdkRegisterCallback(m_instance, CBSDKCALLBACK_SERIAL, CereConn::cbSdkCallbackDigInEv, this);
  235. if (res != 0)
  236. {
  237. m_acq->error("cbSdkRegisterCallback CBSDKCALLBACK_SERIAL returned {}", res);
  238. return;
  239. }
  240. m_acq->info("Registered packet callbacks.");
  241. m_state = State::Recording;
  242. }
  243. void CereConn::cbStopRecording()
  244. {
  245. cbSdkResult res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_CONTINUOUS);
  246. if (res != 0)
  247. {
  248. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_CONTINUOUS returned {}", res);
  249. return;
  250. }
  251. res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_SPIKE);
  252. if (res != 0)
  253. {
  254. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_SPIKE returned {}", res);
  255. return;
  256. }
  257. res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_COMMENT);
  258. if (res != 0)
  259. {
  260. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_COMMENT returned {}", res);
  261. return;
  262. }
  263. res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_DIGITAL);
  264. if (res != 0)
  265. {
  266. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_DIGITAL returned {}", res);
  267. return;
  268. }
  269. res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_SERIAL);
  270. if (res != 0)
  271. {
  272. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_SERIAL returned {}", res);
  273. return;
  274. }
  275. if (m_with_SRE)
  276. {
  277. spikeRateEstimatorStop();
  278. }
  279. if (m_with_SBPE)
  280. {
  281. spikeBandPowerEstimatorStop();
  282. }
  283. m_acq->info("Unregistered packet callbacks.");
  284. m_state = State::Idle;
  285. }
  286. void CereConn::cbClose()
  287. {
  288. m_acq->debug("Closing cbSDK ...");
  289. cbSdkResult res = cbSdkUnRegisterCallback(m_instance, CBSDKCALLBACK_GROUPINFO);
  290. if (res != 0)
  291. {
  292. m_acq->error("cbSdkUnRegisterCallback CBSDKCALLBACK_GROUPINFO returned {}", res);
  293. }
  294. res = cbSdkClose(m_instance);
  295. m_state = State::Closed;
  296. if (res == 0)
  297. {
  298. m_acq->debug("cbSdkClose returned: {}", res);
  299. }
  300. else
  301. {
  302. m_acq->error("cbSdkClose returned {}", res);
  303. return;
  304. }
  305. }
  306. CereConn::State CereConn::getState() const
  307. {
  308. return m_state;
  309. }
  310. CereConn::ReturnCode CereConn::sendComment(const std::string comment, const uint32_t rgba, const uint8_t charset)
  311. {
  312. cbSdkResult res = cbSdkSetComment(m_instance, rgba, charset, comment.c_str());
  313. m_acq->info("Sent comment <{}> ({}) with result: {}", comment, rgba, res);
  314. if (res != 0)
  315. {
  316. m_acq->error("cbSdkSetComment returned {} (in sendComment)", res);
  317. return ReturnCode::Error;
  318. }
  319. return ReturnCode::Success;
  320. }
  321. CereConn::ReturnCode CereConn::getCommentData(CommentList &clist, uint32_t &cbTime)
  322. {
  323. size_t oc;
  324. return getCommentData(clist, cbTime, oc);
  325. }
  326. CereConn::ReturnCode CereConn::getCommentData(CommentList &clist, uint32_t &cbTime, size_t &overflowCount)
  327. {
  328. if (m_state != State::Recording)
  329. {
  330. m_console->warn("CereConn::getCommentData called while not recording.");
  331. return ReturnCode::NotRecording;
  332. }
  333. m_pCRb->consume(clist, overflowCount);
  334. cbSdkResult res;
  335. res = cbSdkGetTime(m_instance, &cbTime);
  336. if (res != 0)
  337. {
  338. m_acq->error("cbSdkGetTime returned {} (in getCommentData)", res);
  339. return ReturnCode::NoValidTimestamp;
  340. }
  341. return ReturnCode::Success;
  342. }
  343. CereConn::ReturnCode CereConn::getDigInEvData(DigInEvList &dievlist, uint32_t &cbTime)
  344. {
  345. size_t oc;
  346. return getDigInEvData(dievlist, cbTime, oc);
  347. }
  348. CereConn::ReturnCode CereConn::getDigInEvData(DigInEvList &dievlist, uint32_t &cbTime, size_t &overflowCount)
  349. {
  350. if (m_state != State::Recording)
  351. {
  352. m_console->warn("CereConn::getDigInEvData called while not recording.");
  353. return ReturnCode::NotRecording;
  354. }
  355. m_pDIRb->consume(dievlist, overflowCount);
  356. cbSdkResult res;
  357. res = cbSdkGetTime(m_instance, &cbTime);
  358. if (res != 0)
  359. {
  360. m_acq->error("cbSdkGetTime returned {} (in getDigInEvData)", res);
  361. return ReturnCode::NoValidTimestamp;
  362. }
  363. return ReturnCode::Success;
  364. }
  365. CereConn::ReturnCode CereConn::getCbTime(uint32_t &cbTime)
  366. {
  367. cbSdkResult res;
  368. if (m_state == State::Invalid || m_state == State::Closed)
  369. {
  370. m_console->warn("CereConn::getCbTime called while not recording.");
  371. return ReturnCode::NotRecording;
  372. }
  373. res = cbSdkGetTime(m_instance, &cbTime);
  374. if (res != 0)
  375. {
  376. m_acq->error("cbSdkGetTime returned {}", res);
  377. return ReturnCode::NoValidTimestamp;
  378. }
  379. return ReturnCode::Success;
  380. }
  381. void CereConn::setEnabledSampleGroups(const SGroupBoolA &sgroups_enabled)
  382. {
  383. std::copy(sgroups_enabled.begin(), sgroups_enabled.end(), m_sample_groups_enabled.begin());
  384. }
  385. void CereConn::setSampleGroup(const size_t group, const bool state)
  386. {
  387. m_sample_groups_enabled[group - 1] = state;
  388. }
  389. bool CereConn::getSampleGroup(const size_t group) const
  390. {
  391. return m_sample_groups_enabled[group - 1];
  392. }
  393. bool CereConn::setCARChannels(const size_t group, const ChannelNumList_t &carChannelList)
  394. {
  395. if (mp_sbpe)
  396. {
  397. mp_sbpe->setCARChannels(group, carChannelList);
  398. }
  399. return m_pRb->setCARChannels(group, carChannelList);
  400. }
  401. bool CereConn::setCARChannels(const size_t group, ChannelNumList_t &&carChannelList)
  402. {
  403. if (mp_sbpe)
  404. {
  405. mp_sbpe->setCARChannels(group, carChannelList);
  406. }
  407. return m_pRb->setCARChannels(group, carChannelList);
  408. }
  409. void CereConn::disableCAR(const size_t group)
  410. {
  411. if (mp_sbpe)
  412. {
  413. mp_sbpe->disableCAR(group);
  414. }
  415. m_pRb->disableCAR(group);
  416. }
  417. void CereConn::printBufferState() const
  418. {
  419. std::array<size_t, constants::NSampleGroups> ofc = m_pRb->getOverflowCount();
  420. for (unsigned int i = 0; i < constants::NSampleGroups; ++i)
  421. {
  422. m_acq->info("Sample group {} Buffer overflow counter: {}", i+1, ofc[i]);
  423. }
  424. }
  425. void CereConn::spikeRateEstimatorSetUp()
  426. {
  427. using namespace std::literals;
  428. mp_sre = std::make_unique<sre::SpikeRateEstimator>(constants::MaxFEChannels, constants::MaxUnits, 200, 100ms);
  429. if (mp_sre)
  430. {
  431. mp_sre->set_logger(m_console);
  432. if (mp_rateRB)
  433. {
  434. mp_sre->attachSpikeRateRB(mp_rateRB);
  435. }
  436. mp_sre->bindCallback([](const sre::SpikeRateEstimator::unit_hist_type& uh){ return r_estimate_with_boxcar_w_cont(uh, 10);});
  437. mp_sre->bindTimestampCallback([this](){Timestamp_t cbTime = 0; cbSdkGetTime(m_instance, &cbTime); return cbTime;});
  438. }
  439. }
  440. void CereConn::spikeRateEstimatorStart()
  441. {
  442. if (mp_sre)
  443. {
  444. m_console->debug("Starting SpikeRateEstimator");
  445. mp_sre->signalStart();
  446. }
  447. else
  448. {
  449. m_console->warn("CereConn::spikeRateEstimatorStart: spike rate estimator not initialised");
  450. }
  451. }
  452. void CereConn::spikeRateEstimatorStop()
  453. {
  454. if (mp_sre)
  455. {
  456. m_console->debug("Stopping SpikeRateEstimator");
  457. mp_sre->signalStop();
  458. }
  459. else
  460. {
  461. m_console->warn("CereConn::spikeRateEstimatorStop: spike rate estimator not initialised");
  462. }
  463. }
  464. void CereConn::setSpikeRateEstimatorChannelUnitList(const sre::SpikeRateEstimator::ch_un_list_type & ch_un_list)
  465. {
  466. if (mp_sre)
  467. {
  468. m_console->debug("CereConn::setSpikeRateEstimatorChannelUnitList: change channel unit map");
  469. mp_sre->setChannelUnitList(ch_un_list);
  470. }
  471. else
  472. {
  473. m_console->warn("CereConn::setSpikeRateEstimatorChannelUnitList: spike rate estimator not initialised");
  474. }
  475. }
  476. void CereConn::fillSpikeRateEstimatorChannelUnitList(const sre::SpikeRateEstimator::size_type n_channels, const sre::SpikeRateEstimator::size_type n_units)
  477. {
  478. if (mp_sre)
  479. {
  480. m_console->debug("CereConn::fillSpikeRateEstimatorChannelUnitList: change channel unit map");
  481. mp_sre->fillChannelUnitList(n_channels, n_units);
  482. }
  483. else
  484. {
  485. m_console->warn("CereConn::fillSpikeRateEstimatorChannelUnitList: spike rate estimator not initialised");
  486. }
  487. }
  488. std::pair<sre::SpikeRateEstimator::ch_un_list_type, sre::SpikeRateEstimator::ch_un_map_type> CereConn::getSpikeRateEstimatorChannelUnitMapping() const
  489. {
  490. if (mp_sre)
  491. {
  492. return mp_sre->getChannelUnitMapping();
  493. }
  494. else
  495. {
  496. m_console->warn("CereConn::getSpikeRateEstimatorChannelUnitMapping: spike rate estimator not initialised");
  497. return std::make_pair<sre::SpikeRateEstimator::ch_un_list_type, sre::SpikeRateEstimator::ch_un_map_type>({},{});
  498. }
  499. }
  500. sre::SpikeRateEstimator::ch_un_list_type CereConn::getSpikeRateEstimatorChannelUnitList() const
  501. {
  502. if (mp_sre)
  503. {
  504. return mp_sre->getChannelUnitList();
  505. }
  506. else
  507. {
  508. m_console->warn("CereConn::getSpikeRateEstimatorChannelUnitList: spike rate estimator not initialised");
  509. return sre::SpikeRateEstimator::ch_un_list_type({});
  510. }
  511. }
  512. void CereConn::setSpikeRateEstimatorLoopInterval(const sre::SpikeRateEstimator::rate_interval_type & new_interval)
  513. {
  514. if (mp_sre)
  515. {
  516. mp_sre->setSpikeRateLoopInterval(new_interval);
  517. }
  518. }
  519. sre::SpikeRateEstimator::rate_interval_type CereConn::getSpikeRateEstimatorLoopInterval() const
  520. {
  521. if (mp_sre)
  522. {
  523. return mp_sre->getSpikeRateLoopInterval();
  524. }
  525. else
  526. {
  527. return sre::SpikeRateEstimator::rate_interval_type{0};
  528. }
  529. }
  530. void CereConn::setSpikeRateEstimatorLoopIntervalMS(const unsigned int & new_interval)
  531. {
  532. if (mp_sre)
  533. {
  534. std::chrono::milliseconds new_interval_ms{new_interval};
  535. mp_sre->setSpikeRateLoopInterval(std::chrono::duration_cast<sre::SpikeRateEstimator::rate_interval_type>(new_interval_ms));
  536. }
  537. }
  538. unsigned int CereConn::getSpikeRateEstimatorLoopIntervalMS() const
  539. {
  540. if (mp_sre)
  541. {
  542. return std::chrono::duration_cast<std::chrono::milliseconds>(mp_sre->getSpikeRateLoopInterval()).count();
  543. }
  544. else
  545. {
  546. return 0;
  547. }
  548. }
  549. void CereConn::bindSpikeRateEstimatorCallback(const sre::SpikeRateEstimator::rate_callback_type& rcb)
  550. {
  551. if (mp_sre)
  552. {
  553. mp_sre->bindCallback(rcb);
  554. }
  555. }
  556. void CereConn::spikeRateEstimatorId()
  557. {
  558. const sre::SpikeRateEstimator::rate_callback_type rcb = [](const sre::SpikeRateEstimator::unit_hist_type& uh){ return r_estimate_id_w_cont(uh);};
  559. bindSpikeRateEstimatorCallback(rcb);
  560. }
  561. void CereConn::spikeRateEstimatorBoxcar(const size_t length)
  562. {
  563. const sre::SpikeRateEstimator::rate_callback_type rcb = [length](const sre::SpikeRateEstimator::unit_hist_type& uh){ return r_estimate_with_boxcar_w_cont(uh, length);};
  564. bindSpikeRateEstimatorCallback(rcb);
  565. }
  566. void CereConn::spikeRateEstimatorExp(const double decay_factor, const size_t max_length)
  567. {
  568. const sre::SpikeRateEstimator::rate_callback_type rcb = [decay_factor, max_length](const sre::SpikeRateEstimator::unit_hist_type& uh){ return r_estimate_with_exp_decay_w_cont(uh, decay_factor, max_length);};
  569. bindSpikeRateEstimatorCallback(rcb);
  570. }
  571. CereConn::ReturnCode CereConn::getSpikeRateData(sre::SpikeRateEstimator::rate_list_type &srl, uint32_t &cbTime)
  572. {
  573. size_t oc;
  574. return getSpikeRateData(srl, cbTime, oc);
  575. }
  576. CereConn::ReturnCode CereConn::getSpikeRateData(sre::SpikeRateEstimator::rate_list_type &srl, uint32_t &cbTime, size_t &overflowCount)
  577. {
  578. if (m_state != State::Recording)
  579. {
  580. m_console->warn("CereConn::getSpikeRateData called while not recording.");
  581. return ReturnCode::NotRecording;
  582. }
  583. if (!mp_rateRB)
  584. {
  585. m_console->warn("CereConn::getSpikeRateData has no spike rate buffer.");
  586. return ReturnCode::InvalidSpikeRateBuffer;
  587. }
  588. if (!mp_sre)
  589. {
  590. m_console->warn("CereConn::getSpikeRateData: no Spike Rate Estimator present.");
  591. return ReturnCode::InvalidSpikeRateEstimator;
  592. }
  593. if (mp_sre->ringBufferInvalid())
  594. {
  595. m_console->warn("CereConn::getSpikeRateData: spike rate buffer is invalid.");
  596. return ReturnCode::InvalidSpikeRateBuffer;
  597. }
  598. if (mp_rateRB->wasEmpty())
  599. {
  600. m_console->debug("spike rate ring buffer estimated empty");
  601. }
  602. mp_rateRB->consume(srl, overflowCount);
  603. cbSdkResult res;
  604. res = cbSdkGetTime(m_instance, &cbTime);
  605. if (res != 0)
  606. {
  607. m_acq->error("cbSdkGetTime returned {}", res);
  608. return ReturnCode::CbSdkError;
  609. }
  610. return ReturnCode::Success;
  611. }
  612. void CereConn::spikeBandPowerEstimatorSetUp()
  613. {
  614. using namespace std::literals;
  615. mp_sbpe = std::make_unique<sbpe::SpikeBandPowerEstimator>(constants::MaxFEChannels, 50ms);
  616. if (mp_sbpe)
  617. {
  618. mp_sbpe->setLogger(m_console);
  619. if (mp_sbpRB)
  620. {
  621. mp_sbpe->attachSpikeBandPowerRB(mp_sbpRB);
  622. }
  623. mp_sbpe->bindTimestampCallback([this](){Timestamp_t cbTime = 0; cbSdkGetTime(m_instance, &cbTime); return cbTime;});
  624. }
  625. }
  626. void CereConn::spikeBandPowerEstimatorStart()
  627. {
  628. if (mp_sbpe)
  629. {
  630. m_console->debug("Starting SpikeBandPowerEstimator");
  631. mp_sbpe->reset(m_sgroup_chlist[mp_sbpe->getAcceptedSampleGroup() - 1]);
  632. mp_sbpe->signalStart();
  633. }
  634. else
  635. {
  636. m_console->warn("CereConn::spikeBandPowerEstimatorStart: spike band power estimator not initialised");
  637. }
  638. }
  639. void CereConn::spikeBandPowerEstimatorStop()
  640. {
  641. if (mp_sbpe)
  642. {
  643. m_console->debug("Stopping SpikeBandPowerEstimator");
  644. mp_sbpe->signalStop();
  645. }
  646. else
  647. {
  648. m_console->warn("CereConn::spikeBandPowerEstimatorStop: spike band power estimator not initialised");
  649. }
  650. }
  651. void CereConn::setSpikeBandPowerEstimatorChannelList(const sbpe::SpikeBandPowerEstimator::ch_list_type & ch_list)
  652. {
  653. if (mp_sbpe)
  654. {
  655. m_console->debug("CereConn::setSpikeBandPowerEstimatorChannelList: change channel map");
  656. mp_sbpe->setChannelList(ch_list);
  657. }
  658. else
  659. {
  660. m_console->warn("CereConn::setSpikeBandPowerEstimatorChannelList: spike band power estimator not initialised");
  661. }
  662. }
  663. void CereConn::fillSpikeBandPowerEstimatorChannelList(const sbpe::SpikeBandPowerEstimator::size_type n_channels)
  664. {
  665. if (mp_sbpe)
  666. {
  667. mp_sbpe->fillChannelList(n_channels);
  668. }
  669. }
  670. std::pair<sbpe::SpikeBandPowerEstimator::ch_list_type, sbpe::SpikeBandPowerEstimator::ch_map_type> CereConn::getSpikeBandPowerEstimatorChannelMapping() const
  671. {
  672. if (mp_sbpe)
  673. {
  674. return mp_sbpe->getChannelMapping();
  675. }
  676. else
  677. {
  678. m_console->warn("CereConn::getSpikeBandPowerEstimatorChannelMapping: spike band power estimator not initialised");
  679. return std::make_pair<sbpe::SpikeBandPowerEstimator::ch_list_type, sbpe::SpikeBandPowerEstimator::ch_map_type>({},{});
  680. }
  681. }
  682. sbpe::SpikeBandPowerEstimator::ch_list_type CereConn::getSpikeBandPowerEstimatorChannelList() const
  683. {
  684. if (mp_sbpe)
  685. {
  686. return mp_sbpe->getChannelList();
  687. }
  688. else
  689. {
  690. m_console->warn("CereConn::getSpikeBandPowerEstimatorChannelList: spike band power estimator not initialised");
  691. return sbpe::SpikeBandPowerEstimator::ch_list_type({});
  692. }
  693. }
  694. void CereConn::setSpikeBandPowerEstimatorLoopInterval(const sbpe::SpikeBandPowerEstimator::sbp_interval_type & new_interval)
  695. {
  696. if (mp_sbpe)
  697. {
  698. mp_sbpe->setLoopInterval(new_interval);
  699. }
  700. }
  701. sbpe::SpikeBandPowerEstimator::sbp_interval_type CereConn::getSpikeBandPowerEstimatorLoopInterval() const
  702. {
  703. if (mp_sbpe)
  704. {
  705. return mp_sbpe->getLoopInterval();
  706. }
  707. else
  708. {
  709. return sbpe::SpikeBandPowerEstimator::sbp_interval_type{0};
  710. }
  711. }
  712. void CereConn::setSpikeBandPowerEstimatorLoopIntervalMS(const unsigned int & new_interval)
  713. {
  714. if (mp_sre)
  715. {
  716. std::chrono::milliseconds new_interval_ms{new_interval};
  717. mp_sbpe->setLoopInterval(std::chrono::duration_cast<sre::SpikeRateEstimator::rate_interval_type>(new_interval_ms));
  718. }
  719. }
  720. unsigned int CereConn::getSpikeBandPowerEstimatorLoopIntervalMS() const
  721. {
  722. if (mp_sbpe)
  723. {
  724. return std::chrono::duration_cast<std::chrono::milliseconds>(mp_sbpe->getLoopInterval()).count();
  725. }
  726. else
  727. {
  728. return 0;
  729. }
  730. }
  731. void CereConn::setSpikeBandPowerEstimatorAcceptedSampleGroup(const size_t group)
  732. {
  733. if (mp_sbpe)
  734. {
  735. mp_sbpe->setAcceptedSampleGroup(group);
  736. }
  737. }
  738. size_t CereConn::getSpikeBandPowerEstimatorAcceptedSampleGroup() const
  739. {
  740. if (mp_sbpe)
  741. {
  742. return mp_sbpe->getAcceptedSampleGroup();
  743. }
  744. else
  745. {
  746. return 0;
  747. }
  748. }
  749. void CereConn::setSpikeBandPowerEstimatorIIRFilterNSamples(const size_t n_samples)
  750. {
  751. if (mp_sbpe)
  752. {
  753. mp_sbpe->setIIRFilterNSamples(n_samples);
  754. }
  755. }
  756. size_t CereConn::getSpikeBandPowerEstimatorIIRFilterNSamples() const
  757. {
  758. if (mp_sbpe)
  759. {
  760. return mp_sbpe->getIIRFilterNSamples();
  761. }
  762. else
  763. {
  764. return 0;
  765. }
  766. }
  767. void CereConn::setSpikeBandPowerEstimatorAvgNBins(const size_t n_bins)
  768. {
  769. if (mp_sbpe)
  770. {
  771. mp_sbpe->setRMSNBins(n_bins);
  772. }
  773. }
  774. size_t CereConn::getSpikeBandPowerEstimatorAvgNBins() const
  775. {
  776. if (mp_sbpe)
  777. {
  778. return mp_sbpe->getRMSNBins();
  779. }
  780. else
  781. {
  782. return 0;
  783. }
  784. }
  785. void CereConn::setSpikeBandPowerEstimatorIIRFilterCoeffs(const sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type &b, const sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type &a)
  786. {
  787. if (mp_sbpe)
  788. {
  789. mp_sbpe->setIIRFilterCoeffs(b, a);
  790. }
  791. }
  792. std::pair<sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type, sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type> CereConn::getSpikeBandPowerEstimatorIIRFilterCoeffs() const
  793. {
  794. if (mp_sbpe)
  795. {
  796. return mp_sbpe->getIIRFilterCoeffs();
  797. }
  798. else
  799. {
  800. return std::make_pair<>(sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type(), sbpe::SpikeBandPowerEstimator::iir_filt_coeff_type());
  801. }
  802. }
  803. CereConn::ReturnCode CereConn::getSpikeBandPowerData(sbpe::SpikeBandPowerEstimator::sbp_list_type &sbpl, uint32_t &cbTime)
  804. {
  805. size_t overflowCount;
  806. return getSpikeBandPowerData(sbpl, cbTime, overflowCount);
  807. }
  808. CereConn::ReturnCode CereConn::getSpikeBandPowerData(sbpe::SpikeBandPowerEstimator::sbp_list_type &sbpl, uint32_t &cbTime, size_t &overflowCount)
  809. {
  810. if (m_state != State::Recording)
  811. {
  812. m_console->warn("CereConn::getSpikeBandPowerData called while not recording.");
  813. return ReturnCode::NotRecording;
  814. }
  815. if (!mp_sbpRB)
  816. {
  817. m_console->warn("CereConn::getSpikeBandPowerData has no spike band power buffer.");
  818. return ReturnCode::InvalidSpikeBandPowerBuffer;
  819. }
  820. if (!mp_sbpe)
  821. {
  822. m_console->warn("CereConn::getSpikeBandPowerData: no Spike Band Power Estimator present.");
  823. return ReturnCode::InvalidSpikeBandPowerEstimator;
  824. }
  825. if (mp_sbpe->ringBufferInvalid())
  826. {
  827. m_console->warn("CereConn::getSpikeBandPowerData: spike band power buffer is invalid.");
  828. return ReturnCode::InvalidSpikeBandPowerBuffer;
  829. }
  830. mp_sbpRB->consume(sbpl, overflowCount);
  831. cbSdkResult res;
  832. res = cbSdkGetTime(m_instance, &cbTime);
  833. if (res != 0)
  834. {
  835. m_acq->error("cbSdkGetTime returned {}", res);
  836. return ReturnCode::CbSdkError;
  837. }
  838. return ReturnCode::Success;
  839. }
  840. void CereConn::cbSdkCallbackContinuous(uint32_t nInstance, const cbSdkPktType type, const void* pPkt)
  841. {
  842. cbPKT_GROUP * pPktSgrp = (cbPKT_GROUP *) pPkt;
  843. const uint32_t group = pPktSgrp->type;
  844. if (mp_sbpe)
  845. {
  846. mp_sbpe->addSamplesFromPacket(pPktSgrp);
  847. }
  848. // ignore if group ignored
  849. if (!m_sample_groups_enabled[group - 1])
  850. {
  851. return;
  852. }
  853. m_pRb->addSamplesFromPacket(pPktSgrp);
  854. }
  855. void CereConn::cbSdkCallbackContinuous(uint32_t nInstance, const cbSdkPktType type, const void* pPkt, void* pCallbackData)
  856. {
  857. CereConn *me = reinterpret_cast<CereConn*>(pCallbackData);
  858. me->cbSdkCallbackContinuous(nInstance, type, pPkt);
  859. }
  860. void CereConn::cbSdkCallbackSpike(uint32_t nInstance, const cbSdkPktType type, const void* pPkt)
  861. {
  862. const cbPKT_SPK * pSpk = (const cbPKT_SPK *) pPkt;
  863. SpikeRingBuffer::BufType spk(*pSpk);
  864. m_pSRb->push(spk);
  865. if (mp_sre)
  866. {
  867. mp_sre->addSpike(pSpk->chid, pSpk->unit);
  868. }
  869. m_acq->debug("pkt time: {}, chid: {}, unit: {}", pSpk->time, pSpk->chid, pSpk->unit);
  870. }
  871. void CereConn::cbSdkCallbackSpike(uint32_t nInstance, const cbSdkPktType type, const void* pPkt, void* pCallbackData)
  872. {
  873. CereConn *me = reinterpret_cast<CereConn*>(pCallbackData);
  874. me->cbSdkCallbackSpike(nInstance, type, pPkt);
  875. }
  876. void CereConn::cbSdkCallbackComment(uint32_t nInstance, const cbSdkPktType type, const void* pPkt)
  877. {
  878. const cbPKT_COMMENT * pCmt = (const cbPKT_COMMENT *) pPkt;
  879. CommentRingBuffer::BufType comment(*pCmt);
  880. // m_acq->debug("received comment: time: {}, comment: {}, data: {}", comment.timestamp, comment.comment, comment.data);
  881. m_pCRb->push(comment);
  882. }
  883. void CereConn::cbSdkCallbackComment(uint32_t nInstance, const cbSdkPktType type, const void* pPkt, void* pCallbackData)
  884. {
  885. CereConn *me = reinterpret_cast<CereConn*>(pCallbackData);
  886. me->cbSdkCallbackComment(nInstance, type, pPkt);
  887. }
  888. void CereConn::cbSdkCallbackDigInEv(uint32_t nInstance, const cbSdkPktType type, const void* pPkt)
  889. {
  890. const cbPKT_DINP * pDIE = (const cbPKT_DINP *) pPkt;
  891. DigInEvRingBuffer::BufType digInEv(*pDIE);
  892. m_pDIRb->push(digInEv);
  893. }
  894. void CereConn::cbSdkCallbackDigInEv(uint32_t nInstance, const cbSdkPktType type, const void* pPkt, void* pCallbackData)
  895. {
  896. CereConn *me = reinterpret_cast<CereConn*>(pCallbackData);
  897. me->cbSdkCallbackDigInEv(nInstance, type, pPkt);
  898. }
  899. void CereConn::cbSdkCallbackGroupInfo(uint32_t nInstance, const cbSdkPktType type, const void* pPkt)
  900. {
  901. const cbPKT_GROUPINFO * pGI = (const cbPKT_GROUPINFO *) pPkt;
  902. updateGroupChannelList(pGI->group);
  903. m_acq->info("Group Info Callback called, group {} changed", pGI->group);
  904. }
  905. void CereConn::cbSdkCallbackGroupInfo(uint32_t nInstance, const cbSdkPktType type, const void* pPkt, void* pCallbackData)
  906. {
  907. CereConn *me = reinterpret_cast<CereConn*>(pCallbackData);
  908. me->cbSdkCallbackGroupInfo(nInstance, type, pPkt);
  909. }
  910. void CereConn::updateGroupChannelList(const uint32_t group)
  911. {
  912. uint32_t length;
  913. const uint32_t group0 = group - 1;
  914. m_sgroup_changed[group0] = true;
  915. cbSdkGetSampleGroupInfo(m_instance, 1, group, nullptr, nullptr, &length);
  916. m_sgroup_chlist[group0].resize(length);
  917. cbSdkGetSampleGroupList(m_instance, 1, group, nullptr, m_sgroup_chlist[group0].data());
  918. m_pRb->reset(group, m_sgroup_chlist[group0]);
  919. if (mp_sbpe)
  920. {
  921. mp_sbpe->reset(group, m_sgroup_chlist[group0]);
  922. }
  923. std::ostringstream oss;
  924. std::for_each(m_sgroup_chlist[group0].cbegin(), m_sgroup_chlist[group0].cend(), [&oss](auto x){oss << x << ", ";} );
  925. m_acq->debug("Channel ID list for sampling group {}: [{}]", group, oss.str());
  926. }
  927. void CereConn::updateGroupChannelLists()
  928. {
  929. for (uint32_t i = 1; i <= cc::constants::NSampleGroups; ++i)
  930. {
  931. updateGroupChannelList(i);
  932. }
  933. }
  934. } // namespace cc