Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
OpenBCI_32bit_Library.cpp
00001 /* 00002 OpenBCI 32bit Library 00003 Place the containing folder into your libraries folder insdie the arduino folder in your Documents folder 00004 00005 This library will work with a single OpenBCI 32bit board, or 00006 an OpenBCI 32bit board with an OpenBCI Daisy Module attached. 00007 00008 */ 00009 00010 #include "OpenBCI_32bit_Library.h" 00011 00012 /***************************************************/ 00013 /** PUBLIC METHODS *********************************/ 00014 /***************************************************/ 00015 // CONSTRUCTOR 00016 OpenBCI_32bit_Library::OpenBCI_32bit_Library() { 00017 curBoardMode = OPENBCI_BOARD_MODE_DEFAULT; 00018 daisyPresent = false; 00019 sniffMode = false; 00020 useAccel = false; 00021 useAux = false; 00022 channelDataAvailable = false; 00023 initializeVariables(); 00024 } 00025 00026 /** 00027 * @description: The function the OpenBCI board will call in setup. 00028 * @author: AJ Keller (@pushtheworldllc) 00029 */ 00030 void OpenBCI_32bit_Library::begin(void) { 00031 curBoardMode = OPENBCI_BOARD_MODE_DEFAULT; 00032 // Bring the board up 00033 boardBegin(); 00034 } 00035 00036 /** 00037 * @description: The function the OpenBCI board will call in setup. Turns sniff mode 00038 * on and allows you to tap into the serial port that is broken out on the OpenBCI 00039 * 32bit board. You must alter this file: 00040 * On Mac: 00041 * `/Users/username/Documents/Arduino/hardware/chipkit-core/pic32/variants/openbci/Board_Defs.h` 00042 * On Windows: 00043 * `C:\Users\username\Documents\Arduino\hardware\chipkit-core\pic32\variants\openbci\Board_Defs.h` 00044 * Specifically lines `311` and `313` from `7` and `10` to `11` and `12` for 00045 * `_SER1_TX_PIN` and `_SER1_RX_PIN` respectively. Check out this sweet gif if 00046 * you are a visual person http://g.recordit.co/3jH01sMD6Y.gif 00047 * You will need to reflash your board! But now you can connect to pins `11` 00048 * `12` via a FTDI serial port driver, really any serial to USB driver would 00049 * work. Remember to use 3V3, 115200 baud, and have a common ground! 00050 * @author: AJ Keller (@pushtheworldllc) 00051 */ 00052 void OpenBCI_32bit_Library::beginDebug(void) { 00053 // Bring the board up 00054 boolean started = boardBeginDebug(); 00055 curBoardMode = OPENBCI_BOARD_MODE_DEBUG; 00056 00057 sniffMode = true; 00058 00059 if (Serial1) { 00060 if (started) { 00061 Serial1.println("Board up"); 00062 } else { 00063 Serial1.println("Board err"); 00064 } 00065 00066 } 00067 } 00068 00069 /** 00070 * @description: The function the OpenBCI board will call in setup. This sets up the hardware serial port on D11 and D12 00071 * @author: AJ Keller (@pushtheworldllc) 00072 */ 00073 boolean OpenBCI_32bit_Library::beginSecondarySerial(void) { 00074 // Initalize the serial 1 port 00075 Serial1.begin(OPENBCI_BAUD_RATE); 00076 return true; 00077 } 00078 00079 00080 /** 00081 * @description Called in every `loop()` and checks `Serial0` 00082 * @returns {boolean} - `true` if there is data ready to be read 00083 */ 00084 boolean OpenBCI_32bit_Library::hasDataSerial0(void) { 00085 if (Serial0.available()) { 00086 return true; 00087 } else { 00088 return false; 00089 } 00090 } 00091 00092 /** 00093 * @description Called in every `loop()` and checks `Serial0` 00094 * @returns {boolean} - `true` if there is data ready to be read 00095 */ 00096 boolean OpenBCI_32bit_Library::hasDataSerial1(void) { 00097 if (Serial1.available()) { 00098 return true; 00099 } else { 00100 return false; 00101 } 00102 } 00103 00104 /** 00105 * @description Called if `hasDataSerial0` is true, returns a char from `Serial0` 00106 * @returns {char} - A char from the serial port 00107 */ 00108 char OpenBCI_32bit_Library::getCharSerial0(void) { 00109 return Serial0.read(); 00110 } 00111 00112 /** 00113 * @description Called if `hasDataSerial1` is true, returns a char from `Serial1` 00114 * @returns {char} - A char from the serial port 00115 */ 00116 char OpenBCI_32bit_Library::getCharSerial1(void) { 00117 return Serial1.read(); 00118 } 00119 00120 /** 00121 * @description If `isSerialAvailableForRead()` is `true` then this function is 00122 * called. Reads from `Serial0` first and foremost, which comes from the RFduino. 00123 * If `sniffMode` is true and `Serial0` didn't have any data, we will try to 00124 * read from `Serial1`. If both are not available then we will return a `0x00` 00125 * which is NOT a command that the system will recognize, aka this function has 00126 * many safe guards. 00127 * @returns {char} - The character from the serial port. 00128 */ 00129 // char OpenBCI_32bit_Library::readOneSerialChar(void) { 00130 // if (Serial0.available()) { 00131 // return Serial0.read(); 00132 // } else if (sniffMode && Serial1.available()) { 00133 // return Serial1.read(); 00134 // } else { 00135 // return 0x00; 00136 // } 00137 // } 00138 00139 /** 00140 * @description Public function for sending data to the PC 00141 * @param data {char *} - The data you want to send 00142 * @author AJ Keller (@pushtheworldllc) 00143 */ 00144 void OpenBCI_32bit_Library::writeSerial(char *data, int len) { 00145 for (int i = 0; i < len; i++) { 00146 Serial0.write(data[i]); 00147 } 00148 } 00149 00150 /** 00151 * @description While processing incoming multi byte messages these will turn 00152 * true. 00153 * @return {boolean} - True if processing a message and false otherwise 00154 */ 00155 boolean OpenBCI_32bit_Library::isProcessingMultibyteMsg(void) { 00156 return isProcessingIncomingSettingsChannel || isProcessingIncomingSettingsLeadOff || settingBoardMode; 00157 } 00158 00159 /** 00160 * @description Process one char at a time from serial port. This is the main 00161 * command processor for the OpenBCI system. Considered mission critical for 00162 * normal operation. 00163 * @param `character` {char} - The character to process. 00164 * @return {boolean} - `true` if the command was recognized, `false` if not 00165 */ 00166 boolean OpenBCI_32bit_Library::processChar(char character) { 00167 if (sniffMode && Serial1) { 00168 Serial1.print("pC: "); Serial1.println(character); 00169 } 00170 00171 if (isProcessingMultibyteMsg()) { 00172 if (isProcessingIncomingSettingsChannel) { 00173 processIncomingChannelSettings(character); 00174 } else if (isProcessingIncomingSettingsLeadOff) { 00175 processIncomingLeadOffSettings(character); 00176 } else if (settingBoardMode) { 00177 processIncomingBoardMode(character); 00178 } 00179 } else { // Normal... 00180 switch (character){ 00181 //TURN CHANNELS ON/OFF COMMANDS 00182 case OPENBCI_CHANNEL_OFF_1: 00183 streamSafeChannelDeactivate(1); 00184 break; 00185 case OPENBCI_CHANNEL_OFF_2: 00186 streamSafeChannelDeactivate(2); 00187 break; 00188 case OPENBCI_CHANNEL_OFF_3: 00189 streamSafeChannelDeactivate(3); 00190 break; 00191 case OPENBCI_CHANNEL_OFF_4: 00192 streamSafeChannelDeactivate(4); 00193 break; 00194 case OPENBCI_CHANNEL_OFF_5: 00195 streamSafeChannelDeactivate(5); 00196 break; 00197 case OPENBCI_CHANNEL_OFF_6: 00198 streamSafeChannelDeactivate(6); 00199 break; 00200 case OPENBCI_CHANNEL_OFF_7: 00201 streamSafeChannelDeactivate(7); 00202 break; 00203 case OPENBCI_CHANNEL_OFF_8: 00204 streamSafeChannelDeactivate(8); 00205 break; 00206 case OPENBCI_CHANNEL_OFF_9: 00207 streamSafeChannelDeactivate(9); 00208 break; 00209 case OPENBCI_CHANNEL_OFF_10: 00210 streamSafeChannelDeactivate(10); 00211 break; 00212 case OPENBCI_CHANNEL_OFF_11: 00213 streamSafeChannelDeactivate(11); 00214 break; 00215 case OPENBCI_CHANNEL_OFF_12: 00216 streamSafeChannelDeactivate(12); 00217 break; 00218 case OPENBCI_CHANNEL_OFF_13: 00219 streamSafeChannelDeactivate(13); 00220 break; 00221 case OPENBCI_CHANNEL_OFF_14: 00222 streamSafeChannelDeactivate(14); 00223 break; 00224 case OPENBCI_CHANNEL_OFF_15: 00225 streamSafeChannelDeactivate(15); 00226 break; 00227 case OPENBCI_CHANNEL_OFF_16: 00228 streamSafeChannelDeactivate(16); 00229 break; 00230 00231 case OPENBCI_CHANNEL_ON_1: 00232 streamSafeChannelActivate(1); 00233 break; 00234 case OPENBCI_CHANNEL_ON_2: 00235 streamSafeChannelActivate(2); 00236 break; 00237 case OPENBCI_CHANNEL_ON_3: 00238 streamSafeChannelActivate(3); 00239 break; 00240 case OPENBCI_CHANNEL_ON_4: 00241 streamSafeChannelActivate(4); 00242 break; 00243 case OPENBCI_CHANNEL_ON_5: 00244 streamSafeChannelActivate(5); 00245 break; 00246 case OPENBCI_CHANNEL_ON_6: 00247 streamSafeChannelActivate(6); 00248 break; 00249 case OPENBCI_CHANNEL_ON_7: 00250 streamSafeChannelActivate(7); 00251 break; 00252 case OPENBCI_CHANNEL_ON_8: 00253 streamSafeChannelActivate(8); 00254 break; 00255 case OPENBCI_CHANNEL_ON_9: 00256 streamSafeChannelActivate(9); 00257 break; 00258 case OPENBCI_CHANNEL_ON_10: 00259 streamSafeChannelActivate(10); 00260 break; 00261 case OPENBCI_CHANNEL_ON_11: 00262 streamSafeChannelActivate(11); 00263 break; 00264 case OPENBCI_CHANNEL_ON_12: 00265 streamSafeChannelActivate(12); 00266 break; 00267 case OPENBCI_CHANNEL_ON_13: 00268 streamSafeChannelActivate(13); 00269 break; 00270 case OPENBCI_CHANNEL_ON_14: 00271 streamSafeChannelActivate(14); 00272 break; 00273 case OPENBCI_CHANNEL_ON_15: 00274 streamSafeChannelActivate(15); 00275 break; 00276 case OPENBCI_CHANNEL_ON_16: 00277 streamSafeChannelActivate(16); 00278 break; 00279 00280 // TEST SIGNAL CONTROL COMMANDS 00281 case OPENBCI_TEST_SIGNAL_CONNECT_TO_GROUND: 00282 activateAllChannelsToTestCondition(ADSINPUT_SHORTED,ADSTESTSIG_NOCHANGE,ADSTESTSIG_NOCHANGE); 00283 break; 00284 case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_SLOW: 00285 activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_SLOW); 00286 break; 00287 case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_FAST: 00288 activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST); 00289 break; 00290 case OPENBCI_TEST_SIGNAL_CONNECT_TO_DC: 00291 activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_DCSIG); 00292 break; 00293 case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_SLOW: 00294 activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_SLOW); 00295 break; 00296 case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_FAST: 00297 activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_FAST); 00298 break; 00299 00300 00301 // CHANNEL SETTING COMMANDS 00302 case OPENBCI_CHANNEL_CMD_SET: // This is the first byte that tells us to expect more commands 00303 isProcessingIncomingSettingsChannel = true; 00304 numberOfIncomingSettingsProcessedChannel = 1; 00305 break; 00306 00307 // LEAD OFF IMPEDANCE DETECTION COMMANDS 00308 case OPENBCI_CHANNEL_IMPEDANCE_SET: 00309 isProcessingIncomingSettingsLeadOff = true; 00310 numberOfIncomingSettingsProcessedLeadOff = 1; 00311 break; 00312 00313 case OPENBCI_CHANNEL_DEFAULT_ALL_SET: // reset all channel settings to default 00314 if(!streaming) { 00315 Serial0.println("updating channel settings to default"); 00316 sendEOT(); 00317 } 00318 streamSafeSetAllChannelsToDefault(); 00319 break; 00320 case OPENBCI_CHANNEL_DEFAULT_ALL_REPORT: // report the default settings 00321 reportDefaultChannelSettings(); 00322 break; 00323 00324 00325 00326 // DAISY MODULE COMMANDS 00327 case OPENBCI_CHANNEL_MAX_NUMBER_8: // use 8 channel mode 00328 if(daisyPresent){ 00329 removeDaisy(); 00330 } 00331 break; 00332 case OPENBCI_CHANNEL_MAX_NUMBER_16: // use 16 channel mode 00333 if(daisyPresent == false){ 00334 attachDaisy(); 00335 } 00336 if(daisyPresent){ 00337 Serial0.print("16"); 00338 }else{ 00339 Serial0.print("8"); 00340 } 00341 sendEOT(); 00342 break; 00343 00344 // STREAM DATA AND FILTER COMMANDS 00345 case OPENBCI_STREAM_START: // stream data 00346 if(useAccel){ 00347 enable_accel(RATE_25HZ); 00348 } // fire up the accelerometer if you want it 00349 streamStart(); // turn on the fire hose 00350 break; 00351 case OPENBCI_STREAM_STOP: // stop streaming data 00352 if(useAccel){ 00353 disable_accel(); 00354 } // shut down the accelerometer if you're using it 00355 streamStop(); 00356 break; 00357 00358 // INITIALIZE AND VERIFY 00359 case OPENBCI_MISC_SOFT_RESET: 00360 boardReset(); // initialize ADS and read device IDs 00361 break; 00362 // QUERY THE ADS AND ACCEL REGITSTERS 00363 case OPENBCI_MISC_QUERY_REGISTER_SETTINGS: 00364 if (!streaming) { 00365 printAllRegisters(); // print the ADS and accelerometer register values 00366 } 00367 break; 00368 00369 // TIME SYNC 00370 case OPENBCI_TIME_SET: 00371 // Set flag to send time packet 00372 if (streaming) { 00373 sendTimeSyncUpPacket = true; 00374 } else { 00375 Serial0.print("Time stamp ON"); 00376 sendEOT(); 00377 } 00378 timeSynced = true; 00379 break; 00380 00381 case OPENBCI_TIME_STOP: 00382 // Stop the Sync 00383 timeSynced = false; 00384 if (!streaming) { 00385 Serial0.print("Time stamp OFF"); 00386 sendEOT(); 00387 } 00388 break; 00389 00390 // PACKET SET TYPE 00391 case OPENBCI_BOARD_MODE_SET: 00392 // Tell this function which case that is 00393 settingBoardMode = true; 00394 break; 00395 00396 default: 00397 return false; 00398 } 00399 } 00400 return true; 00401 } 00402 00403 /** 00404 * @description Reads a status register to see if there is new accelerometer 00405 * data. 00406 * @returns {boolean} `true` if the accelerometer has new data. 00407 */ 00408 boolean OpenBCI_32bit_Library::accelHasNewData(void) { 00409 return LIS3DH_DataAvailable(); 00410 } 00411 00412 /** 00413 * @description Reads from the accelerometer to get new X, Y, and Z data. Updates 00414 * the global array `axisData`. 00415 */ 00416 void OpenBCI_32bit_Library::accelUpdateAxisData(void) { 00417 LIS3DH_updateAxisData(); 00418 } 00419 00420 /** 00421 * @description Reads from the accelerometer to get new X, Y, and Z data. 00422 */ 00423 void OpenBCI_32bit_Library::accelWriteAxisData(void) { 00424 LIS3DH_writeAxisData(); 00425 } 00426 00427 /** 00428 * @description: This is a function that is called once and confiures all pins on 00429 * the PIC32 uC 00430 * @author: AJ Keller (@pushtheworldllc) 00431 */ 00432 boolean OpenBCI_32bit_Library::boardBegin(void) { 00433 // Initalize the serial port baud rate 00434 Serial0.begin(OPENBCI_BAUD_RATE); 00435 00436 pinMode(OPENBCI_PIN_LED, OUTPUT); 00437 pinMode(OPENBCI_PIN_PGC, OUTPUT); 00438 00439 // Startup for interrupt 00440 setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR 00441 setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority 00442 clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together 00443 setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq 00444 00445 // Do a soft reset 00446 boardReset(); 00447 00448 return true; 00449 } 00450 00451 /** 00452 * @description: This is a function that is called once and confiures all pins on 00453 * the PIC32 uC 00454 * @author: AJ Keller (@pushtheworldllc) 00455 */ 00456 boolean OpenBCI_32bit_Library::boardBeginDebug(void) { 00457 // Initalize the serial port baud rate 00458 Serial0.begin(OPENBCI_BAUD_RATE); 00459 00460 // Initalize the serial debug port 00461 Serial1.begin(OPENBCI_BAUD_RATE); 00462 00463 // Startup for interrupt 00464 setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR 00465 setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority 00466 clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together 00467 setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq 00468 00469 // Do a soft reset 00470 boardReset(); 00471 00472 return true; 00473 } 00474 00475 /** 00476 * @description: This is a function that is called once and confiures the Pic to run in secondary serial mode 00477 * @param baudRate {int} - The baudRate you want the secondary serial port to run at. 00478 * @author: AJ Keller (@pushtheworldllc) 00479 */ 00480 boolean OpenBCI_32bit_Library::boardBeginDebug(int baudRate) { 00481 // Initalize the serial port baud rate 00482 Serial0.begin(OPENBCI_BAUD_RATE); 00483 00484 // Initalize the serial debug port 00485 Serial1.begin(baudRate); 00486 00487 // Do a soft reset 00488 boardReset(); 00489 00490 return true; 00491 } 00492 00493 /** 00494 * @description: This is a function that can be called multiple times, this is 00495 * what we refer to as a `soft reset`. You will hear/see this 00496 * many times. 00497 * @author: AJ Keller (@pushtheworldllc) 00498 */ 00499 void OpenBCI_32bit_Library::boardReset(void) { 00500 initialize(); // initalizes accelerometer and on-board ADS and on-daisy ADS if present 00501 delay(500); 00502 00503 Serial0.println("OpenBCI V3 8-16 channel"); 00504 configureLeadOffDetection(LOFF_MAG_6NA, LOFF_FREQ_31p2HZ); 00505 Serial0.print("On Board ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_BOARD),HEX); 00506 if(daisyPresent){ // library will set this in initialize() if daisy present and functional 00507 Serial0.print("On Daisy ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_DAISY),HEX); 00508 } 00509 Serial0.print("LIS3DH Device ID: 0x"); Serial0.println(LIS3DH_getDeviceID(),HEX); 00510 Serial0.println("Firmware: v2.0.0"); 00511 sendEOT(); 00512 } 00513 00514 /** 00515 * @description: Simple method to send the EOT over serial... 00516 * @author: AJ Keller (@pushtheworldllc) 00517 */ 00518 void OpenBCI_32bit_Library::sendEOT(void) { 00519 Serial0.print("$$$"); 00520 } 00521 00522 00523 00524 void OpenBCI_32bit_Library::activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode) 00525 { 00526 boolean wasStreaming = streaming; 00527 00528 // Stop streaming if you are currently streaming 00529 if (streaming) { 00530 streamStop(); 00531 } 00532 00533 //set the test signal to the desired state 00534 configureInternalTestSignal(amplitudeCode,freqCode); 00535 //change input type settings for all channels 00536 changeInputType(testInputCode); 00537 00538 // Restart stream if need be 00539 if (wasStreaming) { 00540 streamStart(); 00541 } 00542 } 00543 00544 /** 00545 * @description When a 'z' is found on the serial port, we jump to this function 00546 * where we continue to read from the serial port and read the 00547 * remaining 4 bytes. 00548 * @param `character` - {char} - The character you want to process... 00549 */ 00550 void OpenBCI_32bit_Library::processIncomingBoardMode(char c) { 00551 00552 if (isValidBoardType(c)) { 00553 curBoardMode = c; 00554 if (!streaming) { 00555 Serial0.print("Success: Board type set"); 00556 sendEOT(); 00557 } 00558 } else { 00559 if (!streaming) { 00560 Serial0.print("Failure: invalid board mode"); 00561 sendEOT(); 00562 } 00563 } 00564 settingBoardMode = false; 00565 } 00566 00567 /** 00568 * @description When a 'x' is found on the serial port, we jump to this function 00569 * where we continue to read from the serial port and read the 00570 * remaining 7 bytes. 00571 */ 00572 void OpenBCI_32bit_Library::processIncomingChannelSettings(char character) { 00573 00574 if (character == OPENBCI_CHANNEL_CMD_LATCH && numberOfIncomingSettingsProcessedChannel < OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL - 1) { 00575 // We failed somehow and should just abort 00576 numberOfIncomingSettingsProcessedChannel = 0; 00577 00578 // put flag back down 00579 isProcessingIncomingSettingsChannel = false; 00580 00581 if (!streaming) { 00582 Serial0.print("Channel setting failure: too few chars"); sendEOT(); 00583 } 00584 00585 return; 00586 } 00587 switch (numberOfIncomingSettingsProcessedChannel) { 00588 case 1: // channel number 00589 currentChannelSetting = getChannelCommandForAsciiChar(character); 00590 break; 00591 case 2: // POWER_DOWN 00592 channelSettings[currentChannelSetting][POWER_DOWN] = getNumberForAsciiChar(character); 00593 break; 00594 case 3: // GAIN_SET 00595 channelSettings[currentChannelSetting][GAIN_SET] = getGainForAsciiChar(character); 00596 break; 00597 case 4: // INPUT_TYPE_SET 00598 channelSettings[currentChannelSetting][INPUT_TYPE_SET] = getNumberForAsciiChar(character); 00599 break; 00600 case 5: // BIAS_SET 00601 channelSettings[currentChannelSetting][BIAS_SET] = getNumberForAsciiChar(character); 00602 break; 00603 case 6: // SRB2_SET 00604 channelSettings[currentChannelSetting][SRB2_SET] = getNumberForAsciiChar(character); 00605 break; 00606 case 7: // SRB1_SET 00607 channelSettings[currentChannelSetting][SRB1_SET] = getNumberForAsciiChar(character); 00608 break; 00609 case 8: // 'X' latch 00610 if (character != OPENBCI_CHANNEL_CMD_LATCH) { 00611 if (!streaming) { 00612 Serial0.print("Err: 9th char not "); 00613 Serial0.println(OPENBCI_CHANNEL_CMD_LATCH); 00614 sendEOT(); 00615 } 00616 // We failed somehow and should just abort 00617 numberOfIncomingSettingsProcessedChannel = 0; 00618 00619 // put flag back down 00620 isProcessingIncomingSettingsChannel = false; 00621 00622 } 00623 break; 00624 default: // should have exited 00625 if (!streaming) { 00626 Serial0.print("Err: too many chars"); 00627 sendEOT(); 00628 } 00629 // We failed somehow and should just abort 00630 numberOfIncomingSettingsProcessedChannel = 0; 00631 00632 // put flag back down 00633 isProcessingIncomingSettingsChannel = false; 00634 return; 00635 } 00636 00637 // increment the number of bytes processed 00638 numberOfIncomingSettingsProcessedChannel++; 00639 00640 if (numberOfIncomingSettingsProcessedChannel == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL)) { 00641 // We are done processing channel settings... 00642 00643 if (!streaming) { 00644 Serial0.print("Channel set for "); Serial0.println(currentChannelSetting + 1); sendEOT(); 00645 } 00646 00647 if (sniffMode && Serial1) { 00648 Serial1.print("Channel set for "); Serial1.println(currentChannelSetting + 1); 00649 } 00650 00651 // Set channel settings 00652 streamSafeChannelSettingsForChannel(currentChannelSetting + 1, channelSettings[currentChannelSetting][POWER_DOWN], channelSettings[currentChannelSetting][GAIN_SET], channelSettings[currentChannelSetting][INPUT_TYPE_SET], channelSettings[currentChannelSetting][BIAS_SET], channelSettings[currentChannelSetting][SRB2_SET], channelSettings[currentChannelSetting][SRB1_SET]); 00653 00654 // Reset 00655 numberOfIncomingSettingsProcessedChannel = 0; 00656 00657 // put flag back down 00658 isProcessingIncomingSettingsChannel = false; 00659 } 00660 } 00661 00662 /** 00663 * @description When a 'z' is found on the serial port, we jump to this function 00664 * where we continue to read from the serial port and read the 00665 * remaining 4 bytes. 00666 * @param `character` - {char} - The character you want to process... 00667 */ 00668 void OpenBCI_32bit_Library::processIncomingLeadOffSettings(char character) { 00669 00670 if (character == OPENBCI_CHANNEL_IMPEDANCE_LATCH && numberOfIncomingSettingsProcessedLeadOff < OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF - 1) { 00671 // We failed somehow and should just abort 00672 // reset numberOfIncomingSettingsProcessedLeadOff 00673 numberOfIncomingSettingsProcessedLeadOff = 0; 00674 00675 // put flag back down 00676 isProcessingIncomingSettingsLeadOff = false; 00677 00678 if (!streaming) { 00679 Serial0.print("Lead off failure: too few chars"); sendEOT(); 00680 } 00681 00682 return; 00683 } 00684 switch (numberOfIncomingSettingsProcessedLeadOff) { 00685 case 1: // channel number 00686 currentChannelSetting = getChannelCommandForAsciiChar(character); 00687 break; 00688 case 2: // pchannel setting 00689 leadOffSettings[currentChannelSetting][PCHAN] = getNumberForAsciiChar(character); 00690 break; 00691 case 3: // nchannel setting 00692 leadOffSettings[currentChannelSetting][NCHAN] = getNumberForAsciiChar(character); 00693 break; 00694 case 4: // 'Z' latch 00695 if (character != OPENBCI_CHANNEL_IMPEDANCE_LATCH) { 00696 if (!streaming) { 00697 Serial0.print("Err: 5th char not "); 00698 Serial0.println(OPENBCI_CHANNEL_IMPEDANCE_LATCH); 00699 sendEOT(); 00700 } 00701 // We failed somehow and should just abort 00702 // reset numberOfIncomingSettingsProcessedLeadOff 00703 numberOfIncomingSettingsProcessedLeadOff = 0; 00704 00705 // put flag back down 00706 isProcessingIncomingSettingsLeadOff = false; 00707 00708 } 00709 break; 00710 default: // should have exited 00711 if (!streaming) { 00712 Serial0.print("Err: too many chars "); 00713 sendEOT(); 00714 } 00715 // We failed somehow and should just abort 00716 // reset numberOfIncomingSettingsProcessedLeadOff 00717 numberOfIncomingSettingsProcessedLeadOff = 0; 00718 00719 // put flag back down 00720 isProcessingIncomingSettingsLeadOff = false; 00721 return; 00722 } 00723 00724 // increment the number of bytes processed 00725 numberOfIncomingSettingsProcessedLeadOff++; 00726 00727 if (numberOfIncomingSettingsProcessedLeadOff == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF)) { 00728 // We are done processing lead off settings... 00729 00730 if (!streaming) { 00731 Serial0.print("Lead off set for "); Serial0.println(currentChannelSetting + 1); sendEOT(); 00732 } 00733 00734 if (sniffMode && Serial1) { 00735 Serial1.print("Lead off set for "); Serial1.println(currentChannelSetting + 1); 00736 } 00737 00738 // Set lead off settings 00739 streamSafeLeadOffSetForChannel(currentChannelSetting + 1,leadOffSettings[currentChannelSetting][PCHAN],leadOffSettings[currentChannelSetting][NCHAN]); 00740 00741 // reset numberOfIncomingSettingsProcessedLeadOff 00742 numberOfIncomingSettingsProcessedLeadOff = 0; 00743 00744 // put flag back down 00745 isProcessingIncomingSettingsLeadOff = false; 00746 } 00747 } 00748 00749 00750 boolean OpenBCI_32bit_Library::isValidBoardType(char c) { 00751 switch (c) { 00752 case OPENBCI_BOARD_MODE_DEFAULT: 00753 case OPENBCI_BOARD_MODE_DEBUG: 00754 case OPENBCI_BOARD_MODE_WIFI: 00755 case OPENBCI_BOARD_MODE_INPUT_ANALOG: 00756 case OPENBCI_BOARD_MODE_INPUT_DIGITAL: 00757 return true; 00758 default: 00759 return false; 00760 } 00761 } 00762 00763 00764 // <<<<<<<<<<<<<<<<<<<<<<<<< BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 00765 00766 void OpenBCI_32bit_Library::initialize(){ 00767 pinMode(SD_SS,OUTPUT); digitalWrite(SD_SS,HIGH); // de-select SDcard if present 00768 pinMode(BOARD_ADS, OUTPUT); digitalWrite(BOARD_ADS,HIGH); 00769 pinMode(DAISY_ADS, OUTPUT); digitalWrite(DAISY_ADS,HIGH); 00770 pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH); 00771 spi.begin(); 00772 spi.setSpeed(4000000); // use 4MHz for ADS and LIS3DH 00773 spi.setMode(DSPI_MODE0); // default to SD card mode! 00774 initialize_ads(); // hard reset ADS, set pin directions 00775 initialize_accel(SCALE_4G); // set pin directions, G scale, DRDY interrupt, power down 00776 initializeVariables(); 00777 } 00778 00779 // void __USER_ISR ADS_DRDY_Service() { 00780 void __USER_ISR ADS_DRDY_Service() { 00781 clearIntFlag(_EXTERNAL_4_IRQ); // clear the irq, or else it will continually interrupt! 00782 if(bitRead(PORTA,0) == 0){ 00783 board.channelDataAvailable = true; 00784 } 00785 } 00786 00787 void OpenBCI_32bit_Library::initializeVariables(void) { 00788 streaming = false; 00789 sendTimeSyncUpPacket = false; 00790 timeSynced = false; 00791 isProcessingIncomingSettingsChannel = false; 00792 isProcessingIncomingSettingsLeadOff = false; 00793 settingBoardMode = false; 00794 numberOfIncomingSettingsProcessedChannel = 0; 00795 numberOfIncomingSettingsProcessedLeadOff = 0; 00796 currentChannelSetting = 0; 00797 timeOffset = 0; 00798 timeSetCharArrived = 0; 00799 streamPacketType = (char)OPENBCI_PACKET_TYPE_V3; 00800 } 00801 00802 void OpenBCI_32bit_Library::printAllRegisters(){ 00803 if(!isRunning){ 00804 Serial0.println("\nBoard ADS Registers"); 00805 printADSregisters(BOARD_ADS); 00806 if(daisyPresent){ 00807 Serial0.println("\nDaisy ADS Registers"); 00808 printADSregisters(DAISY_ADS); 00809 } 00810 Serial0.println("\nLIS3DH Registers"); 00811 LIS3DH_readAllRegs(); 00812 sendEOT(); 00813 } 00814 } 00815 00816 /** 00817 * @description Writes channel data and `axisData` array to serial port in 00818 * the correct stream packet format. 00819 * 00820 * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h` 00821 */ 00822 void OpenBCI_32bit_Library::sendChannelDataWithAccel(void) { 00823 00824 Serial0.write(OPENBCI_SOP_SYMBOL); 00825 00826 Serial0.write(sampleCounter); // 1 byte 00827 00828 ADS_writeChannelData(); // 24 bytes 00829 00830 accelWriteAxisData(); // 6 bytes 00831 00832 Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xC0 00833 00834 sampleCounter++; 00835 00836 } 00837 00838 /** 00839 * @description Writes channel data and `auxData` array to serial port in 00840 * the correct stream packet format. 00841 * 00842 * Adds stop byte `OPENBCI_EOP_STND_RAW_AUX`. See `OpenBCI_32bit_Library_Definitions.h` 00843 */ 00844 void OpenBCI_32bit_Library::sendChannelDataWithRawAux(void) { 00845 00846 Serial0.write(OPENBCI_SOP_SYMBOL); 00847 00848 Serial0.write(sampleCounter); // 1 byte 00849 00850 ADS_writeChannelData(); // 24 bytes 00851 00852 writeAuxData(); // 6 bytes 00853 00854 Serial0.write(OPENBCI_EOP_STND_RAW_AUX); // 0xC1 - 1 byte 00855 00856 sampleCounter++; 00857 } 00858 00859 /** 00860 * @description Writes channel data, `axisData` array, and 4 byte unsigned time 00861 * stamp in ms to serial port in the correct stream packet format. 00862 * 00863 * `axisData` will be split up and sent on the samples with `sampleCounter` of 00864 * 7, 8, and 9 for X, Y, and Z respectively. Driver writers parse accordingly. 00865 * 00866 * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar` 00867 * getting a time sync set `<` command) then: 00868 * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SET` and sets `sendTimeSyncUpPacket` 00869 * to `false`. 00870 * Else if `sendTimeSyncUpPacket` is `false` then: 00871 * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SYNCED` 00872 */ 00873 void OpenBCI_32bit_Library::sendChannelDataWithTimeAndAccel(void) { 00874 00875 Serial0.write(OPENBCI_SOP_SYMBOL); 00876 00877 Serial0.write(sampleCounter); // 1 byte 00878 00879 ADS_writeChannelData(); // 24 bytes 00880 00881 // send two bytes of either accel data or blank 00882 switch (sampleCounter % 10) { 00883 case ACCEL_AXIS_X: // 7 00884 LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_X); 00885 break; 00886 case ACCEL_AXIS_Y: // 8 00887 LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Y); 00888 break; 00889 case ACCEL_AXIS_Z: // 9 00890 LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Z); 00891 break; 00892 default: 00893 Serial0.write((byte)0x00); // high byte 00894 Serial0.write((byte)0x00); // low byte 00895 break; 00896 } 00897 00898 writeTimeCurrent(); // 4 bytes 00899 00900 if (sendTimeSyncUpPacket) { 00901 sendTimeSyncUpPacket = false; 00902 Serial0.write(OPENBCI_EOP_ACCEL_TIME_SET); // 0xC3 00903 } else { 00904 Serial0.write(OPENBCI_EOP_ACCEL_TIME_SYNCED); // 0xC4 00905 } 00906 00907 sampleCounter++; 00908 } 00909 00910 /** 00911 * @description Writes channel data, `auxData[0]` 2 bytes, and 4 byte unsigned 00912 * time stamp in ms to serial port in the correct stream packet format. 00913 * 00914 * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar` 00915 * getting a time sync set `<` command) then: 00916 * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SET` and sets `sendTimeSyncUpPacket` 00917 * to `false`. 00918 * Else if `sendTimeSyncUpPacket` is `false` then: 00919 * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SYNCED` 00920 */ 00921 void OpenBCI_32bit_Library::sendChannelDataWithTimeAndRawAux(void) { 00922 00923 Serial0.print(OPENBCI_SOP_SYMBOL); 00924 00925 Serial0.write(sampleCounter); // 1 byte 00926 00927 ADS_writeChannelData(); // 24 bytes 00928 00929 Serial0.write(highByte(auxData[0])); // 2 bytes of aux data 00930 Serial0.write(lowByte(auxData[0])); 00931 00932 writeTimeCurrent(); // 4 bytes 00933 00934 if (sendTimeSyncUpPacket) { 00935 sendTimeSyncUpPacket = false; 00936 Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SET); // 0xC5 00937 } else { 00938 Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SYNCED); // 0xC6 00939 } 00940 00941 sampleCounter++; 00942 00943 } 00944 00945 /** 00946 * @description Writes channel data, aux data, and footer to serial port. This 00947 * is the old way to send channel data. Based on global variables `useAux` 00948 * and `useAccel` Must keep for portability. Will look to deprecate in 3.0.0. 00949 * 00950 * If `useAccel` is `true` then sends data from `axisData` array and sets the 00951 * contents of `axisData` to `0`. 00952 * If `useAux` is `true` then sends data from `auxData` array and sets the 00953 * contents of `auxData` to `0`. 00954 * 00955 * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h` 00956 */ 00957 void OpenBCI_32bit_Library::sendChannelData(void) { 00958 00959 Serial0.print(OPENBCI_SOP_SYMBOL); 00960 00961 Serial0.write(sampleCounter); // 1 byte 00962 ADS_writeChannelData(); // 24 bytes 00963 if(useAux){ 00964 writeAuxData(); // 6 bytes of aux data 00965 } else if(useAccel){ // or 00966 LIS3DH_writeAxisData(); // 6 bytes of accelerometer data 00967 } else{ 00968 for(int i=0; i<6; i++){ 00969 Serial0.write((byte)0x00); 00970 } 00971 } 00972 00973 Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xF0 00974 00975 sampleCounter++; 00976 } 00977 00978 void OpenBCI_32bit_Library::writeAuxData(){ 00979 for(int i=0; i<3; i++){ 00980 Serial0.write(highByte(auxData[i])); // write 16 bit axis data MSB first 00981 Serial0.write(lowByte(auxData[i])); // axisData is array of type short (16bit) 00982 auxData[i] = 0; // reset auxData bytes to 0 00983 } 00984 } 00985 00986 void OpenBCI_32bit_Library::writeTimeCurrent(void) { 00987 uint32_t newTime = millis(); // serialize the number, placing the MSB in lower packets 00988 for (int j = 3; j >= 0; j--) { 00989 Serial0.write(newTime >> (j*8)); 00990 } 00991 } 00992 00993 //SPI communication method 00994 byte OpenBCI_32bit_Library::xfer(byte _data) 00995 { 00996 byte inByte; 00997 inByte = spi.transfer(_data); 00998 return inByte; 00999 } 01000 01001 //SPI chip select method 01002 void OpenBCI_32bit_Library::csLow(int SS) 01003 { // select an SPI slave to talk to 01004 switch(SS){ 01005 case BOARD_ADS: 01006 spi.setMode(DSPI_MODE1); 01007 spi.setSpeed(4000000); 01008 digitalWrite(BOARD_ADS, LOW); 01009 break; 01010 case LIS3DH_SS: 01011 spi.setMode(DSPI_MODE3); 01012 spi.setSpeed(4000000); 01013 digitalWrite(LIS3DH_SS, LOW); 01014 break; 01015 case SD_SS: 01016 spi.setMode(DSPI_MODE0); 01017 spi.setSpeed(20000000); 01018 digitalWrite(SD_SS, LOW); 01019 break; 01020 case DAISY_ADS: 01021 spi.setMode(DSPI_MODE1); 01022 spi.setSpeed(4000000); 01023 digitalWrite(DAISY_ADS, LOW); 01024 break; 01025 case BOTH_ADS: 01026 spi.setMode(DSPI_MODE1); 01027 spi.setSpeed(4000000); 01028 digitalWrite(BOARD_ADS,LOW); 01029 digitalWrite(DAISY_ADS,LOW); 01030 break; 01031 default: 01032 break; 01033 } 01034 } 01035 01036 void OpenBCI_32bit_Library::csHigh(int SS) 01037 { // deselect SPI slave 01038 switch(SS){ 01039 case BOARD_ADS: 01040 digitalWrite(BOARD_ADS, HIGH); 01041 spi.setSpeed(20000000); 01042 break; 01043 case LIS3DH_SS: 01044 digitalWrite(LIS3DH_SS, HIGH); 01045 spi.setSpeed(20000000); 01046 break; 01047 case SD_SS: 01048 digitalWrite(SD_SS, HIGH); 01049 spi.setSpeed(4000000); 01050 break; 01051 case DAISY_ADS: 01052 digitalWrite(DAISY_ADS, HIGH); 01053 spi.setSpeed(20000000); 01054 break; 01055 case BOTH_ADS: 01056 digitalWrite(BOARD_ADS, HIGH); 01057 digitalWrite(DAISY_ADS, HIGH); 01058 spi.setSpeed(20000000); break; 01059 default: 01060 break; 01061 } 01062 spi.setMode(DSPI_MODE0); // DEFAULT TO SD MODE! 01063 } 01064 01065 // <<<<<<<<<<<<<<<<<<<<<<<<< END OF BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 01066 // ************************************************************************************* 01067 // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 01068 01069 01070 void OpenBCI_32bit_Library::initialize_ads(){ 01071 // recommended power up sequence requiers >Tpor (~32mS) 01072 delay(50); 01073 pinMode(ADS_RST,OUTPUT); 01074 digitalWrite(ADS_RST,LOW); // reset pin connected to both ADS ICs 01075 delayMicroseconds(4); // toggle reset pin 01076 digitalWrite(ADS_RST,HIGH); // this will reset the Daisy if it is present 01077 delayMicroseconds(20); // recommended to wait 18 Tclk before using device (~8uS); 01078 // initalize the data ready chip select and reset pins: 01079 pinMode(ADS_DRDY, INPUT); // we get DRDY asertion from the on-board ADS 01080 delay(40); 01081 resetADS(BOARD_ADS); // reset the on-board ADS registers, and stop DataContinuousMode 01082 delay(10); 01083 WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output its clk, set the data rate to 250SPS 01084 delay(40); 01085 resetADS(DAISY_ADS); // software reset daisy module if present 01086 delay(10); 01087 daisyPresent = smellDaisy(); // check to see if daisy module is present 01088 if(!daisyPresent){ 01089 WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present 01090 numChannels = 8; // expect up to 8 ADS channels 01091 }else{ 01092 numChannels = 16; // expect up to 16 ADS channels 01093 } 01094 01095 // DEFAULT CHANNEL SETTINGS FOR ADS 01096 defaultChannelSettings[POWER_DOWN] = NO; // on = NO, off = YES 01097 defaultChannelSettings[GAIN_SET] = ADS_GAIN24; // Gain setting 01098 defaultChannelSettings[INPUT_TYPE_SET] = ADSINPUT_NORMAL;// input muxer setting 01099 defaultChannelSettings[BIAS_SET] = YES; // add this channel to bias generation 01100 defaultChannelSettings[SRB2_SET] = YES; // connect this P side to SRB2 01101 defaultChannelSettings[SRB1_SET] = NO; // don't use SRB1 01102 01103 for(int i=0; i<numChannels; i++){ 01104 for(int j=0; j<6; j++){ 01105 channelSettings[i][j] = defaultChannelSettings[j]; // assign default settings 01106 } 01107 useInBias[i] = true; // keeping track of Bias Generation 01108 useSRB2[i] = true; // keeping track of SRB2 inclusion 01109 } 01110 boardUseSRB1 = daisyUseSRB1 = false; 01111 01112 writeChannelSettings(); // write settings to the on-board and on-daisy ADS if present 01113 01114 WREG(CONFIG3,0b11101100,BOTH_ADS); delay(1); // enable internal reference drive and etc. 01115 for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal 01116 leadOffSettings[i][PCHAN] = OFF; 01117 leadOffSettings[i][NCHAN] = OFF; 01118 } 01119 verbosity = false; // when verbosity is true, there will be Serial feedback 01120 firstDataPacket = true; 01121 01122 streaming = false; 01123 } 01124 01125 ////////////////////////////////////////////// 01126 ///////////// STREAM METHODS ///////////////// 01127 ////////////////////////////////////////////// 01128 01129 /** 01130 * @description Used to activate a channel, if running must stop and start after... 01131 * @param channelNumber int the channel you want to change 01132 * @author AJ Keller (@pushtheworldllc) 01133 */ 01134 void OpenBCI_32bit_Library::streamSafeChannelActivate(byte channelNumber) { 01135 boolean wasStreaming = streaming; 01136 01137 // Stop streaming if you are currently streaming 01138 if (streaming) { 01139 streamStop(); 01140 } 01141 01142 // Activate the channel 01143 activateChannel(channelNumber); 01144 01145 // Restart stream if need be 01146 if (wasStreaming) { 01147 streamStart(); 01148 } 01149 } 01150 01151 /** 01152 * @description Used to deactivate a channel, if running must stop and start after... 01153 * @param channelNumber int the channel you want to change 01154 * @author AJ Keller (@pushtheworldllc) 01155 */ 01156 void OpenBCI_32bit_Library::streamSafeChannelDeactivate(byte channelNumber){ 01157 boolean wasStreaming = streaming; 01158 01159 // Stop streaming if you are currently streaming 01160 if (streaming) { 01161 streamStop(); 01162 } 01163 01164 // deactivate the channel 01165 deactivateChannel(channelNumber); 01166 01167 // Restart stream if need be 01168 if (wasStreaming) { 01169 streamStart(); 01170 } 01171 } 01172 01173 /** 01174 * @description Used to set lead off for a channel, if running must stop and start after... 01175 * @param `channelNumber` - [byte] - The channel you want to change 01176 * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0) 01177 * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0) 01178 * @author AJ Keller (@pushtheworldllc) 01179 */ 01180 void OpenBCI_32bit_Library::streamSafeLeadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) { 01181 boolean wasStreaming = streaming; 01182 01183 // Stop streaming if you are currently streaming 01184 if (streaming) { 01185 streamStop(); 01186 } 01187 01188 changeChannelLeadOffDetect(channelNumber); 01189 01190 // leadOffSetForChannel(channelNumber, pInput, nInput); 01191 01192 // Restart stream if need be 01193 if (wasStreaming) { 01194 streamStart(); 01195 } 01196 } 01197 01198 /** 01199 * @description Used to set lead off for a channel, if running must stop and start after... 01200 * @param see `.channelSettingsSetForChannel()` for parameters 01201 * @author AJ Keller (@pushtheworldllc) 01202 */ 01203 void OpenBCI_32bit_Library::streamSafeChannelSettingsForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) { 01204 boolean wasStreaming = streaming; 01205 01206 // Stop streaming if you are currently streaming 01207 if (streaming) { 01208 streamStop(); 01209 } 01210 01211 writeChannelSettings(channelNumber); 01212 01213 // channelSettingsSetForChannel(channelNumber, powerDown, gain, inputType, bias, srb2, srb1); 01214 01215 // Restart stream if need be 01216 if (wasStreaming) { 01217 streamStart(); 01218 } 01219 } 01220 01221 /** 01222 * @description Used to report (Serial0.print) the default channel settings 01223 * if running must stop and start after... 01224 * @author AJ Keller (@pushtheworldllc) 01225 */ 01226 void OpenBCI_32bit_Library::streamSafeReportAllChannelDefaults(void) { 01227 boolean wasStreaming = streaming; 01228 01229 // Stop streaming if you are currently streaming 01230 if (streaming) { 01231 streamStop(); 01232 } 01233 01234 reportDefaultChannelSettings(); 01235 01236 // Restart stream if need be 01237 if (wasStreaming) { 01238 streamStart(); 01239 } 01240 } 01241 01242 /** 01243 * @description Used to set all channels on Board (and Daisy) to the default 01244 * channel settings if running must stop and start after... 01245 * @author AJ Keller (@pushtheworldllc) 01246 */ 01247 void OpenBCI_32bit_Library::streamSafeSetAllChannelsToDefault(void) { 01248 boolean wasStreaming = streaming; 01249 01250 // Stop streaming if you are currently streaming 01251 if (streaming) { 01252 streamStop(); 01253 } 01254 01255 setChannelsToDefault(); 01256 01257 // Restart stream if need be 01258 if (wasStreaming) { 01259 streamStart(); 01260 } 01261 } 01262 01263 /** 01264 * @description Call this to start the streaming data from the ADS1299 01265 * @returns boolean if able to start streaming 01266 */ 01267 void OpenBCI_32bit_Library::streamStart(){ // needs daisy functionality 01268 streaming = true; 01269 startADS(); 01270 if (sniffMode && Serial1) { 01271 Serial1.println("ADS Started"); 01272 } 01273 } 01274 01275 /** 01276 * @description Call this to stop streaming from the ADS1299 01277 * @returns boolean if able to stop streaming 01278 */ 01279 void OpenBCI_32bit_Library::streamStop(){ 01280 streaming = false; 01281 stopADS(); 01282 if (sniffMode && Serial1) { 01283 Serial1.println("ADS Stopped"); 01284 } 01285 01286 } 01287 01288 ////////////////////////////////////////////// 01289 ////////////// DAISY METHODS ///////////////// 01290 ////////////////////////////////////////////// 01291 boolean OpenBCI_32bit_Library::smellDaisy(void){ // check if daisy present 01292 boolean isDaisy = false; 01293 byte setting = RREG(ID_REG,DAISY_ADS); // try to read the daisy product ID 01294 if(verbosity){Serial0.print("Daisy ID 0x"); Serial0.println(setting,HEX); sendEOT();} 01295 if(setting == ADS_ID) {isDaisy = true;} // should read as 0x3E 01296 return isDaisy; 01297 } 01298 01299 void OpenBCI_32bit_Library::removeDaisy(void){ 01300 if(daisyPresent){ 01301 // Daisy removed 01302 SDATAC(DAISY_ADS); 01303 RESET(DAISY_ADS); 01304 STANDBY(DAISY_ADS); 01305 daisyPresent = false; 01306 if(!isRunning) { 01307 Serial0.println("daisy removed"); 01308 sendEOT(); 01309 } 01310 }else{ 01311 if(!isRunning) { 01312 Serial0.println("no daisy to remove!"); 01313 sendEOT(); 01314 } 01315 } 01316 } 01317 01318 void OpenBCI_32bit_Library::attachDaisy(void){ 01319 WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output the clk, set the data rate to 250SPS 01320 delay(40); 01321 resetADS(DAISY_ADS); // software reset daisy module if present 01322 delay(10); 01323 daisyPresent = smellDaisy(); 01324 if(!daisyPresent){ 01325 WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present 01326 numChannels = 8; // expect up to 8 ADS channels 01327 if(!isRunning) Serial0.println("no daisy to attach!"); 01328 }else{ 01329 numChannels = 16; // expect up to 16 ADS channels 01330 if(!isRunning) Serial0.println("daisy attached"); 01331 } 01332 } 01333 01334 //reset all the ADS1299's settings. Stops all data acquisition 01335 void OpenBCI_32bit_Library::resetADS(int targetSS) 01336 { 01337 int startChan, stopChan; 01338 if(targetSS == BOARD_ADS) {startChan = 1; stopChan = 8;} 01339 if(targetSS == DAISY_ADS) {startChan = 9; stopChan = 16;} 01340 RESET(targetSS); // send RESET command to default all registers 01341 SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS 01342 delay(100); 01343 // turn off all channels 01344 for (int chan=startChan; chan <= stopChan; chan++) { 01345 deactivateChannel(chan); 01346 } 01347 } 01348 01349 void OpenBCI_32bit_Library::setChannelsToDefault(void){ 01350 for(int i=0; i<numChannels; i++){ 01351 for(int j=0; j<6; j++){ 01352 channelSettings[i][j] = defaultChannelSettings[j]; 01353 } 01354 useInBias[i] = true; // keeping track of Bias Generation 01355 useSRB2[i] = true; // keeping track of SRB2 inclusion 01356 } 01357 boardUseSRB1 = daisyUseSRB1 = false; 01358 01359 writeChannelSettings(); // write settings to on-board ADS 01360 01361 for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal 01362 leadOffSettings[i][PCHAN] = OFF; 01363 leadOffSettings[i][NCHAN] = OFF; 01364 } 01365 changeChannelLeadOffDetect(); // write settings to all ADS 01366 01367 01368 WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board 01369 if(daisyPresent){ WREG(MISC1,0x00,DAISY_ADS); } // open SRB1 switch on-daisy 01370 } 01371 01372 // void OpenBCI_32bit_Library::setChannelsToDefault(void){ 01373 01374 // // Reset the global channel settings array to default 01375 // resetChannelSettingsArrayToDefault(channelSettings); 01376 // // Write channel settings to board (and daisy) ADS 01377 // channelSettingsArraySetForAll(); 01378 01379 // // Reset the global lead off settings array to default 01380 // resetLeadOffArrayToDefault(leadOffSettings); 01381 // // Write lead off settings to board (and daisy) ADS 01382 // leadOffSetForAllChannels(); 01383 01384 // WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board 01385 // if(daisyPresent){ // open SRB1 switch on-daisy 01386 // WREG(MISC1,0x00,DAISY_ADS); 01387 // } 01388 // } 01389 01390 /** 01391 * @description Writes the default channel settings over the serial port 01392 */ 01393 void OpenBCI_32bit_Library::reportDefaultChannelSettings(void){ 01394 Serial0.write(getDefaultChannelSettingForSettingAscii(POWER_DOWN)); // on = NO, off = YES 01395 Serial0.write(getDefaultChannelSettingForSettingAscii(GAIN_SET)); // Gain setting 01396 Serial0.write(getDefaultChannelSettingForSettingAscii(INPUT_TYPE_SET)); // input muxer setting 01397 Serial0.write(getDefaultChannelSettingForSettingAscii(BIAS_SET)); // add this channel to bias generation 01398 Serial0.write(getDefaultChannelSettingForSettingAscii(SRB2_SET)); // connect this P side to SRB2 01399 Serial0.write(getDefaultChannelSettingForSettingAscii(SRB1_SET)); // don't use SRB1 01400 sendEOT(); 01401 } 01402 01403 /** 01404 * @description Set all channels using global channelSettings array 01405 * @author AJ Keller (@pushtheworldllc) 01406 */ 01407 // void OpenBCI_32bit_Library::channelSettingsArraySetForAll(void) { 01408 // byte channelNumberUpperLimit; 01409 01410 // // The upper limit of the channels, either 8 or 16 01411 // channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; 01412 01413 // // Loop through all channels 01414 // for (byte i = 1; i <= channelNumberUpperLimit; i++) { 01415 // // Set for this channel 01416 // channelSettingsSetForChannel(i, channelSettings[i][POWER_DOWN], channelSettings[i][GAIN_SET], channelSettings[i][INPUT_TYPE_SET], channelSettings[i][BIAS_SET], channelSettings[i][SRB2_SET], channelSettings[i][SRB1_SET]); 01417 // } 01418 // } 01419 01420 /** 01421 * @description Set channel using global channelSettings array for channelNumber 01422 * @param `channelNumber` - [byte] - 1-16 channel number 01423 * @author AJ Keller (@pushtheworldllc) 01424 */ 01425 // void OpenBCI_32bit_Library::channelSettingsArraySetForChannel(byte channelNumber) { 01426 // // contstrain the channel number to 0-15 01427 // char index = getConstrainedChannelNumber(channelNumber); 01428 01429 // // Set for this channel 01430 // channelSettingsSetForChannel(channelNumber, channelSettings[index][POWER_DOWN], channelSettings[index][GAIN_SET], channelSettings[index][INPUT_TYPE_SET], channelSettings[index][BIAS_SET], channelSettings[index][SRB2_SET], channelSettings[index][SRB1_SET]); 01431 // } 01432 01433 /** 01434 * @description To add a usability abstraction layer above channel setting commands. Due to the 01435 * extensive and highly specific nature of the channel setting command chain. 01436 * @param `channelNumber` - [byte] (1-16) for index, so convert channel to array prior 01437 * @param `powerDown` - [byte] - YES (1) or NO (0) 01438 * Powers channel down 01439 * @param `gain` - [byte] - Sets the gain for the channel 01440 * ADS_GAIN01 (0b00000000) // 0x00 01441 * ADS_GAIN02 (0b00010000) // 0x10 01442 * ADS_GAIN04 (0b00100000) // 0x20 01443 * ADS_GAIN06 (0b00110000) // 0x30 01444 * ADS_GAIN08 (0b01000000) // 0x40 01445 * ADS_GAIN12 (0b01010000) // 0x50 01446 * ADS_GAIN24 (0b01100000) // 0x60 01447 * @param `inputType` - [byte] - Selects the ADC channel input source, either: 01448 * ADSINPUT_NORMAL (0b00000000) 01449 * ADSINPUT_SHORTED (0b00000001) 01450 * ADSINPUT_BIAS_MEAS (0b00000010) 01451 * ADSINPUT_MVDD (0b00000011) 01452 * ADSINPUT_TEMP (0b00000100) 01453 * ADSINPUT_TESTSIG (0b00000101) 01454 * ADSINPUT_BIAS_DRP (0b00000110) 01455 * ADSINPUT_BIAL_DRN (0b00000111) 01456 * @param `bias` - [byte] (YES (1) -> Include in bias (default), NO (0) -> remove from bias) 01457 * selects to include the channel input in bias generation 01458 * @param `srb2` - [byte] (YES (1) -> Connect this input to SRB2 (default), 01459 * NO (0) -> Disconnect this input from SRB2) 01460 * Select to connect (YES) this channel's P input to the SRB2 pin. This closes 01461 * a switch between P input and SRB2 for the given channel, and allows the 01462 * P input to also remain connected to the ADC. 01463 * @param `srb1` - [byte] (YES (1) -> connect all N inputs to SRB1, 01464 * NO (0) -> Disconnect all N inputs from SRB1 (default)) 01465 * Select to connect (YES) all channels' N inputs to SRB1. This effects all pins, 01466 * and disconnects all N inputs from the ADC. 01467 * @author AJ Keller (@pushtheworldllc) 01468 */ 01469 // void OpenBCI_32bit_Library::channelSettingsSetForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) { 01470 // byte setting, targetSS; 01471 01472 // // contstrain the channel number to 0-15 01473 // char index = getConstrainedChannelNumber(channelNumber); 01474 01475 // // Get the slave select pin for this channel 01476 // targetSS = getTargetSSForConstrainedChannelNumber(index); 01477 01478 // if (sniffMode && Serial1) { 01479 // if (targetSS == BOARD_ADS) { 01480 // Serial1.print("Set channel "); Serial1.print(channelNumber); Serial1.println(" settings"); 01481 // } 01482 // } 01483 01484 // // first, disable any data collection 01485 // SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01486 01487 // setting = 0x00; 01488 01489 // // Set the power down bit 01490 // if(powerDown == YES) { 01491 // setting |= 0x80; 01492 // } 01493 01494 // // Set the gain bits 01495 // setting |= gain; 01496 01497 // // Set input type bits 01498 // setting |= inputType; 01499 01500 // if(srb2 == YES){ 01501 // setting |= 0x08; // close this SRB2 switch 01502 // useSRB2[index] = true; // keep track of SRB2 usage 01503 // }else{ 01504 // useSRB2[index] = false; 01505 // } 01506 01507 // byte channelNumberRegister = 0x00; 01508 01509 // // Since we are addressing 8 bit registers, we need to subtract 8 from the 01510 // // channelNumber if we are addressing the Daisy ADS 01511 // if (targetSS == DAISY_ADS) { 01512 // channelNumberRegister = index - OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; 01513 // } else { 01514 // channelNumberRegister = index; 01515 // } 01516 // WREG(CH1SET+channelNumberRegister, setting, targetSS); // write this channel's register settings 01517 01518 // // add or remove from inclusion in BIAS generation 01519 // setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings 01520 // if(bias == YES){ 01521 // useInBias[index] = true; 01522 // bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation 01523 // }else{ 01524 // useInBias[index] = false; 01525 // bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation 01526 // } 01527 // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01528 01529 // setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings 01530 // if(bias == YES){ 01531 // bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation 01532 // }else{ 01533 // bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation 01534 // } 01535 // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01536 01537 // byte startChan = targetSS == BOARD_ADS ? 0 : OPENBCI_CHANNEL_MAX_NUMBER_8 - 1; 01538 // byte endChan = targetSS == BOARD_ADS ? OPENBCI_CHANNEL_MAX_NUMBER_8 : OPENBCI_CHANNEL_MAX_NUMBER_16 - 1; 01539 // // if SRB1 is closed or open for one channel, it will be the same for all channels 01540 // if(srb1 == YES){ 01541 // for(int i=startChan; i<endChan; i++){ 01542 // channelSettings[i][SRB1_SET] = YES; 01543 // } 01544 // if(targetSS == BOARD_ADS) boardUseSRB1 = true; 01545 // if(targetSS == DAISY_ADS) daisyUseSRB1 = true; 01546 // setting = 0x20; // close SRB1 swtich 01547 // } 01548 // if(srb1 == NO){ 01549 // for(int i=startChan; i<endChan; i++){ 01550 // channelSettings[i][SRB1_SET] = NO; 01551 // } 01552 // if(targetSS == BOARD_ADS) boardUseSRB1 = false; 01553 // if(targetSS == DAISY_ADS) daisyUseSRB1 = false; 01554 // setting = 0x00; // open SRB1 switch 01555 // } 01556 // WREG(MISC1,setting,targetSS); 01557 // } 01558 01559 // write settings for ALL 8 channels for a given ADS board 01560 // channel settings: powerDown, gain, inputType, SRB2, SRB1 01561 void OpenBCI_32bit_Library::writeChannelSettings(){ 01562 boolean use_SRB1 = false; 01563 byte setting, startChan, endChan, targetSS; 01564 01565 for(int b=0; b<2; b++){ 01566 if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; } 01567 if(b == 1){ 01568 if(!daisyPresent){ return; } 01569 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01570 } 01571 01572 SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01573 01574 for(byte i=startChan; i<endChan; i++){ // write 8 channel settings 01575 setting = 0x00; 01576 if(channelSettings[i][POWER_DOWN] == YES){setting |= 0x80;} 01577 setting |= channelSettings[i][GAIN_SET]; // gain 01578 setting |= channelSettings[i][INPUT_TYPE_SET]; // input code 01579 if(channelSettings[i][SRB2_SET] == YES){ 01580 setting |= 0x08; // close this SRB2 switch 01581 useSRB2[i] = true; // remember SRB2 state for this channel 01582 }else{ 01583 useSRB2[i] = false; // rememver SRB2 state for this channel 01584 } 01585 WREG(CH1SET+(i-startChan),setting,targetSS); // write this channel's register settings 01586 01587 // add or remove this channel from inclusion in BIAS generation 01588 setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings 01589 if(channelSettings[i][BIAS_SET] == YES){ 01590 bitSet(setting,i-startChan); useInBias[i] = true; //add this channel to the bias generation 01591 }else{ 01592 bitClear(setting,i-startChan); useInBias[i] = false; //remove this channel from bias generation 01593 } 01594 WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01595 01596 setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings 01597 if(channelSettings[i][BIAS_SET] == YES){ 01598 bitSet(setting,i-startChan); //set this channel's bit to add it to the bias generation 01599 }else{ 01600 bitClear(setting,i-startChan); // clear this channel's bit to remove from bias generation 01601 } 01602 WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01603 01604 if(channelSettings[i][SRB1_SET] == YES){ 01605 use_SRB1 = true; // if any of the channel setting closes SRB1, it is closed for all 01606 } 01607 } // end of CHnSET and BIAS settings 01608 } // end of board select loop 01609 if(use_SRB1){ 01610 for(int i=startChan; i<endChan; i++){ 01611 channelSettings[i][SRB1_SET] = YES; 01612 } 01613 WREG(MISC1,0x20,targetSS); // close SRB1 swtich 01614 if(targetSS == BOARD_ADS){ boardUseSRB1 = true; } 01615 if(targetSS == DAISY_ADS){ daisyUseSRB1 = true; } 01616 }else{ 01617 for(int i=startChan; i<endChan; i++){ 01618 channelSettings[i][SRB1_SET] = NO; 01619 } 01620 WREG(MISC1,0x00,targetSS); // open SRB1 switch 01621 if(targetSS == BOARD_ADS){ boardUseSRB1 = false; } 01622 if(targetSS == DAISY_ADS){ daisyUseSRB1 = false; } 01623 } 01624 } 01625 01626 // write settings for a SPECIFIC channel on a given ADS board 01627 void OpenBCI_32bit_Library::writeChannelSettings(byte N){ 01628 01629 byte setting, startChan, endChan, targetSS; 01630 if(N < 9){ // channels 1-8 on board 01631 targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01632 }else{ // channels 9-16 on daisy module 01633 if(!daisyPresent) { return; } 01634 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01635 } 01636 // function accepts channel 1-16, must be 0 indexed to work with array 01637 N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 01638 // first, disable any data collection 01639 SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01640 01641 setting = 0x00; 01642 if(channelSettings[N][POWER_DOWN] == YES) setting |= 0x80; 01643 setting |= channelSettings[N][GAIN_SET]; // gain 01644 setting |= channelSettings[N][INPUT_TYPE_SET]; // input code 01645 if(channelSettings[N][SRB2_SET] == YES){ 01646 setting |= 0x08; // close this SRB2 switch 01647 useSRB2[N] = true; // keep track of SRB2 usage 01648 }else{ 01649 useSRB2[N] = false; 01650 } 01651 WREG(CH1SET+(N-startChan), setting, targetSS); // write this channel's register settings 01652 01653 // add or remove from inclusion in BIAS generation 01654 setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings 01655 if(channelSettings[N][BIAS_SET] == YES){ 01656 useInBias[N] = true; 01657 bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01658 }else{ 01659 useInBias[N] = false; 01660 bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01661 } 01662 WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01663 setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings 01664 if(channelSettings[N][BIAS_SET] == YES){ 01665 bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01666 }else{ 01667 bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01668 } 01669 WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01670 01671 // if SRB1 is closed or open for one channel, it will be the same for all channels 01672 if(channelSettings[N][SRB1_SET] == YES){ 01673 for(int i=startChan; i<endChan; i++){ 01674 channelSettings[i][SRB1_SET] = YES; 01675 } 01676 if(targetSS == BOARD_ADS) boardUseSRB1 = true; 01677 if(targetSS == DAISY_ADS) daisyUseSRB1 = true; 01678 setting = 0x20; // close SRB1 swtich 01679 } 01680 if(channelSettings[N][SRB1_SET] == NO){ 01681 for(int i=startChan; i<endChan; i++){ 01682 channelSettings[i][SRB1_SET] = NO; 01683 } 01684 if(targetSS == BOARD_ADS) boardUseSRB1 = false; 01685 if(targetSS == DAISY_ADS) daisyUseSRB1 = false; 01686 setting = 0x00; // open SRB1 switch 01687 } 01688 WREG(MISC1,setting,targetSS); 01689 } 01690 01691 // deactivate the given channel. 01692 void OpenBCI_32bit_Library::deactivateChannel(byte N) 01693 { 01694 byte setting, startChan, endChan, targetSS; 01695 if(N < 9){ 01696 targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01697 }else{ 01698 if(!daisyPresent) { return; } 01699 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01700 } 01701 SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01702 N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 01703 01704 setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings 01705 bitSet(setting,7); // set bit7 to shut down channel 01706 bitClear(setting,3); // clear bit3 to disclude from SRB2 if used 01707 WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel 01708 01709 //remove the channel from the bias generation... 01710 setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings 01711 bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation 01712 WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01713 01714 setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings 01715 bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation 01716 WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01717 01718 leadOffSettings[N][0] = leadOffSettings[N][1] = NO; 01719 changeChannelLeadOffDetect(N+1); 01720 } 01721 01722 void OpenBCI_32bit_Library::activateChannel(byte N) 01723 { 01724 byte setting, startChan, endChan, targetSS; 01725 if(N < 9){ 01726 targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01727 }else{ 01728 if(!daisyPresent) { return; } 01729 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01730 } 01731 01732 N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15 01733 01734 SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS 01735 setting = 0x00; 01736 // channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE? 01737 setting |= channelSettings[N][GAIN_SET]; // gain 01738 setting |= channelSettings[N][INPUT_TYPE_SET]; // input code 01739 if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;} 01740 if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch 01741 WREG(CH1SET+(N-startChan),setting,targetSS); 01742 // add or remove from inclusion in BIAS generation 01743 if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;} 01744 setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings 01745 if(channelSettings[N][BIAS_SET] == YES){ 01746 bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01747 useInBias[N] = true; 01748 }else{ 01749 bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01750 useInBias[N] = false; 01751 } 01752 WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01753 setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings 01754 if(channelSettings[N][BIAS_SET] == YES){ 01755 bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01756 }else{ 01757 bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01758 } 01759 WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01760 01761 setting = 0x00; 01762 if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20; 01763 if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20; 01764 WREG(MISC1,setting,targetSS); // close all SRB1 swtiches 01765 } 01766 01767 // change the lead off detect settings for all channels 01768 void OpenBCI_32bit_Library::changeChannelLeadOffDetect() 01769 { 01770 byte setting, startChan, endChan, targetSS; 01771 01772 for(int b=0; b<2; b++){ 01773 if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; } 01774 if(b == 1){ 01775 if(!daisyPresent){ return; } 01776 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01777 } 01778 01779 SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01780 byte P_setting = RREG(LOFF_SENSP,targetSS); 01781 byte N_setting = RREG(LOFF_SENSN,targetSS); 01782 01783 for(int i=startChan; i<endChan; i++){ 01784 if(leadOffSettings[i][PCHAN] == ON){ 01785 bitSet(P_setting,i-startChan); 01786 }else{ 01787 bitClear(P_setting,i-startChan); 01788 } 01789 if(leadOffSettings[i][NCHAN] == ON){ 01790 bitSet(N_setting,i-startChan); 01791 }else{ 01792 bitClear(N_setting,i-startChan); 01793 } 01794 WREG(LOFF_SENSP,P_setting,targetSS); 01795 WREG(LOFF_SENSN,N_setting,targetSS); 01796 } 01797 } 01798 } 01799 01800 // change the lead off detect settings for specified channel 01801 void OpenBCI_32bit_Library::changeChannelLeadOffDetect(byte N) 01802 { 01803 byte setting, targetSS, startChan, endChan; 01804 01805 if(N < 9){ 01806 targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01807 }else{ 01808 if(!daisyPresent) { return; } 01809 targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01810 } 01811 01812 N = constrain(N-1,startChan,endChan-1); 01813 SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01814 byte P_setting = RREG(LOFF_SENSP,targetSS); 01815 byte N_setting = RREG(LOFF_SENSN,targetSS); 01816 01817 if(leadOffSettings[N][PCHAN] == ON){ 01818 bitSet(P_setting,N-startChan); 01819 }else{ 01820 bitClear(P_setting,N-startChan); 01821 } 01822 if(leadOffSettings[N][NCHAN] == ON){ 01823 bitSet(N_setting,N-startChan); 01824 }else{ 01825 bitClear(N_setting,N-startChan); 01826 } 01827 WREG(LOFF_SENSP,P_setting,targetSS); 01828 WREG(LOFF_SENSN,N_setting,targetSS); 01829 } 01830 01831 void OpenBCI_32bit_Library::configureLeadOffDetection(byte amplitudeCode, byte freqCode) 01832 { 01833 amplitudeCode &= 0b00001100; //only these two bits should be used 01834 freqCode &= 0b00000011; //only these two bits should be used 01835 01836 byte setting, targetSS; 01837 for(int i=0; i<2; i++){ 01838 if(i == 0){ targetSS = BOARD_ADS; } 01839 if(i == 1){ 01840 if(!daisyPresent){ return; } 01841 targetSS = DAISY_ADS; 01842 } 01843 setting = RREG(LOFF,targetSS); //get the current bias settings 01844 //reconfigure the byte to get what we want 01845 setting &= 0b11110000; //clear out the last four bits 01846 setting |= amplitudeCode; //set the amplitude 01847 setting |= freqCode; //set the frequency 01848 //send the config byte back to the hardware 01849 WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS 01850 } 01851 } 01852 01853 // // deactivate the given channel. 01854 // void OpenBCI_32bit_Library::deactivateChannel(byte N) 01855 // { 01856 // byte setting, startChan, endChan, targetSS; 01857 // if(N < 9){ 01858 // targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01859 // }else{ 01860 // if(!daisyPresent) { return; } 01861 // targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01862 // } 01863 // SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS 01864 // N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 01865 01866 // setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings 01867 // bitSet(setting,7); // set bit7 to shut down channel 01868 // bitClear(setting,3); // clear bit3 to disclude from SRB2 if used 01869 // WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel 01870 01871 // //remove the channel from the bias generation... 01872 // setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings 01873 // bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation 01874 // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01875 01876 // setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings 01877 // bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation 01878 // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01879 01880 // leadOffSettings[N][PCHAN] = leadOffSettings[N][NCHAN] = NO; 01881 // leadOffSetForChannel(N+1, NO, NO); 01882 // } 01883 01884 // void OpenBCI_32bit_Library::activateChannel(byte N) 01885 // { 01886 // byte setting, startChan, endChan, targetSS; 01887 // if(N < 9){ 01888 // targetSS = BOARD_ADS; startChan = 0; endChan = 8; 01889 // }else{ 01890 // if(!daisyPresent) { return; } 01891 // targetSS = DAISY_ADS; startChan = 8; endChan = 16; 01892 // } 01893 01894 // N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15 01895 01896 // SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS 01897 // setting = 0x00; 01898 // // channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE? 01899 // setting |= channelSettings[N][GAIN_SET]; // gain 01900 // setting |= channelSettings[N][INPUT_TYPE_SET]; // input code 01901 // if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;} 01902 // if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch 01903 // WREG(CH1SET+(N-startChan),setting,targetSS); 01904 // // add or remove from inclusion in BIAS generation 01905 // if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;} 01906 // setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings 01907 // if(channelSettings[N][BIAS_SET] == YES){ 01908 // bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01909 // useInBias[N] = true; 01910 // }else{ 01911 // bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01912 // useInBias[N] = false; 01913 // } 01914 // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS 01915 // setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings 01916 // if(channelSettings[N][BIAS_SET] == YES){ 01917 // bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation 01918 // }else{ 01919 // bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation 01920 // } 01921 // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS 01922 01923 // setting = 0x00; 01924 // if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20; 01925 // if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20; 01926 // WREG(MISC1,setting,targetSS); // close all SRB1 swtiches 01927 // } 01928 01929 ////////////////////////////////////////////// 01930 ///////////// LEAD OFF METHODS /////////////// 01931 ////////////////////////////////////////////// 01932 01933 /** 01934 * @description Runs through the `leadOffSettings` global array to set/change 01935 * the lead off signals for all inputs of all channels. 01936 * @author AJ Keller (@pushtheworldllc) 01937 */ 01938 // void OpenBCI_32bit_Library::leadOffSetForAllChannels(void) { 01939 // byte channelNumberUpperLimit; 01940 01941 // // The upper limit of the channels, either 8 or 16 01942 // channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; 01943 01944 // // Loop through all channels 01945 // for (int i = 1; i <= channelNumberUpperLimit; i++) { 01946 // leadOffSetForChannel((byte)i,leadOffSettings[i-1][PCHAN],leadOffSettings[i-1][NCHAN]); 01947 // } 01948 // } 01949 01950 /** 01951 * @description Used to set lead off for a channel 01952 * @param `channelNumber` - [byte] - The channel you want to change 01953 * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0) 01954 * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0) 01955 * @author AJ Keller (@pushtheworldllc) 01956 */ 01957 // void OpenBCI_32bit_Library::leadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) { 01958 01959 // // contstrain the channel number to 0-15 01960 // channelNumber = getConstrainedChannelNumber(channelNumber); 01961 01962 // // Get the slave select pin for this channel 01963 // byte targetSS = getTargetSSForConstrainedChannelNumber(channelNumber); 01964 01965 // // exit Read Data Continuous mode to communicate with ADS 01966 // SDATAC(targetSS); 01967 // delay(1); 01968 01969 // // Read P register 01970 // byte P_setting = RREG(LOFF_SENSP,targetSS); 01971 01972 // // Read N register 01973 // byte N_setting = RREG(LOFF_SENSN,targetSS); 01974 01975 // // Since we are addressing 8 bit registers, we need to subtract 8 from the 01976 // // channelNumber if we are addressing the Daisy ADS 01977 // if (targetSS == DAISY_ADS) { 01978 // channelNumber -= OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; 01979 // } 01980 01981 // // If pInput is ON then we want to set, otherwise we want to clear 01982 // if (pInput == ON) { 01983 // bitSet(P_setting, channelNumber); 01984 // } else { 01985 // bitClear(P_setting, channelNumber); 01986 // } 01987 // // Write to the P register 01988 // WREG(LOFF_SENSP,P_setting,targetSS); 01989 01990 // // If nInput is ON then we want to set, otherwise we want to clear 01991 // if (nInput == ON) { 01992 // bitSet(N_setting, channelNumber); 01993 // } else { 01994 // bitClear(N_setting, channelNumber); 01995 // } 01996 // // Write to the N register 01997 // WREG(LOFF_SENSN,N_setting,targetSS); 01998 // } 01999 02000 /** 02001 * @description This sets the LOFF register on the Board ADS and the Daisy ADS 02002 * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal. 02003 * See `.setleadOffForSS()` for complete description 02004 * @param `freqCode` - [byte] - The frequency of the impedance signal can be either. 02005 * See `.setleadOffForSS()` for complete description 02006 * @author AJ Keller (@pushtheworldllc) 02007 */ 02008 // void OpenBCI_32bit_Library::leadOffConfigureSignalForAll(byte amplitudeCode, byte freqCode) 02009 // { 02010 // // Set the lead off detection for the on board ADS 02011 // leadOffConfigureSignalForTargetSS(BOARD_ADS, amplitudeCode, freqCode); 02012 02013 // // if the daisy board is present, set that register as well 02014 // if (daisyPresent) { 02015 // leadOffConfigureSignalForTargetSS(DAISY_ADS, amplitudeCode, freqCode); 02016 // } 02017 // } 02018 02019 /** 02020 * @description This sets the LOFF (lead off) register for the given ADS with slave 02021 * select 02022 * @param `targetSS` - [byte] - The Slave Select pin. 02023 * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal. 02024 * LOFF_MAG_6NA (0b00000000) 02025 * LOFF_MAG_24NA (0b00000100) 02026 * LOFF_MAG_6UA (0b00001000) 02027 * LOFF_MAG_24UA (0b00001100) 02028 * @param `freqCode` - [byte] - The frequency of the impedance signal can be either. 02029 * LOFF_FREQ_DC (0b00000000) 02030 * LOFF_FREQ_7p8HZ (0b00000001) 02031 * LOFF_FREQ_31p2HZ (0b00000010) 02032 * LOFF_FREQ_FS_4 (0b00000011) 02033 * @author Joel/Leif/Conor (@OpenBCI) Summer 2014 02034 */ 02035 // void OpenBCI_32bit_Library::leadOffConfigureSignalForTargetSS(byte targetSS, byte amplitudeCode, byte freqCode) { 02036 // byte setting; 02037 02038 // amplitudeCode &= 0b00001100; //only these two bits should be used 02039 // freqCode &= 0b00000011; //only these two bits should be used 02040 02041 // setting = RREG(LOFF,targetSS); //get the current bias settings 02042 // //reconfigure the byte to get what we want 02043 // setting &= 0b11110000; //clear out the last four bits 02044 // setting |= amplitudeCode; //set the amplitude 02045 // setting |= freqCode; //set the frequency 02046 // //send the config byte back to the hardware 02047 // WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS 02048 // } 02049 02050 //Configure the test signals that can be inernally generated by the ADS1299 02051 void OpenBCI_32bit_Library::configureInternalTestSignal(byte amplitudeCode, byte freqCode) 02052 { 02053 byte setting, targetSS; 02054 for(int i=0; i<2; i++){ 02055 if(i == 0){ targetSS = BOARD_ADS;} 02056 if(i == 1){ 02057 if(daisyPresent == false){ return; } 02058 targetSS = DAISY_ADS; 02059 } 02060 if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (RREG(CONFIG2,targetSS) & (0b00000100)); 02061 if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (RREG(CONFIG2,targetSS) & (0b00000011)); 02062 freqCode &= 0b00000011; //only the last two bits are used 02063 amplitudeCode &= 0b00000100; //only this bit is used 02064 byte setting = 0b11010000 | freqCode | amplitudeCode; //compose the code 02065 WREG(CONFIG2,setting,targetSS); delay(1); 02066 if (sniffMode && Serial1) { 02067 Serial1.print("Wrote to CONFIG2: "); 02068 Serial1.print(setting,BIN); 02069 } 02070 } 02071 } 02072 02073 void OpenBCI_32bit_Library::changeInputType(byte inputCode){ 02074 02075 for(int i=0; i<numChannels; i++){ 02076 channelSettings[i][INPUT_TYPE_SET] = inputCode; 02077 } 02078 02079 // OLD CODE REVERT 02080 //channelSettingsArraySetForAll(); 02081 02082 writeChannelSettings(); 02083 } 02084 02085 // Start continuous data acquisition 02086 void OpenBCI_32bit_Library::startADS(void) // NEEDS ADS ADDRESS, OR BOTH? 02087 { 02088 sampleCounter = 0; 02089 firstDataPacket = true; 02090 RDATAC(BOTH_ADS); // enter Read Data Continuous mode 02091 delay(1); 02092 START(BOTH_ADS); // start the data acquisition 02093 delay(1); 02094 isRunning = true; 02095 } 02096 02097 /** 02098 * @description Check status register to see if data is available from the ADS1299. 02099 * @returns {boolean} - `true` if data is available 02100 */ 02101 boolean OpenBCI_32bit_Library::waitForNewChannelData(void) { 02102 return !isADSDataAvailable(); 02103 } 02104 02105 /** 02106 * @description Check status register to see if data is available from the ADS1299. 02107 * @returns {boolean} - `true` if data is available 02108 */ 02109 boolean OpenBCI_32bit_Library::isADSDataAvailable(void) { 02110 return (!(digitalRead(ADS_DRDY))); 02111 } 02112 02113 // CALLED WHEN DRDY PIN IS ASSERTED. NEW ADS DATA AVAILABLE! 02114 void OpenBCI_32bit_Library::updateChannelData(){ 02115 // this needs to be reset, or else it will constantly flag us 02116 channelDataAvailable = false; 02117 updateBoardData(); 02118 if(daisyPresent) {updateDaisyData();} 02119 } 02120 02121 void OpenBCI_32bit_Library::updateBoardData(){ 02122 byte inByte; 02123 int byteCounter = 0; 02124 02125 if(daisyPresent && !firstDataPacket){ 02126 for(int i=0; i < 8; i++){ // shift and average the byte arrays 02127 lastBoardChannelDataInt[i] = boardChannelDataInt[i]; // remember the last samples 02128 } 02129 } 02130 02131 csLow(BOARD_ADS); // open SPI 02132 for(int i=0; i<3; i++){ 02133 inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) 02134 boardStat = (boardStat << 8) | inByte; 02135 } 02136 for(int i = 0; i<8; i++){ 02137 for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks 02138 inByte = xfer(0x00); 02139 boardChannelDataRaw[byteCounter] = inByte; // raw data goes here 02140 byteCounter++; 02141 boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; // int data goes here 02142 } 02143 } 02144 csHigh(BOARD_ADS); // close SPI 02145 02146 // need to convert 24bit to 32bit if using the filter 02147 for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment 02148 if(bitRead(boardChannelDataInt[i],23) == 1){ 02149 boardChannelDataInt[i] |= 0xFF000000; 02150 } else{ 02151 boardChannelDataInt[i] &= 0x00FFFFFF; 02152 } 02153 } 02154 if(daisyPresent && !firstDataPacket){ 02155 byteCounter = 0; 02156 for(int i=0; i<8; i++){ // take the average of this and the last sample 02157 meanBoardChannelDataInt[i] = (lastBoardChannelDataInt[i] + boardChannelDataInt[i])/2; 02158 } 02159 for(int i=0; i<8; i++){ // place the average values in the meanRaw array 02160 for(int b=2; b>=0; b--){ 02161 meanBoardDataRaw[byteCounter] = (meanBoardChannelDataInt[i] >> (b*8)) & 0xFF; 02162 byteCounter++; 02163 } 02164 } 02165 } 02166 02167 if(firstDataPacket == true){ 02168 firstDataPacket = false; 02169 } 02170 } 02171 02172 void OpenBCI_32bit_Library::updateDaisyData(){ 02173 byte inByte; 02174 int byteCounter = 0; 02175 02176 if(daisyPresent && !firstDataPacket){ 02177 for(int i=0; i<8; i++){ // shift and average the byte arrays 02178 lastDaisyChannelDataInt[i] = daisyChannelDataInt[i]; // remember the last samples 02179 } 02180 } 02181 02182 csLow(DAISY_ADS); // open SPI 02183 for(int i=0; i<3; i++){ 02184 inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) 02185 daisyStat = (daisyStat << 8) | inByte; 02186 } 02187 for(int i = 0; i<8; i++){ 02188 for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks 02189 inByte = xfer(0x00); 02190 daisyChannelDataRaw[byteCounter] = inByte; // raw data goes here 02191 byteCounter++; 02192 daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; // int data goes here 02193 } 02194 } 02195 csHigh(DAISY_ADS); // close SPI 02196 // need to convert 24bit to 32bit 02197 for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment 02198 if(bitRead(daisyChannelDataInt[i],23) == 1){ 02199 daisyChannelDataInt[i] |= 0xFF000000; 02200 }else{ 02201 daisyChannelDataInt[i] &= 0x00FFFFFF; 02202 } 02203 } 02204 if(daisyPresent && !firstDataPacket){ 02205 byteCounter = 0; 02206 for(int i=0; i<8; i++){ // average this sample with the last sample 02207 meanDaisyChannelDataInt[i] = (lastDaisyChannelDataInt[i] + daisyChannelDataInt[i])/2; 02208 } 02209 for(int i=0; i<8; i++){ // place the average values in the meanRaw array 02210 for(int b=2; b>=0; b--){ 02211 meanDaisyDataRaw[byteCounter] = (meanDaisyChannelDataInt[i] >> (b*8)) & 0xFF; 02212 byteCounter++; 02213 } 02214 } 02215 } 02216 02217 if(firstDataPacket == true) { 02218 firstDataPacket = false; 02219 } 02220 } 02221 02222 // Stop the continuous data acquisition 02223 void OpenBCI_32bit_Library::stopADS() 02224 { 02225 STOP(BOTH_ADS); // stop the data acquisition 02226 delay(1); 02227 SDATAC(BOTH_ADS); // stop Read Data Continuous mode to communicate with ADS 02228 delay(1); 02229 isRunning = false; 02230 } 02231 02232 02233 //write as binary each channel's data 02234 void OpenBCI_32bit_Library::ADS_writeChannelData() 02235 { 02236 02237 if(daisyPresent){ 02238 if(sampleCounter % 2 != 0){ //CHECK SAMPLE ODD-EVEN AND SEND THE APPROPRIATE ADS DATA 02239 for (int i=0; i<24; i++){ 02240 Serial0.write(meanBoardDataRaw[i]); // send board data on odd samples 02241 } 02242 }else{ 02243 for (int i=0; i<24; i++){ 02244 Serial0.write(meanDaisyDataRaw[i]); // send daisy data on even samples 02245 } 02246 } 02247 }else{ 02248 for(int i=0; i<24; i++){ 02249 Serial0.write(boardChannelDataRaw[i]); 02250 } 02251 } 02252 } 02253 02254 02255 //print out the state of all the control registers 02256 void OpenBCI_32bit_Library::printADSregisters(int targetSS) 02257 { 02258 boolean prevverbosityState = verbosity; 02259 verbosity = true; // set up for verbosity output 02260 RREGS(0x00,0x0C,targetSS); // read out the first registers 02261 delay(10); // stall to let all that data get read by the PC 02262 RREGS(0x0D,0x17-0x0D,targetSS); // read out the rest 02263 verbosity = prevverbosityState; 02264 } 02265 02266 byte OpenBCI_32bit_Library::ADS_getDeviceID(int targetSS) { // simple hello world com check 02267 byte data = RREG(ID_REG,targetSS); 02268 if(verbosity){ // verbosity otuput 02269 Serial0.print("On Board ADS ID "); 02270 printHex(data); Serial0.println(); 02271 sendEOT(); 02272 } 02273 return data; 02274 } 02275 02276 //System Commands 02277 void OpenBCI_32bit_Library::WAKEUP(int targetSS) { 02278 csLow(targetSS); 02279 xfer(_WAKEUP); 02280 csHigh(targetSS); 02281 delayMicroseconds(3); //must wait 4 tCLK cycles before sending another command (Datasheet, pg. 35) 02282 } 02283 02284 void OpenBCI_32bit_Library::STANDBY(int targetSS) { // only allowed to send WAKEUP after sending STANDBY 02285 csLow(targetSS); 02286 xfer(_STANDBY); 02287 csHigh(targetSS); 02288 } 02289 02290 void OpenBCI_32bit_Library::RESET(int targetSS) { // reset all the registers to default settings 02291 csLow(targetSS); 02292 xfer(_RESET); 02293 delayMicroseconds(12); //must wait 18 tCLK cycles to execute this command (Datasheet, pg. 35) 02294 csHigh(targetSS); 02295 } 02296 02297 void OpenBCI_32bit_Library::START(int targetSS) { //start data conversion 02298 csLow(targetSS); 02299 xfer(_START); // KEEP ON-BOARD AND ON-DAISY IN SYNC 02300 csHigh(targetSS); 02301 } 02302 02303 void OpenBCI_32bit_Library::STOP(int targetSS) { //stop data conversion 02304 csLow(targetSS); 02305 xfer(_STOP); // KEEP ON-BOARD AND ON-DAISY IN SYNC 02306 csHigh(targetSS); 02307 } 02308 02309 void OpenBCI_32bit_Library::RDATAC(int targetSS) { 02310 csLow(targetSS); 02311 xfer(_RDATAC); // read data continuous 02312 csHigh(targetSS); 02313 delayMicroseconds(3); 02314 } 02315 void OpenBCI_32bit_Library::SDATAC(int targetSS) { 02316 csLow(targetSS); 02317 xfer(_SDATAC); 02318 csHigh(targetSS); 02319 delayMicroseconds(10); //must wait at least 4 tCLK cycles after executing this command (Datasheet, pg. 37) 02320 } 02321 02322 02323 // THIS NEEDS CLEANING AND UPDATING TO THE NEW FORMAT 02324 void OpenBCI_32bit_Library::RDATA(int targetSS) { // use in Stop Read Continuous mode when DRDY goes low 02325 byte inByte; // to read in one sample of the channels 02326 csLow(targetSS); // open SPI 02327 xfer(_RDATA); // send the RDATA command 02328 for(int i=0; i<3; i++){ // read in the status register and new channel data 02329 inByte = xfer(0x00); 02330 boardStat = (boardStat<<8) | inByte; // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) 02331 } 02332 if(targetSS == BOARD_ADS){ 02333 for(int i = 0; i<8; i++){ 02334 for(int j=0; j<3; j++){ // read in the new channel data 02335 inByte = xfer(0x00); 02336 boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; 02337 } 02338 } 02339 for(int i=0; i<8; i++){ 02340 if(bitRead(boardChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment 02341 boardChannelDataInt[i] |= 0xFF000000; 02342 }else{ 02343 boardChannelDataInt[i] &= 0x00FFFFFF; 02344 } 02345 } 02346 }else{ 02347 for(int i = 0; i<8; i++){ 02348 for(int j=0; j<3; j++){ // read in the new channel data 02349 inByte = xfer(0x00); 02350 daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; 02351 } 02352 } 02353 for(int i=0; i<8; i++){ 02354 if(bitRead(daisyChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment 02355 daisyChannelDataInt[i] |= 0xFF000000; 02356 }else{ 02357 daisyChannelDataInt[i] &= 0x00FFFFFF; 02358 } 02359 } 02360 } 02361 csHigh(targetSS); // close SPI 02362 02363 02364 } 02365 02366 byte OpenBCI_32bit_Library::RREG(byte _address,int targetSS) { // reads ONE register at _address 02367 byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address 02368 csLow(targetSS); // open SPI 02369 xfer(opcode1); // opcode1 02370 xfer(0x00); // opcode2 02371 regData[_address] = xfer(0x00);// update mirror location with returned byte 02372 csHigh(targetSS); // close SPI 02373 if (verbosity){ // verbosity output 02374 printRegisterName(_address); 02375 printHex(_address); 02376 Serial0.print(", "); 02377 printHex(regData[_address]); 02378 Serial0.print(", "); 02379 for(byte j = 0; j<8; j++){ 02380 Serial0.print(bitRead(regData[_address], 7-j)); 02381 if(j!=7) Serial0.print(", "); 02382 } 02383 02384 Serial0.println(); 02385 } 02386 return regData[_address]; // return requested register value 02387 } 02388 02389 02390 // Read more than one register starting at _address 02391 void OpenBCI_32bit_Library::RREGS(byte _address, byte _numRegistersMinusOne, int targetSS) { 02392 02393 byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address 02394 csLow(targetSS); // open SPI 02395 xfer(opcode1); // opcode1 02396 xfer(_numRegistersMinusOne); // opcode2 02397 for(int i = 0; i <= _numRegistersMinusOne; i++){ 02398 regData[_address + i] = xfer(0x00); // add register byte to mirror array 02399 } 02400 csHigh(targetSS); // close SPI 02401 if(verbosity){ // verbosity output 02402 for(int i = 0; i<= _numRegistersMinusOne; i++){ 02403 printRegisterName(_address + i); 02404 printHex(_address + i); 02405 Serial0.print(", "); 02406 printHex(regData[_address + i]); 02407 Serial0.print(", "); 02408 for(int j = 0; j<8; j++){ 02409 Serial0.print(bitRead(regData[_address + i], 7-j)); 02410 if(j!=7) Serial0.print(", "); 02411 } 02412 Serial0.println(); 02413 delay(30); 02414 } 02415 } 02416 } 02417 02418 void OpenBCI_32bit_Library::WREG(byte _address, byte _value, int target_SS) { // Write ONE register at _address 02419 byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address 02420 csLow(target_SS); // open SPI 02421 xfer(opcode1); // Send WREG command & address 02422 xfer(0x00); // Send number of registers to read -1 02423 xfer(_value); // Write the value to the register 02424 csHigh(target_SS); // close SPI 02425 regData[_address] = _value; // update the mirror array 02426 if(verbosity){ // verbosity output 02427 Serial0.print("Register "); 02428 printHex(_address); 02429 Serial0.println(" modified."); 02430 sendEOT(); 02431 } 02432 } 02433 02434 void OpenBCI_32bit_Library::WREGS(byte _address, byte _numRegistersMinusOne, int targetSS) { 02435 byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address 02436 csLow(targetSS); // open SPI 02437 xfer(opcode1); // Send WREG command & address 02438 xfer(_numRegistersMinusOne); // Send number of registers to read -1 02439 for (int i=_address; i <=(_address + _numRegistersMinusOne); i++){ 02440 xfer(regData[i]); // Write to the registers 02441 } 02442 csHigh(targetSS); 02443 if(verbosity){ 02444 Serial0.print("Registers "); 02445 printHex(_address); Serial0.print(" to "); 02446 printHex(_address + _numRegistersMinusOne); 02447 Serial0.println(" modified"); 02448 sendEOT(); 02449 } 02450 } 02451 02452 02453 // <<<<<<<<<<<<<<<<<<<<<<<<< END OF ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>> 02454 // ****************************************************************************** 02455 // <<<<<<<<<<<<<<<<<<<<<<<<< LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 02456 02457 02458 void OpenBCI_32bit_Library::initialize_accel(byte g){ 02459 byte setting = g | 0x08; // mask the g range for REG4 02460 pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer 02461 LIS3DH_write(TMP_CFG_REG, 0x00); // DISable ADC inputs, enable temperature sensor 02462 LIS3DH_write(CTRL_REG1, 0x08); // disable accel, low power mode 02463 LIS3DH_write(CTRL_REG2, 0x00); // don't use the high pass filter 02464 LIS3DH_write(CTRL_REG3, 0x00); // no interrupts yet 02465 LIS3DH_write(CTRL_REG4, setting); // set scale to g, high resolution 02466 LIS3DH_write(CTRL_REG5, 0x00); // no boot, no fifo 02467 LIS3DH_write(CTRL_REG6, 0x00); 02468 LIS3DH_write(REFERENCE, 0x00); 02469 DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables 02470 } 02471 02472 void OpenBCI_32bit_Library::enable_accel(byte Hz){ 02473 for(int i=0; i<3; i++){ 02474 axisData[i] = 0; // clear the axisData array so we don't get any stale news 02475 } 02476 byte setting = Hz | 0x07; // mask the desired frequency 02477 LIS3DH_write(CTRL_REG1, setting); // set freq and enable all axis in normal mode 02478 LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to PIC pin 0, LIS3DH_DRDY) 02479 } 02480 02481 void OpenBCI_32bit_Library::disable_accel(){ 02482 LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode 02483 LIS3DH_write(CTRL_REG3, 0x00); // disable DRDY1 on INT1 02484 } 02485 02486 byte OpenBCI_32bit_Library::LIS3DH_getDeviceID(){ 02487 return LIS3DH_read(WHO_AM_I); 02488 } 02489 02490 boolean OpenBCI_32bit_Library::LIS3DH_DataAvailable(){ 02491 boolean x = false; 02492 if((LIS3DH_read(STATUS_REG2) & 0x08) > 0) x = true; // read STATUS_REG 02493 return x; 02494 } 02495 02496 boolean OpenBCI_32bit_Library::LIS3DH_DataReady(){ 02497 boolean r = false; 02498 DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin 02499 if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking 02500 if(DRDYpinValue == HIGH){ // see if this is the rising edge 02501 r = true; // if so, there is fresh data! 02502 } 02503 lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin 02504 } 02505 return r; 02506 } 02507 02508 void OpenBCI_32bit_Library::LIS3DH_writeAxisData(void){ 02509 for(int i=0; i<3; i++){ 02510 Serial0.write(highByte(axisData[i])); // write 16 bit axis data MSB first 02511 Serial0.write(lowByte(axisData[i])); // axisData is array of type short (16bit) 02512 axisData[i] = 0; 02513 } 02514 } 02515 02516 void OpenBCI_32bit_Library::LIS3DH_writeAxisDataForAxis(uint8_t axis) { 02517 if (axis > 2) axis = 0; 02518 Serial0.write(highByte(axisData[axis])); // write 16 bit axis data MSB first 02519 Serial0.write(lowByte(axisData[axis])); // axisData is array of type short (16bit) 02520 axisData[axis] = 0; 02521 } 02522 02523 byte OpenBCI_32bit_Library::LIS3DH_read(byte reg){ 02524 reg |= READ_REG; // add the READ_REG bit 02525 csLow(LIS3DH_SS); // take spi 02526 spi.transfer(reg); // send reg to read 02527 byte inByte = spi.transfer(0x00); // retrieve data 02528 csHigh(LIS3DH_SS); // release spi 02529 return inByte; 02530 } 02531 02532 void OpenBCI_32bit_Library::LIS3DH_write(byte reg, byte value){ 02533 csLow(LIS3DH_SS); // take spi 02534 spi.transfer(reg); // send reg to write 02535 spi.transfer(value); // write value 02536 csHigh(LIS3DH_SS); // release spi 02537 } 02538 02539 int OpenBCI_32bit_Library::LIS3DH_read16(byte reg){ // use for reading axis data. 02540 int inData; 02541 reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits 02542 csLow(LIS3DH_SS); // take spi 02543 spi.transfer(reg); // send reg to start reading from 02544 inData = spi.transfer(0x00) | (spi.transfer(0x00) << 8); // get the data and arrange it 02545 csHigh(LIS3DH_SS); // release spi 02546 return inData; 02547 } 02548 02549 int OpenBCI_32bit_Library::getX(){ 02550 return LIS3DH_read16(OUT_X_L); 02551 } 02552 02553 int OpenBCI_32bit_Library::getY(){ 02554 return LIS3DH_read16(OUT_Y_L); 02555 } 02556 02557 int OpenBCI_32bit_Library::getZ(){ 02558 return LIS3DH_read16(OUT_Z_L); 02559 } 02560 02561 void OpenBCI_32bit_Library::LIS3DH_updateAxisData(){ 02562 axisData[0] = getX(); 02563 axisData[1] = getY(); 02564 axisData[2] = getZ(); 02565 } 02566 02567 void OpenBCI_32bit_Library::LIS3DH_readAllRegs(){ 02568 02569 byte inByte; 02570 02571 for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){ 02572 inByte = LIS3DH_read(i); 02573 Serial0.print("0x0");Serial0.print(i,HEX); 02574 Serial0.print("\t");Serial0.println(inByte,HEX); 02575 delay(20); 02576 } 02577 Serial0.println(); 02578 02579 for (int i = TMP_CFG_REG; i <= INT1_DURATION; i++){ 02580 inByte = LIS3DH_read(i); 02581 // printRegisterName(i); 02582 Serial0.print("0x");Serial0.print(i,HEX); 02583 Serial0.print("\t");Serial0.println(inByte,HEX); 02584 delay(20); 02585 } 02586 Serial0.println(); 02587 02588 for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){ 02589 inByte = LIS3DH_read(i); 02590 Serial0.print("0x");Serial0.print(i,HEX); 02591 Serial0.print("\t");Serial0.println(inByte,HEX); 02592 delay(20); 02593 } 02594 02595 } 02596 02597 02598 02599 // <<<<<<<<<<<<<<<<<<<<<<<<< END OF LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 02600 02601 02602 02603 // String-Byte converters for ADS 02604 void OpenBCI_32bit_Library::printRegisterName(byte _address) { 02605 switch(_address){ 02606 case ID_REG: 02607 Serial0.print("ADS_ID, "); break; 02608 case CONFIG1: 02609 Serial0.print("CONFIG1, "); break; 02610 case CONFIG2: 02611 Serial0.print("CONFIG2, "); break; 02612 case CONFIG3: 02613 Serial0.print("CONFIG3, "); break; 02614 case LOFF: 02615 Serial0.print("LOFF, "); break; 02616 case CH1SET: 02617 Serial0.print("CH1SET, "); break; 02618 case CH2SET: 02619 Serial0.print("CH2SET, "); break; 02620 case CH3SET: 02621 Serial0.print("CH3SET, "); break; 02622 case CH4SET: 02623 Serial0.print("CH4SET, "); break; 02624 case CH5SET: 02625 Serial0.print("CH5SET, "); break; 02626 case CH6SET: 02627 Serial0.print("CH6SET, "); break; 02628 case CH7SET: 02629 Serial0.print("CH7SET, "); break; 02630 case CH8SET: 02631 Serial0.print("CH8SET, "); break; 02632 case BIAS_SENSP: 02633 Serial0.print("BIAS_SENSP, "); break; 02634 case BIAS_SENSN: 02635 Serial0.print("BIAS_SENSN, "); break; 02636 case LOFF_SENSP: 02637 Serial0.print("LOFF_SENSP, "); break; 02638 case LOFF_SENSN: 02639 Serial0.print("LOFF_SENSN, "); break; 02640 case LOFF_FLIP: 02641 Serial0.print("LOFF_FLIP, "); break; 02642 case LOFF_STATP: 02643 Serial0.print("LOFF_STATP, "); break; 02644 case LOFF_STATN: 02645 Serial0.print("LOFF_STATN, "); break; 02646 case GPIO: 02647 Serial0.print("GPIO, "); break; 02648 case MISC1: 02649 Serial0.print("MISC1, "); break; 02650 case MISC2: 02651 Serial0.print("MISC2, "); break; 02652 case CONFIG4: 02653 Serial0.print("CONFIG4, "); break; 02654 default: 02655 break; 02656 } 02657 } 02658 02659 // Used for printing HEX in verbosity feedback mode 02660 void OpenBCI_32bit_Library::printHex(byte _data){ 02661 Serial0.print("0x"); 02662 if(_data < 0x10) Serial0.print("0"); 02663 Serial0.print(_data, HEX); 02664 } 02665 02666 /** 02667 * @description Converts ascii character to byte value for channel setting bytes 02668 * @param `asciiChar` - [char] - The ascii character to convert 02669 * @return [char] - Byte number value of acsii character, defaults to 0 02670 * @author AJ Keller (@pushtheworldllc) 02671 */ 02672 char OpenBCI_32bit_Library::getChannelCommandForAsciiChar(char asciiChar) { 02673 switch(asciiChar){ 02674 case OPENBCI_CHANNEL_CMD_CHANNEL_1: 02675 return 0x00; 02676 case OPENBCI_CHANNEL_CMD_CHANNEL_2: 02677 return 0x01; 02678 case OPENBCI_CHANNEL_CMD_CHANNEL_3: 02679 return 0x02; 02680 case OPENBCI_CHANNEL_CMD_CHANNEL_4: 02681 return 0x03; 02682 case OPENBCI_CHANNEL_CMD_CHANNEL_5: 02683 return 0x04; 02684 case OPENBCI_CHANNEL_CMD_CHANNEL_6: 02685 return 0x05; 02686 case OPENBCI_CHANNEL_CMD_CHANNEL_7: 02687 return 0x06; 02688 case OPENBCI_CHANNEL_CMD_CHANNEL_8: 02689 return 0x07; 02690 case OPENBCI_CHANNEL_CMD_CHANNEL_9: 02691 return 0x08; 02692 case OPENBCI_CHANNEL_CMD_CHANNEL_10: 02693 return 0x09; 02694 case OPENBCI_CHANNEL_CMD_CHANNEL_11: 02695 return 0x0A; 02696 case OPENBCI_CHANNEL_CMD_CHANNEL_12: 02697 return 0x0B; 02698 case OPENBCI_CHANNEL_CMD_CHANNEL_13: 02699 return 0x0C; 02700 case OPENBCI_CHANNEL_CMD_CHANNEL_14: 02701 return 0x0D; 02702 case OPENBCI_CHANNEL_CMD_CHANNEL_15: 02703 return 0x0E; 02704 case OPENBCI_CHANNEL_CMD_CHANNEL_16: 02705 return 0x0F; 02706 default: 02707 return 0x00; 02708 } 02709 } 02710 02711 /** 02712 * @description Converts ascii '0' to number 0 and ascii '1' to number 1 02713 * @param `asciiChar` - [char] - The ascii character to convert 02714 * @return [char] - Byte number value of acsii character, defaults to 0 02715 * @author AJ Keller (@pushtheworldllc) 02716 */ 02717 char OpenBCI_32bit_Library::getYesOrNoForAsciiChar(char asciiChar) { 02718 switch (asciiChar) { 02719 case '1': 02720 return ACTIVATE; 02721 case '0': 02722 default: 02723 return DEACTIVATE; 02724 } 02725 } 02726 02727 /** 02728 * @description Converts ascii character to get gain from channel settings 02729 * @param `asciiChar` - [char] - The ascii character to convert 02730 * @return [char] - Byte number value of acsii character, defaults to 0 02731 * @author AJ Keller (@pushtheworldllc) 02732 */ 02733 char OpenBCI_32bit_Library::getGainForAsciiChar(char asciiChar) { 02734 02735 char output = 0x00; 02736 02737 if (asciiChar < '0' || asciiChar > '6') { 02738 asciiChar = '6'; // Default to 24 02739 } 02740 02741 output = asciiChar - '0'; 02742 02743 return output << 4; 02744 } 02745 02746 /** 02747 * @description Converts ascii character to get gain from channel settings 02748 * @param `asciiChar` - [char] - The ascii character to convert 02749 * @return [char] - Byte number value of acsii character, defaults to 0 02750 * @author AJ Keller (@pushtheworldllc) 02751 */ 02752 char OpenBCI_32bit_Library::getNumberForAsciiChar(char asciiChar) { 02753 if (asciiChar < '0' || asciiChar > '9') { 02754 asciiChar = '0'; 02755 } 02756 02757 // Convert ascii char to number 02758 asciiChar -= '0'; 02759 02760 return asciiChar; 02761 } 02762 02763 /** 02764 * @description Used to set the channelSettings array to default settings 02765 * @param `setting` - [byte] - The byte you need a setting for.... 02766 * @returns - [byte] - Retuns the proper byte for the input setting, defualts to 0 02767 */ 02768 byte OpenBCI_32bit_Library::getDefaultChannelSettingForSetting(byte setting) { 02769 switch (setting) { 02770 case POWER_DOWN: 02771 return NO; 02772 case GAIN_SET: 02773 return ADS_GAIN24; 02774 case INPUT_TYPE_SET: 02775 return ADSINPUT_NORMAL; 02776 case BIAS_SET: 02777 return YES; 02778 case SRB2_SET: 02779 return YES; 02780 case SRB1_SET: 02781 default: 02782 return NO; 02783 } 02784 } 02785 02786 /** 02787 * @description Used to set the channelSettings array to default settings 02788 * @param `setting` - [byte] - The byte you need a setting for.... 02789 * @returns - [char] - Retuns the proper ascii char for the input setting, defaults to '0' 02790 */ 02791 char OpenBCI_32bit_Library::getDefaultChannelSettingForSettingAscii(byte setting) { 02792 switch (setting) { 02793 case GAIN_SET: // Special case where GAIN_SET needs to be shifted first 02794 return (ADS_GAIN24 >> 4) + '0'; 02795 default: // All other settings are just adding the ascii value for '0' 02796 return getDefaultChannelSettingForSetting(setting) + '0'; 02797 } 02798 } 02799 02800 /** 02801 * @description Convert user channelNumber for use in array indexs by subtracting 1, 02802 * also make sure N is not greater than 15 or less than 0 02803 * @param `channelNumber` - [byte] - The channel number 02804 * @return [byte] - Constrained channel number 02805 */ 02806 char OpenBCI_32bit_Library::getConstrainedChannelNumber(byte channelNumber) { 02807 return constrain(channelNumber - 1, 0, OPENBCI_NUMBER_OF_CHANNELS_DAISY - 1); 02808 } 02809 02810 /** 02811 * @description Get slave select pin for channelNumber 02812 * @param `channelNumber` - [byte] - The channel number 02813 * @return [byte] - Constrained channel number 02814 */ 02815 char OpenBCI_32bit_Library::getTargetSSForConstrainedChannelNumber(byte channelNumber) { 02816 // Is channelNumber in the range of default [0,7] 02817 if (channelNumber < OPENBCI_NUMBER_OF_CHANNELS_DEFAULT) { 02818 return BOARD_ADS; 02819 } else { 02820 return DAISY_ADS; 02821 } 02822 } 02823 02824 /** 02825 * @description Used to set the channelSettings array to default settings 02826 * @param `channelSettingsArray` - [byte **] - Takes a two dimensional array of 02827 * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 6 elements 02828 */ 02829 void OpenBCI_32bit_Library::resetChannelSettingsArrayToDefault(byte channelSettingsArray[][OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]) { 02830 // Loop through all channels 02831 for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) { 02832 channelSettingsArray[i][POWER_DOWN] = getDefaultChannelSettingForSetting(POWER_DOWN); // on = NO, off = YES 02833 channelSettingsArray[i][GAIN_SET] = getDefaultChannelSettingForSetting(GAIN_SET); // Gain setting 02834 channelSettingsArray[i][INPUT_TYPE_SET] = getDefaultChannelSettingForSetting(INPUT_TYPE_SET); // input muxer setting 02835 channelSettingsArray[i][BIAS_SET] = getDefaultChannelSettingForSetting(BIAS_SET); // add this channel to bias generation 02836 channelSettingsArray[i][SRB2_SET] = getDefaultChannelSettingForSetting(SRB2_SET); // connect this P side to SRB2 02837 channelSettingsArray[i][SRB1_SET] = getDefaultChannelSettingForSetting(SRB1_SET); // don't use SRB1 02838 02839 useInBias[i] = true; // keeping track of Bias Generation 02840 useSRB2[i] = true; // keeping track of SRB2 inclusion 02841 } 02842 02843 boardUseSRB1 = daisyUseSRB1 = false; 02844 } 02845 02846 /** 02847 * @description Used to set the channelSettings array to default settings 02848 * @param `channelSettingsArray` - [byte **] - A two dimensional array of 02849 * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 2 elements 02850 */ 02851 void OpenBCI_32bit_Library::resetLeadOffArrayToDefault(byte leadOffArray[][OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS]) { 02852 // Loop through all channels 02853 for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) { 02854 leadOffArray[i][PCHAN] = OFF; 02855 leadOffArray[i][NCHAN] = OFF; 02856 } 02857 } 02858 02859 OpenBCI_32bit_Library board;
Generated on Wed Jul 20 2022 12:01:51 by
1.7.2