Alex Borisevich / Mbed 2 deprecated OpenBCI

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers OpenBCI_32bit_Library.cpp Source File

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;