Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

cbHwlibHi.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. // =STS=> cbHwlibHi.cpp[1688].aa22 submit SMID:23
  2. //////////////////////////////////////////////////////////////////////////////////////////////////
  3. //
  4. // (c) Copyright 2003 - 2008 Cyberkinetics, Inc.
  5. // (c) Copyright 2008 - 2012 Blackrock Microsystems
  6. //
  7. // $Workfile: cbHwlibHi.cpp $
  8. // $Archive: /Cerebus/WindowsApps/cbhwlib/cbHwlibHi.cpp $
  9. // $Revision: 13 $
  10. // $Date: 4/05/04 11:29a $
  11. // $Author: Kkorver $
  12. //
  13. // $NoKeywords: $
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////
  16. #include "StdAfx.h" // MFC core and standard components
  17. #include "debugmacs.h"
  18. #include "cbHwlibHi.h"
  19. #include "math.h"
  20. #include "cki_common.h"
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char THIS_FILE[]=__FILE__;
  24. #endif
  25. ///////////////////////////////////////////////////////////////////////////////////////////////////
  26. // Author & Date: Kirk Korver 30 Jan 2006
  27. // Purpose: tell me if CentralSim is running, or is it regular central
  28. // Outputs:
  29. // TRUE means CentralSIM is running; FALSE, Central
  30. bool IsSimRunning(uint32_t nInstance)
  31. {
  32. #ifdef WIN32
  33. uint32_t nIdx = cb_library_index[nInstance];
  34. char szTitle[255] = "";
  35. ::GetWindowText(static_cast<HWND>(cb_cfg_buffer_ptr[nIdx]->hwndCentral), szTitle, sizeof(szTitle));
  36. if (strstr(szTitle, "SIM"))
  37. return true;
  38. else
  39. return false;
  40. #else
  41. return (cbCheckApp("SIM") == cbRESULT_OK);
  42. #endif
  43. }
  44. // TRUE means yes; FALSE, no
  45. bool IsSpikeProcessingEnabled(uint32_t nChan, uint32_t nInstance)
  46. {
  47. uint32_t dwFlags;
  48. if (cbRESULT_OK != ::cbGetAinpSpikeOptions(nChan, &dwFlags, NULL, nInstance))
  49. return false;
  50. return (dwFlags & cbAINPSPK_EXTRACT) ? true : false;
  51. }
  52. // TRUE means yes; FALSE, no
  53. bool IsContinuousProcessingEnabled(uint32_t nChan, uint32_t nInstance)
  54. {
  55. // In the case where the call fails, we will still return FALSE.
  56. uint32_t nGroup = 0;
  57. ::cbGetAinpSampling(nChan, NULL, &nGroup, nInstance);
  58. return nGroup == 0 ? false : true;
  59. }
  60. // TRUE means yes; FALSE, no
  61. bool IsRawProcessingEnabled(uint32_t nChan, uint32_t nInstance)
  62. {
  63. // In the case where the call fails, we will still return FALSE.
  64. uint32_t nainpopts = 0;
  65. ::cbGetAinpOpts( nChan, &nainpopts, NULL, NULL, nInstance);
  66. return ((nainpopts & cbAINP_RAWSTREAM_ENABLED) == 0 ? false : true);
  67. }
  68. // TRUE means yes; FALSE, no
  69. bool IsChanSerial(uint32_t dwChan)
  70. {
  71. if ((dwChan >= MIN_CHANS_SERIAL) && (dwChan <= MAX_CHANS_SERIAL))
  72. return true;
  73. return false;
  74. }
  75. // TRUE means yes; FALSE, no
  76. bool IsChanDigin(uint32_t dwChan)
  77. {
  78. if ((dwChan >= MIN_CHANS_DIGITAL_IN) && (dwChan <= MAX_CHANS_DIGITAL_IN))
  79. return true;
  80. return false;
  81. }
  82. bool IsChanDigout(uint32_t dwChan)
  83. {
  84. if ((dwChan >= MIN_CHANS_DIGITAL_OUT) && (dwChan <= MAX_CHANS_DIGITAL_OUT))
  85. return true;
  86. return false;
  87. }
  88. // Author & Date: Almut Branner 15 Jan 2004
  89. // Purpose: Find out whether an analog in channel
  90. // Input: nChannel - the channel ID that we want to check
  91. bool IsChanAnalogIn(uint32_t dwChan)
  92. {
  93. if ((dwChan >= MIN_CHANS) && (dwChan <= MAX_CHANS_ANALOG_IN))
  94. return true;
  95. return false;
  96. }
  97. // Author & Date: Almut Branner 15 Jan 2004
  98. // Purpose: Find out whether a channel is a Front-End analog in channel
  99. // Input: nChannel - the channel ID that we want to check
  100. bool IsChanFEAnalogIn(uint32_t dwChan)
  101. {
  102. if ((dwChan >= MIN_CHANS) && (dwChan <= MAX_CHANS_FRONT_END))
  103. return true;
  104. return false;
  105. }
  106. // Author & Date: Almut Branner 15 Jan 2004
  107. // Purpose: Find out whether a channel is a Analog-In analog in channel
  108. // Input: nChannel - the channel ID that we want to check
  109. bool IsChanAIAnalogIn(uint32_t dwChan)
  110. {
  111. if ((dwChan >= MIN_CHANS_ANALOG_IN) && (dwChan <= MAX_CHANS_ANALOG_IN))
  112. return true;
  113. return false;
  114. }
  115. // Author & Date: Almut Branner 21 Nov 2003
  116. // Purpose: Find out whether a channel is continuously sampled
  117. // Input: nChannel - the channel ID that we want to check
  118. bool IsChanCont(uint32_t dwChan, uint32_t nInstance)
  119. {
  120. uint32_t nGroup = 0;
  121. ::cbGetAinpSampling(dwChan, NULL, &nGroup, nInstance);
  122. return (nGroup != 0);
  123. }
  124. // Author & Date: Kirk Korver 29 Oct 2003
  125. // Purpose: Tell me if this channel is enabled
  126. // Inputs:
  127. // nChannel - the channel of interest (1 based)
  128. // Outputs:
  129. // TRUE if the channel is enabled; FALSE, otherwise
  130. bool IsChannelEnabled(uint32_t nChannel, uint32_t nInstance)
  131. {
  132. ASSERT(nChannel >=1);
  133. ASSERT(nChannel <= MAX_CHANS_DIGITAL_OUT);
  134. if (nChannel <= MAX_CHANS_ANALOG_IN)
  135. return IsAnalogInEnabled(nChannel);
  136. if (nChannel <= MAX_CHANS_ANALOG_OUT)
  137. return IsAnalogOutEnabled(nChannel);
  138. if (nChannel <= MAX_CHANS_AUDIO)
  139. return IsAudioEnabled(nChannel);
  140. if (nChannel <= MAX_CHANS_DIGITAL_IN)
  141. return IsDigitalInEnabled(nChannel);
  142. if (nChannel <= MAX_CHANS_SERIAL)
  143. return IsSerialEnabled(nChannel, nInstance);
  144. if (nChannel <= MAX_CHANS_DIGITAL_OUT)
  145. return IsDigitalOutEnabled(nChannel, nInstance);
  146. return false;
  147. }
  148. // Author & Date: Kirk Korver 29 Oct 2003
  149. // Purpose: Tell me if this channel is enabled
  150. // Inputs:
  151. // nChannel - the channel of interest (1 based)
  152. // Outputs:
  153. // TRUE if the channel is enabled; FALSE, otherwise
  154. bool IsAnalogInEnabled(uint32_t nChannel)
  155. {
  156. TRACE("*** ::IsAnalogInEnabled *** not functional\n");
  157. return true;
  158. }
  159. // Author & Date: Kirk Korver 29 Oct 2003
  160. // Purpose: Tell me if this channel is enabled
  161. // Inputs:
  162. // nChannel - the channel of interest (1 based)
  163. // Outputs:
  164. // TRUE if the channel is enabled; FALSE, otherwise
  165. bool IsAnalogOutEnabled(uint32_t nChannel)
  166. {
  167. TRACE("*** ::IsAnalogOutEnabled *** not functional\n");
  168. return true;
  169. }
  170. // Author & Date: Kirk Korver 29 Oct 2003
  171. // Purpose: Tell me if this channel is enabled
  172. // Inputs:
  173. // nChannel - the channel of interest (1 based)
  174. // Outputs:
  175. // TRUE if the channel is enabled; FALSE, otherwise
  176. bool IsAudioEnabled(uint32_t nChannel)
  177. {
  178. TRACE("*** ::IsAudioEnabled *** not functional\n");
  179. return true;
  180. }
  181. // Author & Date: Kirk Korver 29 Oct 2003
  182. // Purpose: Tell me if this channel is enabled
  183. // Inputs:
  184. // nChannel - the channel of interest (1 based)
  185. // Outputs:
  186. // TRUE if the channel is enabled; FALSE, otherwise
  187. bool IsDigitalInEnabled(uint32_t nChannel)
  188. {
  189. TRACE("*** ::IsDigitalInEnabled *** not functional\n");
  190. return true;
  191. }
  192. // Author & Date: Kirk Korver 29 Oct 2003
  193. // Purpose: Tell me if this channel is enabled
  194. // Inputs:
  195. // nChannel - the channel of interest (1 based)
  196. // Outputs:
  197. // TRUE if the channel is enabled; FALSE, otherwise
  198. bool IsSerialEnabled(uint32_t nChannel, uint32_t nInstance)
  199. {
  200. uint32_t nOptions;
  201. ::cbGetDinpOptions(nChannel, &nOptions, NULL, nInstance);//get EOPchar
  202. if (nOptions & cbDINP_SERIALMASK)
  203. return true;
  204. else
  205. return false;
  206. }
  207. // Author & Date: Kirk Korver 29 Oct 2003
  208. // Purpose: Tell me if this channel is enabled
  209. // Inputs:
  210. // nChannel - the channel of interest (1 based)
  211. // Outputs:
  212. // TRUE if the channel is enabled; FALSE, otherwise
  213. bool IsDigitalOutEnabled(uint32_t nChannel, uint32_t nInstance)
  214. {
  215. uint32_t nOptions;
  216. cbGetDoutOptions(nChannel, &nOptions, NULL, NULL, NULL, NULL, NULL, nInstance);
  217. return (nOptions & cbDOUT_1BIT) ? true : false;
  218. }
  219. // Author & Date: Almut Branner 6 Nov 2003
  220. // Purpose: Tell me whether hoops are defined for a channel
  221. // Inputs: nChannel - the channel of interest
  222. // Outputs: TRUE if hoops are defined, FALSE, otherwise
  223. bool AreHoopsDefined(uint32_t nChannel, uint32_t nInstance)
  224. {
  225. cbHOOP hoops[cbMAXUNITS][cbMAXHOOPS];
  226. cbGetAinpSpikeHoops(nChannel, &hoops[0][0], nInstance);
  227. for (uint32_t nUnit = 0; nUnit < cbMAXUNITS; ++nUnit)
  228. if (hoops[nUnit][0].valid)
  229. return true;
  230. return false;
  231. }
  232. // Author & Date: Kirk Korver 24 Mar 2004
  233. // Purpose: tell me if there are hoops for this channel and unit
  234. // Inputs:
  235. // nChannel - the 1 based channel number
  236. // nUnit - the 0 based unit number
  237. bool AreHoopsDefined(uint32_t nChannel, uint32_t nUnit, uint32_t nInstance)
  238. {
  239. cbHOOP hoops[cbMAXUNITS][cbMAXHOOPS];
  240. cbGetAinpSpikeHoops(nChannel, &hoops[0][0], nInstance);
  241. if (hoops[nUnit][0].valid)
  242. return true;
  243. else
  244. return false;
  245. }
  246. // Author & Date: Ehsan Azar June 3, 2009
  247. // Purpose: determine if a channel has valid sorting unit
  248. // Input: nChannel = channel to track 1 - based
  249. // dwUnit the unit number (1=< dwUnit <=cbMAXUNITS)
  250. bool cbHasValidUnit(uint32_t dwChan, uint32_t dwUnit, uint32_t nInstance)
  251. {
  252. uint32_t nIdx = cb_library_index[nInstance];
  253. cbSPIKE_SORTING *pSortingOptions = &cb_cfg_buffer_ptr[nIdx]->isSortingOptions;
  254. if (dwUnit > cbMAXUNITS)
  255. return false;
  256. return (pSortingOptions->asSortModel[dwChan - 1][dwUnit].valid == TRUE);
  257. }
  258. // Author & Date: Ehsan Azar June 2, 2009
  259. // Purpose: Return if given channel has a sorting algorithm
  260. // If cbAINPSPK_ALLSORT is passed it returns if there is any sorting
  261. // If cbAINPSPK_NOSORT is passed it returns if there is no sorting
  262. // Input: spkSrtOpt = Sorting methods:
  263. // cbAINPSPK_HOOPSORT, cbAINPSPK_SPREADSORT,
  264. // cbAINPSPK_CORRSORT, cbAINPSPK_PEAKMAJSORT,
  265. // cbAINPSPK_PEAKFISHSORT, cbAINPSPK_PCAMANSORT,
  266. // cbAINPSPK_NOSORT, cbAINPSPK_OLDAUTOSORT,
  267. // cbAINPSPK_ALLSORT
  268. bool cbHasSpikeSorting(uint32_t dwChan, uint32_t spkSrtOpt, uint32_t nInstance)
  269. {
  270. uint32_t dwFlags;
  271. ::cbGetAinpSpikeOptions(dwChan, &dwFlags, NULL, nInstance);
  272. if (spkSrtOpt == cbAINPSPK_NOSORT)
  273. return ((dwFlags & cbAINPSPK_ALLSORT) == cbAINPSPK_NOSORT);
  274. else if (spkSrtOpt == cbAINPSPK_ALLSORT)
  275. return ((dwFlags & cbAINPSPK_ALLSORT) != cbAINPSPK_NOSORT);
  276. else
  277. return ((dwFlags & spkSrtOpt) != cbAINPSPK_NOSORT);
  278. }
  279. // Author & Date: Ehsan Azar June 2, 2009
  280. // Purpose: Set a sorting algorithm for a channel
  281. // Input: spkSrtOpt = Sorting methods:
  282. // cbAINPSPK_HOOPSORT, cbAINPSPK_SPREADSORT,
  283. // cbAINPSPK_CORRSORT, cbAINPSPK_PEAKMAJSORT,
  284. // cbAINPSPK_PEAKFISHSORT, cbAINPSPK_PCAMANSORT,
  285. // cbAINPSPK_NOSORT
  286. cbRESULT cbSetSpikeSorting(uint32_t dwChan, uint32_t spkSrtOpt, uint32_t nInstance)
  287. {
  288. uint32_t dwFlags, dwFilter;
  289. ::cbGetAinpSpikeOptions(dwChan, &dwFlags, &dwFilter, nInstance);
  290. dwFlags &= ~(cbAINPSPK_ALLSORT) ; // Delete all sortings first
  291. dwFlags |= spkSrtOpt; // Add requested sorting only
  292. cbRESULT nRet = ::cbSetAinpSpikeOptions(dwChan, dwFlags, dwFilter, nInstance);
  293. return nRet;
  294. }
  295. // Author & Date: Almut Branner Dec 9, 2003
  296. // Purpose: Set all output channels to track a particular channel
  297. // Input: nChannel = channel to track 1 - based
  298. void TrackChannel(uint32_t nChannel, uint32_t nInstance)
  299. {
  300. int32_t smpdispmax = 0;
  301. int32_t spkdispmax = 0;
  302. // Only do this if the channel is an analog input channel
  303. if ( (nChannel >= MIN_CHANS) && (nChannel <= MAX_CHANS_ANALOG_IN) )
  304. {
  305. // scan through the analog output channels
  306. // if channel exists and is set to track, update its source channel
  307. for (int aoutch = MIN_CHANS_ANALOG_OUT; aoutch <= MAX_CHANS_AUDIO; ++aoutch)
  308. {
  309. uint32_t options, monchan, value;
  310. if (cbGetAoutOptions(aoutch, &options, &monchan, &value, nInstance)==cbRESULT_OK)
  311. {
  312. if (options & cbAOUT_TRACK)
  313. {
  314. cbSetAoutOptions(aoutch, options, nChannel, value, nInstance);
  315. ///// Now adjust any of the analog output monitoring /////
  316. // Get the input scaling
  317. cbSCALING isInScaling;
  318. ::cbGetAinpDisplay(nChannel, NULL, &smpdispmax, &spkdispmax, NULL);
  319. ::cbGetAinpScaling(nChannel, &isInScaling, nInstance);
  320. if (options & cbAOUT_MONITORSMP) // Monitoring the continuous signal
  321. {
  322. int32_t nAnaMax = smpdispmax * isInScaling.anamax / isInScaling.digmax;
  323. cbSCALING isOutScaling;
  324. isOutScaling.digmin = -smpdispmax;
  325. isOutScaling.digmax = smpdispmax;
  326. isOutScaling.anamin = -nAnaMax;
  327. isOutScaling.anamax = nAnaMax;
  328. strncpy(isOutScaling.anaunit, isInScaling.anaunit, sizeof(isOutScaling.anaunit));
  329. ::cbSetAoutScaling(aoutch, &isOutScaling, nInstance);
  330. }
  331. if (options & cbAOUT_MONITORSPK) // Monitoring the spikes
  332. {
  333. int32_t nAnaMax = spkdispmax * isInScaling.anamax / isInScaling.digmax;
  334. cbSCALING isOutScaling;
  335. isOutScaling.digmin = -spkdispmax;
  336. isOutScaling.digmax = spkdispmax;
  337. isOutScaling.anamin = -nAnaMax;
  338. isOutScaling.anamax = nAnaMax;
  339. strncpy(isOutScaling.anaunit, isInScaling.anaunit, sizeof(isOutScaling.anaunit));
  340. ::cbSetAoutScaling(aoutch, &isOutScaling, nInstance);
  341. }
  342. }
  343. }
  344. }
  345. // Now scan through the Digital Out channels and set them
  346. for (int nChan = MIN_CHANS_DIGITAL_OUT; nChan <= MAX_CHANS_DIGITAL_OUT; ++nChan)
  347. {
  348. uint32_t nOptions, nVal;
  349. if (cbRESULT_OK == ::cbGetDoutOptions(nChan, &nOptions, NULL, &nVal, NULL, NULL, NULL, nInstance))
  350. {
  351. // Now if we are set to track, then change the monitored channel
  352. if (nOptions & cbDOUT_TRACK)
  353. {
  354. ::cbSetDoutOptions(nChan, nOptions, nChannel, nVal, cbDOUT_TRIGGER_NONE, 0, 0, nInstance);
  355. }
  356. }
  357. }
  358. }
  359. }
  360. // Author & Date: Kirk Korver 10 Feb 2004
  361. // Purpose: update the analog input scaling. If there is an Analog Output
  362. // channel which is monitoring this channel, then update the output
  363. // scaling to match the displayed scaling
  364. // Inputs:
  365. // chan - the analog input channel being altered (1 based)
  366. // smpdispmax - the maximum digital value of the continuous display
  367. // spkdispmax - the maximum digital value of the spike display
  368. // lncdispmax - the maximum digital value of the LNC display
  369. cbRESULT cbSetAnaInOutDisplay(uint32_t chan, int32_t smpdispmax, int32_t spkdispmax, int32_t lncdispmax, uint32_t nInstance)
  370. {
  371. cbRESULT retVal;
  372. // Start off by sending the new Analog In scaling
  373. retVal = ::cbSetAinpDisplay(chan, -smpdispmax, smpdispmax, spkdispmax, lncdispmax, nInstance);
  374. if (retVal != cbRESULT_OK)
  375. return retVal;
  376. ///// Now adjust any of the analog output monitoring /////
  377. // There are 6 analog channels of interest
  378. // They happen to be numbered so that AnalogOut and AudioOut are continuous
  379. for (uint32_t nAnaChan = MIN_CHANS_ANALOG_OUT; nAnaChan <= MAX_CHANS_AUDIO; ++nAnaChan)
  380. {
  381. uint32_t dwOptions = 0;
  382. uint32_t dwMonChan = 0;
  383. ::cbGetAoutOptions(nAnaChan, &dwOptions, &dwMonChan, NULL, nInstance);
  384. if (dwMonChan == chan)
  385. {
  386. // Get the input scaling
  387. cbSCALING isInScaling;
  388. retVal = ::cbGetAinpScaling(chan, &isInScaling, nInstance);
  389. if (retVal != cbRESULT_OK)
  390. return retVal;
  391. if (dwOptions & cbAOUT_MONITORSMP) // Monitoring the continuous signal
  392. {
  393. int32_t nAnaMax = smpdispmax * isInScaling.anamax / isInScaling.digmax;
  394. cbSCALING isOutScaling;
  395. isOutScaling.digmin = -smpdispmax;
  396. isOutScaling.digmax = smpdispmax;
  397. isOutScaling.anamin = -nAnaMax;
  398. isOutScaling.anamax = nAnaMax;
  399. strncpy(isOutScaling.anaunit, isInScaling.anaunit, sizeof(isOutScaling.anaunit));
  400. retVal = ::cbSetAoutScaling(nAnaChan, &isOutScaling, nInstance);
  401. if (retVal != cbRESULT_OK)
  402. return retVal;
  403. }
  404. else if (dwOptions & cbAOUT_MONITORSPK) // Monitoring the spikes
  405. {
  406. int32_t nAnaMax = spkdispmax * isInScaling.anamax / isInScaling.digmax;
  407. cbSCALING isOutScaling;
  408. isOutScaling.digmin = -spkdispmax;
  409. isOutScaling.digmax = spkdispmax;
  410. isOutScaling.anamin = -nAnaMax;
  411. isOutScaling.anamax = nAnaMax;
  412. strncpy(isOutScaling.anaunit, isInScaling.anaunit, sizeof(isOutScaling.anaunit));
  413. retVal = ::cbSetAoutScaling(nAnaChan, &isOutScaling, nInstance);
  414. if (retVal != cbRESULT_OK)
  415. return retVal;
  416. }
  417. }
  418. }
  419. return retVal;
  420. }
  421. // Author & Date: Hyrum L. Sessions 25 Jan 2006
  422. // Purpose: Get the scaling of spike and analog channels
  423. // Inputs: nChan - the 1 based channel of interest
  424. // anSpikeScale - pointer to array to store spike scaling
  425. // anContScale - pointer to array to store continuous scaling
  426. // anLncScale - pointer to array to store LNC scaling
  427. cbRESULT cbGetScaling(uint32_t nChan,
  428. uint32_t *anSpikeScale,
  429. uint32_t *anContScale,
  430. uint32_t *anLncScale,
  431. uint32_t nInstance)
  432. {
  433. cbRESULT retVal;
  434. cbSCALING isScaling;
  435. int32_t nAnaMax;
  436. int i;
  437. if (nChan < MIN_CHANS || nChan > MAX_CHANS_ANALOG_IN)
  438. return cbRESULT_INVALIDCHANNEL;
  439. retVal = ::cbGetAinpScaling(nChan, &isScaling, nInstance);
  440. if (retVal != cbRESULT_OK)
  441. return retVal;
  442. nAnaMax = isScaling.anamax / isScaling.anagain;
  443. if (nChan <= MAX_CHANS_FRONT_END)
  444. {
  445. if (anContScale)
  446. {
  447. for (i = 0; i < SCALE_CONTINUOUS_COUNT; ++i)
  448. anContScale[SCALE_CONTINUOUS_COUNT - i - 1] = uint32_t(nAnaMax * exp(-0.3467 * i));
  449. }
  450. if (anLncScale)
  451. {
  452. for (i = 0; i < SCALE_LNC_COUNT; ++i)
  453. anLncScale[SCALE_LNC_COUNT - i - 1] = uint32_t(nAnaMax * exp(-0.3467 * i));
  454. }
  455. if (anSpikeScale)
  456. {
  457. for (i = 0; i < SCALE_SPIKE_COUNT; ++i)
  458. anSpikeScale[SCALE_SPIKE_COUNT - i - 1] = uint32_t(0.25 * nAnaMax * exp(-0.3467 / 2.0 * i));
  459. anSpikeScale[SCALE_SPIKE_COUNT - 1] = nAnaMax;
  460. anSpikeScale[SCALE_SPIKE_COUNT - 2] = nAnaMax / 2;
  461. anSpikeScale[SCALE_SPIKE_COUNT - 3] = nAnaMax / 4;
  462. }
  463. }
  464. else
  465. {
  466. if (anContScale)
  467. for (i = 0; i < SCALE_CONTINUOUS_COUNT; ++i)
  468. anContScale[SCALE_CONTINUOUS_COUNT - i - 1] = uint32_t(nAnaMax * exp(-0.3467 * i));
  469. if (anLncScale)
  470. for (i = 0; i < SCALE_LNC_COUNT; ++i)
  471. anLncScale[SCALE_LNC_COUNT - i - 1] = uint32_t(nAnaMax * exp(-0.3467 * i));
  472. if (anSpikeScale)
  473. for (i = 0; i < SCALE_SPIKE_COUNT; ++i)
  474. anSpikeScale[SCALE_SPIKE_COUNT - i - 1] = uint32_t(nAnaMax * exp(-0.3467 * i / 2.0));
  475. }
  476. return cbRESULT_OK;
  477. }
  478. ////////////////////////////// acquisition groups ////////////////////////////////////////////////
  479. // These will be ordered by group so I don't need that
  480. struct cbAcqSettings
  481. {
  482. uint32_t nFilter; // Which filter
  483. uint32_t nSampleGroup; // Which sample group
  484. };
  485. const cbAcqSettings isAcqData[ACQ_GROUP_COUNT] =
  486. {
  487. // Filter (Low pass) Sample Group
  488. {6, /* don't care (was 1)*/ 0 /* not sampling */}, // match "startup"
  489. {8, /* 150 Hz Low (was 5)*/ 2 /* 1 kS/sec */ },
  490. {6, /* 250 Hz Low (was 1)*/ 2 /* 1 kS/sec */ },
  491. {9, /* 10-250 Hz Band (was 4)*/ 2 /* 1 kS/sec */ },
  492. {7, /* 500 Hz Low (was 2)*/ 3 /* 2 kS/sec */ },
  493. {10, /* 2.5 kHz Low (was 6)*/ 4 /* 10 kS/sec */ },
  494. {0, /* NONE - HW only (7.5 kHz) */ 5 /* 30 kS/sec */ },
  495. {2, /* 250 Hz High (was 3)*/ 5 /* 30 kS/sec */ },
  496. {8, 5 },
  497. };
  498. // Author & Date: Ehsan Azar 28 May 2009
  499. // Purpose: tell which sampling group this channel is part of
  500. // Inputs:
  501. // nChan - the 1 based channel of interest
  502. // Outpus:
  503. // 0 means SMPGRP_NONE
  504. uint32_t cbGetSmpGroup(uint32_t nChan, uint32_t nInstance)
  505. {
  506. uint32_t dwGroup;
  507. ::cbGetAinpSampling(nChan, NULL, &dwGroup, nInstance);
  508. return dwGroup;
  509. }
  510. // Author & Date: Ehsan Azar 28 May 2009
  511. // Purpose: tell me how many sampling groups exist
  512. // this number will always be larger than 1 because group 0 (empty)
  513. // will always exist
  514. uint32_t cbGetSmpGroupCount()
  515. {
  516. return SMP_GROUP_COUNT;
  517. }
  518. // Author & Date: Kirk Korver 02 Nov 2005
  519. // Purpose: tell which acquisition group this channel is part of
  520. // See SetAcqGroup
  521. // Inputs:
  522. // nChan - the 1 based channel of interest
  523. // Outpus:
  524. // 0 means not part of any acquisition group; 1+ means part of that group
  525. // Note: Do not use this function to find the sampling rate,
  526. // use cbGetSmpGroup instead.
  527. uint32_t cbGetAcqGroup(uint32_t nChan, uint32_t nInstance)
  528. {
  529. uint32_t nFilter = 0;
  530. uint32_t nSG = 0;
  531. ::cbGetAinpSampling(nChan, &nFilter, &nSG, nInstance);
  532. for (const cbAcqSettings * pTest = isAcqData; pTest != ARRAY_END(isAcqData); ++pTest)
  533. {
  534. if (pTest->nFilter == nFilter &&
  535. pTest->nSampleGroup == nSG)
  536. {
  537. return uint32_t(pTest - &isAcqData[0]);
  538. }
  539. }
  540. // If I got here then then was no match. I had better make it "not sample"
  541. // and return that.
  542. cbSetAcqGroup(nChan, 0, nInstance);
  543. return 0;
  544. }
  545. // Author & Date: Kirk Korver 02 Nov 2005
  546. // Purpose: tell which acquisition group this channel is part of
  547. // See SetAcqGroup
  548. // Inputs:
  549. // nChan - the 1 based channel of interest
  550. // nGroup - the group to now belong to: 0 = not in a grup; 1+, a member of that group
  551. // Outpus:
  552. // 0 means not part of any acquisition group; 1+ means part of that group
  553. cbRESULT cbSetAcqGroup(uint32_t nChan, uint32_t nGroup, uint32_t nInstance)
  554. {
  555. if (nGroup >= ACQ_GROUP_COUNT)
  556. return cbRESULT_INVALIDFUNCTION;
  557. uint32_t nFilter = isAcqData[nGroup].nFilter;
  558. uint32_t nSG = isAcqData[nGroup].nSampleGroup;
  559. cbRESULT nRet = ::cbSetAinpSampling(nChan, nFilter, nSG, nInstance);
  560. return nRet;
  561. }
  562. // Purpose: tell me how many acquisition groups exist
  563. // this number will always be larger than 1 because group 0 (empty)
  564. // will always exist
  565. uint32_t cbGetAcqGroupCount()
  566. {
  567. return ACQ_GROUP_COUNT;
  568. }
  569. const char * asContFilter[ACQ_GROUP_COUNT] =
  570. {
  571. "",
  572. "0.3 Hz - 150 Hz - 1 kS/s",
  573. "0.3 Hz - 250 Hz - 1 kS/s",
  574. "10 Hz - 250 Hz - 1 kS/s",
  575. "0.3 Hz - 500 Hz - 2 kS/s",
  576. "0.3 Hz - 2.5 kHz - 10 kS/s",
  577. "0.3 Hz - 7.5 kHz - 30 kS/s",
  578. "250 Hz - 7.5 kHz - 30 kS/s",
  579. "0.3 Hz - 150 Hz - 30 kS/s",
  580. };
  581. // Author & Date: Hyrum L. Sessions 25 May 2007
  582. // Purpose: get a textual description of the acquisition group
  583. // Inputs: nGroup - group in question
  584. // Outputs: pointer to the description of the group
  585. const char * cbGetAcqGroupDesc(uint32_t nGroup)
  586. {
  587. return asContFilter[nGroup < ACQ_GROUP_COUNT ? nGroup : 0];
  588. }
  589. // Author & Date: Hyrum L. Sessions 29 May 2007
  590. // Purpose: get the filter used by an acquision group
  591. // Inputs: nGroup - group in question
  592. // Outputs: filter value
  593. uint32_t cbGetAcqGroupFilter(uint32_t nGroup)
  594. {
  595. return isAcqData[nGroup < ACQ_GROUP_COUNT ? nGroup : 0].nFilter;
  596. }
  597. // Author & Date: Hyrum L. Sessions 29 May 2007
  598. // Purpose: get the sample group used by an acquision group
  599. // Inputs: nGroup - group in question
  600. // Outputs: sample group value
  601. uint32_t cbGetAcqGroupSampling(uint32_t nGroup)
  602. {
  603. return isAcqData[nGroup < ACQ_GROUP_COUNT ? nGroup : 0].nSampleGroup;
  604. }
  605. // Purpose: get the number of units for this channel
  606. // Inputs: nChan - 1 based channel of interest
  607. // Returns: number of valid units for this channel
  608. uint32_t cbGetChanUnits(uint32_t nChan, uint32_t nInstance)
  609. {
  610. uint32_t nIdx = cb_library_index[nInstance];
  611. ASSERT(nChan >= MIN_CHANS);
  612. ASSERT(nChan <= cbMAXCHANS);
  613. uint32_t nValidUnits = 0;
  614. // let's start at 1 so we don't get the noise unit which is 0
  615. for (uint32_t i = 1; i < ARRAY_SIZE(cb_cfg_buffer_ptr[nIdx]->isSortingOptions.asSortModel[nChan]); ++i)
  616. {
  617. if (cb_cfg_buffer_ptr[nIdx]->isSortingOptions.asSortModel[nChan - 1][i].valid)
  618. ++nValidUnits;
  619. }
  620. return nValidUnits;
  621. }
  622. // Purpose: tells if the unit in the channel is valid
  623. // Inputs: nChan - 1 based channel of interest
  624. // nUnit - 1 based unit of interest (0 is noise unit)
  625. // Returns: 1 if the unit in the channel is valid, 0 is otherwise
  626. uint32_t cbIsChanUnitValid(uint32_t nChan, int32_t nUnit, uint32_t nInstance)
  627. {
  628. uint32_t nIdx = cb_library_index[nInstance];
  629. BOOL bValid = false;
  630. cbMANUALUNITMAPPING isUnitMapping[cbMAXUNITS];
  631. ASSERT(nChan >= MIN_CHANS);
  632. ASSERT(nChan <= cbMAXCHANS);
  633. ASSERT(nUnit <= cbMAXUNITS);
  634. // get the override array for the requested channel
  635. cbGetChanUnitMapping(nChan, &isUnitMapping[0], nInstance);
  636. // find a translated unit that points to this unit
  637. for (int i = 0; i < cbMAXUNITS; ++i)
  638. {
  639. if (nUnit == isUnitMapping[i].nOverride + 1) // zero based
  640. if ((cb_cfg_buffer_ptr[nIdx]->isSortingOptions.asSortModel[nChan - 1][isUnitMapping[i].nOverride + 1].valid) ||
  641. (isUnitMapping[i].bValid))
  642. {
  643. bValid = true;
  644. break;
  645. }
  646. }
  647. return bValid;
  648. }
  649. // Author & Date: Ehsan Azar 18 Nov 2010
  650. // Purpose: Set the noise boundary parameters (compatibility for int16_t)
  651. // Inputs:
  652. // chanIdx - channel number (1-based)
  653. // anCentroid - the center of an ellipsoid
  654. // anMajor - major axis of the ellipsoid
  655. // anMinor_1 - first minor axis of the ellipsoid
  656. // anMinor_2 - second minor axis of the ellipsoid
  657. // Outputs:
  658. // cbRESULT_OK if life is good
  659. cbRESULT cbSSSetNoiseBoundary(uint32_t chanIdx, int16_t anCentroid[3], int16_t anMajor[3], int16_t anMinor_1[3], int16_t anMinor_2[3], uint32_t nInstance)
  660. {
  661. float afCentroid[3], afMajor[3], afMinor_1[3], afMinor_2[3];
  662. for (int i = 0; i < 3; ++i) {
  663. afCentroid[i] = anCentroid[i];
  664. afMajor[i] = anMajor[i];
  665. afMinor_1[i] = anMinor_1[i];
  666. afMinor_2[i] = anMinor_2[i];
  667. }
  668. return cbSSSetNoiseBoundary(chanIdx, afCentroid, afMajor, afMinor_1, afMinor_2, nInstance);
  669. }
  670. // Author & Date: Ehsan Azar 19 Nov 2010
  671. // Purpose: Get NTrode unitmapping for a particular site
  672. // Inputs:
  673. // ntrode - NTrode number (1-based)
  674. // nSite - the site within NTrode (1 to cbMAXSITEPLOTS)
  675. // Outputs:
  676. // unitmapping - the unitmapping for the given site in given NTrode
  677. // cbRESULT_OK if life is good
  678. cbRESULT cbGetNTrodeUnitMapping(uint32_t ntrode, uint16_t nSite, cbMANUALUNITMAPPING *unitmapping, uint32_t nInstance)
  679. {
  680. uint32_t nIdx = cb_library_index[nInstance];
  681. // Test for prior library initialization
  682. if (!cb_library_initialized[nIdx]) return cbRESULT_NOLIBRARY;
  683. // Test that the NTrode number is valid and initialized
  684. if ((ntrode - 1) >= cbMAXNTRODES) return cbRESULT_INVALIDNTRODE;
  685. if (nSite >= cbMAXSITEPLOTS) return cbRESULT_INVALIDFUNCTION;
  686. if (cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].chid==0) return cbRESULT_INVALIDNTRODE;
  687. // Return the requested data from the rec buffer
  688. if (unitmapping) memcpy(unitmapping,&cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].ellipses[nSite][0],cbMAXUNITS*sizeof(cbMANUALUNITMAPPING));
  689. return cbRESULT_OK;
  690. }
  691. // Author & Date: Ehsan Azar 19 Nov 2010
  692. // Purpose: Set NTrode unitmapping of a particular site
  693. // Inputs:
  694. // ntrode - NTrode number (1-based)
  695. // nSite - the site within NTrode (1 to cbMAXSITEPLOTS)
  696. // unitmapping - the unitmapping for the given site in given NTrode
  697. // fs - if valid, set as new NTrode feature space otherwise leave unchanged
  698. // Outputs:
  699. // cbRESULT_OK if life is good
  700. cbRESULT cbSetNTrodeUnitMapping(uint32_t ntrode, uint16_t nSite, cbMANUALUNITMAPPING *unitmapping, int16_t fs, uint32_t nInstance)
  701. {
  702. uint32_t nIdx = cb_library_index[nInstance];
  703. // Test for prior library initialization
  704. if (!cb_library_initialized[nIdx]) return cbRESULT_NOLIBRARY;
  705. // Test that the NTrode number is valid and initialized
  706. if ((ntrode - 1) >= cbMAXNTRODES) return cbRESULT_INVALIDNTRODE;
  707. if (cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].chid == 0) return cbRESULT_INVALIDNTRODE;
  708. if (nSite >= cbMAXSITEPLOTS) return cbRESULT_INVALIDFUNCTION;
  709. if (fs < 0)
  710. fs = cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].fs; // previous feature space
  711. cbMANUALUNITMAPPING ellipses[cbMAXSITEPLOTS][cbMAXUNITS]; // for the mapping structure called in from the NSP
  712. char label[cbLEN_STR_LABEL];
  713. // Get previous ellipses
  714. cbGetNTrodeInfo(ntrode, label, ellipses, NULL, NULL, NULL, nInstance);
  715. if (unitmapping) memcpy(&ellipses[nSite][0], unitmapping, cbMAXUNITS * sizeof(cbMANUALUNITMAPPING));
  716. cbSetNTrodeInfo(ntrode, label, ellipses, fs, nInstance);
  717. return cbRESULT_OK;
  718. }
  719. // Author & Date: Ehsan Azar 19 Nov 2010
  720. // Purpose: Set NTrode feature space if changed, keeping the rest of NTrode information intact
  721. // Inputs:
  722. // ntrode - NTrode number (1-based)
  723. // fs - set as new NTrode feature space
  724. // Outputs:
  725. // cbRESULT_OK if life is good
  726. cbRESULT cbSetNTrodeFeatureSpace(uint32_t ntrode, uint16_t fs, uint32_t nInstance)
  727. {
  728. uint32_t nIdx = cb_library_index[nInstance];
  729. // Test for prior library initialization
  730. if (!cb_library_initialized[nIdx]) return cbRESULT_NOLIBRARY;
  731. // Test that the NTrode number is valid and initialized
  732. if ((ntrode - 1) >= cbMAXNTRODES) return cbRESULT_INVALIDNTRODE;
  733. if (cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].chid == 0) return cbRESULT_INVALIDNTRODE;
  734. // If feature space has changed
  735. if (fs != cb_cfg_buffer_ptr[nIdx]->isNTrodeInfo[ntrode - 1].fs)
  736. return cbSetNTrodeUnitMapping(ntrode, 0, NULL, fs, nInstance);
  737. return cbRESULT_OK;
  738. }
  739. // Author & Date: Ehsan Azar 6 Nov 2012
  740. // Purpose: Find if file recording is active
  741. // Outputs:
  742. // returns if file is being recorded
  743. bool IsFileRecording(uint32_t nInstance)
  744. {
  745. cbPKT_FILECFG filecfg;
  746. if (cbGetFileInfo(&filecfg, nInstance) == cbRESULT_OK)
  747. {
  748. if (filecfg.options == cbFILECFG_OPT_REC)
  749. return true;
  750. }
  751. return false;
  752. }