Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /* | |
| OpenBCI 32bit Library | |
| Place the containing folder into your libraries folder insdie the arduino folder in your Documents folder | |
| This library will work with a single OpenBCI 32bit board, or | |
| an OpenBCI 32bit board with an OpenBCI Daisy Module attached. | |
| */ | |
| #include "OpenBCI_32bit_Library.h" | |
| /***************************************************/ | |
| /** PUBLIC METHODS *********************************/ | |
| /***************************************************/ | |
| // CONSTRUCTOR | |
| OpenBCI_32bit_Library::OpenBCI_32bit_Library() { | |
| curBoardMode = OPENBCI_BOARD_MODE_DEFAULT; | |
| daisyPresent = false; | |
| sniffMode = false; | |
| useAccel = false; | |
| useAux = false; | |
| channelDataAvailable = false; | |
| initializeVariables(); | |
| } | |
| /** | |
| * @description: The function the OpenBCI board will call in setup. | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::begin(void) { | |
| curBoardMode = OPENBCI_BOARD_MODE_DEFAULT; | |
| // Bring the board up | |
| boardBegin(); | |
| } | |
| /** | |
| * @description: The function the OpenBCI board will call in setup. Turns sniff mode | |
| * on and allows you to tap into the serial port that is broken out on the OpenBCI | |
| * 32bit board. You must alter this file: | |
| * On Mac: | |
| * `/Users/username/Documents/Arduino/hardware/chipkit-core/pic32/variants/openbci/Board_Defs.h` | |
| * On Windows: | |
| * `C:\Users\username\Documents\Arduino\hardware\chipkit-core\pic32\variants\openbci\Board_Defs.h` | |
| * Specifically lines `311` and `313` from `7` and `10` to `11` and `12` for | |
| * `_SER1_TX_PIN` and `_SER1_RX_PIN` respectively. Check out this sweet gif if | |
| * you are a visual person http://g.recordit.co/3jH01sMD6Y.gif | |
| * You will need to reflash your board! But now you can connect to pins `11` | |
| * `12` via a FTDI serial port driver, really any serial to USB driver would | |
| * work. Remember to use 3V3, 115200 baud, and have a common ground! | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::beginDebug(void) { | |
| // Bring the board up | |
| boolean started = boardBeginDebug(); | |
| curBoardMode = OPENBCI_BOARD_MODE_DEBUG; | |
| sniffMode = true; | |
| if (Serial1) { | |
| if (started) { | |
| Serial1.println("Board up"); | |
| } else { | |
| Serial1.println("Board err"); | |
| } | |
| } | |
| } | |
| /** | |
| * @description: The function the OpenBCI board will call in setup. This sets up the hardware serial port on D11 and D12 | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| boolean OpenBCI_32bit_Library::beginSecondarySerial(void) { | |
| // Initalize the serial 1 port | |
| Serial1.begin(OPENBCI_BAUD_RATE); | |
| return true; | |
| } | |
| /** | |
| * @description Called in every `loop()` and checks `Serial0` | |
| * @returns {boolean} - `true` if there is data ready to be read | |
| */ | |
| boolean OpenBCI_32bit_Library::hasDataSerial0(void) { | |
| if (Serial0.available()) { | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| /** | |
| * @description Called in every `loop()` and checks `Serial0` | |
| * @returns {boolean} - `true` if there is data ready to be read | |
| */ | |
| boolean OpenBCI_32bit_Library::hasDataSerial1(void) { | |
| if (Serial1.available()) { | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| /** | |
| * @description Called if `hasDataSerial0` is true, returns a char from `Serial0` | |
| * @returns {char} - A char from the serial port | |
| */ | |
| char OpenBCI_32bit_Library::getCharSerial0(void) { | |
| return Serial0.read(); | |
| } | |
| /** | |
| * @description Called if `hasDataSerial1` is true, returns a char from `Serial1` | |
| * @returns {char} - A char from the serial port | |
| */ | |
| char OpenBCI_32bit_Library::getCharSerial1(void) { | |
| return Serial1.read(); | |
| } | |
| /** | |
| * @description If `isSerialAvailableForRead()` is `true` then this function is | |
| * called. Reads from `Serial0` first and foremost, which comes from the RFduino. | |
| * If `sniffMode` is true and `Serial0` didn't have any data, we will try to | |
| * read from `Serial1`. If both are not available then we will return a `0x00` | |
| * which is NOT a command that the system will recognize, aka this function has | |
| * many safe guards. | |
| * @returns {char} - The character from the serial port. | |
| */ | |
| // char OpenBCI_32bit_Library::readOneSerialChar(void) { | |
| // if (Serial0.available()) { | |
| // return Serial0.read(); | |
| // } else if (sniffMode && Serial1.available()) { | |
| // return Serial1.read(); | |
| // } else { | |
| // return 0x00; | |
| // } | |
| // } | |
| /** | |
| * @description Public function for sending data to the PC | |
| * @param data {char *} - The data you want to send | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::writeSerial(char *data, int len) { | |
| for (int i = 0; i < len; i++) { | |
| Serial0.write(data[i]); | |
| } | |
| } | |
| /** | |
| * @description While processing incoming multi byte messages these will turn | |
| * true. | |
| * @return {boolean} - True if processing a message and false otherwise | |
| */ | |
| boolean OpenBCI_32bit_Library::isProcessingMultibyteMsg(void) { | |
| return isProcessingIncomingSettingsChannel || isProcessingIncomingSettingsLeadOff || settingBoardMode; | |
| } | |
| /** | |
| * @description Process one char at a time from serial port. This is the main | |
| * command processor for the OpenBCI system. Considered mission critical for | |
| * normal operation. | |
| * @param `character` {char} - The character to process. | |
| * @return {boolean} - `true` if the command was recognized, `false` if not | |
| */ | |
| boolean OpenBCI_32bit_Library::processChar(char character) { | |
| if (sniffMode && Serial1) { | |
| Serial1.print("pC: "); Serial1.println(character); | |
| } | |
| if (isProcessingMultibyteMsg()) { | |
| if (isProcessingIncomingSettingsChannel) { | |
| processIncomingChannelSettings(character); | |
| } else if (isProcessingIncomingSettingsLeadOff) { | |
| processIncomingLeadOffSettings(character); | |
| } else if (settingBoardMode) { | |
| processIncomingBoardMode(character); | |
| } | |
| } else { // Normal... | |
| switch (character){ | |
| //TURN CHANNELS ON/OFF COMMANDS | |
| case OPENBCI_CHANNEL_OFF_1: | |
| streamSafeChannelDeactivate(1); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_2: | |
| streamSafeChannelDeactivate(2); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_3: | |
| streamSafeChannelDeactivate(3); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_4: | |
| streamSafeChannelDeactivate(4); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_5: | |
| streamSafeChannelDeactivate(5); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_6: | |
| streamSafeChannelDeactivate(6); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_7: | |
| streamSafeChannelDeactivate(7); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_8: | |
| streamSafeChannelDeactivate(8); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_9: | |
| streamSafeChannelDeactivate(9); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_10: | |
| streamSafeChannelDeactivate(10); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_11: | |
| streamSafeChannelDeactivate(11); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_12: | |
| streamSafeChannelDeactivate(12); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_13: | |
| streamSafeChannelDeactivate(13); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_14: | |
| streamSafeChannelDeactivate(14); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_15: | |
| streamSafeChannelDeactivate(15); | |
| break; | |
| case OPENBCI_CHANNEL_OFF_16: | |
| streamSafeChannelDeactivate(16); | |
| break; | |
| case OPENBCI_CHANNEL_ON_1: | |
| streamSafeChannelActivate(1); | |
| break; | |
| case OPENBCI_CHANNEL_ON_2: | |
| streamSafeChannelActivate(2); | |
| break; | |
| case OPENBCI_CHANNEL_ON_3: | |
| streamSafeChannelActivate(3); | |
| break; | |
| case OPENBCI_CHANNEL_ON_4: | |
| streamSafeChannelActivate(4); | |
| break; | |
| case OPENBCI_CHANNEL_ON_5: | |
| streamSafeChannelActivate(5); | |
| break; | |
| case OPENBCI_CHANNEL_ON_6: | |
| streamSafeChannelActivate(6); | |
| break; | |
| case OPENBCI_CHANNEL_ON_7: | |
| streamSafeChannelActivate(7); | |
| break; | |
| case OPENBCI_CHANNEL_ON_8: | |
| streamSafeChannelActivate(8); | |
| break; | |
| case OPENBCI_CHANNEL_ON_9: | |
| streamSafeChannelActivate(9); | |
| break; | |
| case OPENBCI_CHANNEL_ON_10: | |
| streamSafeChannelActivate(10); | |
| break; | |
| case OPENBCI_CHANNEL_ON_11: | |
| streamSafeChannelActivate(11); | |
| break; | |
| case OPENBCI_CHANNEL_ON_12: | |
| streamSafeChannelActivate(12); | |
| break; | |
| case OPENBCI_CHANNEL_ON_13: | |
| streamSafeChannelActivate(13); | |
| break; | |
| case OPENBCI_CHANNEL_ON_14: | |
| streamSafeChannelActivate(14); | |
| break; | |
| case OPENBCI_CHANNEL_ON_15: | |
| streamSafeChannelActivate(15); | |
| break; | |
| case OPENBCI_CHANNEL_ON_16: | |
| streamSafeChannelActivate(16); | |
| break; | |
| // TEST SIGNAL CONTROL COMMANDS | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_GROUND: | |
| activateAllChannelsToTestCondition(ADSINPUT_SHORTED,ADSTESTSIG_NOCHANGE,ADSTESTSIG_NOCHANGE); | |
| break; | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_SLOW: | |
| activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_SLOW); | |
| break; | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_1X_FAST: | |
| activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_1X,ADSTESTSIG_PULSE_FAST); | |
| break; | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_DC: | |
| activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_DCSIG); | |
| break; | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_SLOW: | |
| activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_SLOW); | |
| break; | |
| case OPENBCI_TEST_SIGNAL_CONNECT_TO_PULSE_2X_FAST: | |
| activateAllChannelsToTestCondition(ADSINPUT_TESTSIG,ADSTESTSIG_AMP_2X,ADSTESTSIG_PULSE_FAST); | |
| break; | |
| // CHANNEL SETTING COMMANDS | |
| case OPENBCI_CHANNEL_CMD_SET: // This is the first byte that tells us to expect more commands | |
| isProcessingIncomingSettingsChannel = true; | |
| numberOfIncomingSettingsProcessedChannel = 1; | |
| break; | |
| // LEAD OFF IMPEDANCE DETECTION COMMANDS | |
| case OPENBCI_CHANNEL_IMPEDANCE_SET: | |
| isProcessingIncomingSettingsLeadOff = true; | |
| numberOfIncomingSettingsProcessedLeadOff = 1; | |
| break; | |
| case OPENBCI_CHANNEL_DEFAULT_ALL_SET: // reset all channel settings to default | |
| if(!streaming) { | |
| Serial0.println("updating channel settings to default"); | |
| sendEOT(); | |
| } | |
| streamSafeSetAllChannelsToDefault(); | |
| break; | |
| case OPENBCI_CHANNEL_DEFAULT_ALL_REPORT: // report the default settings | |
| reportDefaultChannelSettings(); | |
| break; | |
| // DAISY MODULE COMMANDS | |
| case OPENBCI_CHANNEL_MAX_NUMBER_8: // use 8 channel mode | |
| if(daisyPresent){ | |
| removeDaisy(); | |
| } | |
| break; | |
| case OPENBCI_CHANNEL_MAX_NUMBER_16: // use 16 channel mode | |
| if(daisyPresent == false){ | |
| attachDaisy(); | |
| } | |
| if(daisyPresent){ | |
| Serial0.print("16"); | |
| }else{ | |
| Serial0.print("8"); | |
| } | |
| sendEOT(); | |
| break; | |
| // STREAM DATA AND FILTER COMMANDS | |
| case OPENBCI_STREAM_START: // stream data | |
| if(useAccel){ | |
| enable_accel(RATE_25HZ); | |
| } // fire up the accelerometer if you want it | |
| streamStart(); // turn on the fire hose | |
| break; | |
| case OPENBCI_STREAM_STOP: // stop streaming data | |
| if(useAccel){ | |
| disable_accel(); | |
| } // shut down the accelerometer if you're using it | |
| streamStop(); | |
| break; | |
| // INITIALIZE AND VERIFY | |
| case OPENBCI_MISC_SOFT_RESET: | |
| boardReset(); // initialize ADS and read device IDs | |
| break; | |
| // QUERY THE ADS AND ACCEL REGITSTERS | |
| case OPENBCI_MISC_QUERY_REGISTER_SETTINGS: | |
| if (!streaming) { | |
| printAllRegisters(); // print the ADS and accelerometer register values | |
| } | |
| break; | |
| // TIME SYNC | |
| case OPENBCI_TIME_SET: | |
| // Set flag to send time packet | |
| if (streaming) { | |
| sendTimeSyncUpPacket = true; | |
| } else { | |
| Serial0.print("Time stamp ON"); | |
| sendEOT(); | |
| } | |
| timeSynced = true; | |
| break; | |
| case OPENBCI_TIME_STOP: | |
| // Stop the Sync | |
| timeSynced = false; | |
| if (!streaming) { | |
| Serial0.print("Time stamp OFF"); | |
| sendEOT(); | |
| } | |
| break; | |
| // PACKET SET TYPE | |
| case OPENBCI_BOARD_MODE_SET: | |
| // Tell this function which case that is | |
| settingBoardMode = true; | |
| break; | |
| default: | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| /** | |
| * @description Reads a status register to see if there is new accelerometer | |
| * data. | |
| * @returns {boolean} `true` if the accelerometer has new data. | |
| */ | |
| boolean OpenBCI_32bit_Library::accelHasNewData(void) { | |
| return LIS3DH_DataAvailable(); | |
| } | |
| /** | |
| * @description Reads from the accelerometer to get new X, Y, and Z data. Updates | |
| * the global array `axisData`. | |
| */ | |
| void OpenBCI_32bit_Library::accelUpdateAxisData(void) { | |
| LIS3DH_updateAxisData(); | |
| } | |
| /** | |
| * @description Reads from the accelerometer to get new X, Y, and Z data. | |
| */ | |
| void OpenBCI_32bit_Library::accelWriteAxisData(void) { | |
| LIS3DH_writeAxisData(); | |
| } | |
| /** | |
| * @description: This is a function that is called once and confiures all pins on | |
| * the PIC32 uC | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| boolean OpenBCI_32bit_Library::boardBegin(void) { | |
| // Initalize the serial port baud rate | |
| Serial0.begin(OPENBCI_BAUD_RATE); | |
| pinMode(OPENBCI_PIN_LED, OUTPUT); | |
| pinMode(OPENBCI_PIN_PGC, OUTPUT); | |
| // Startup for interrupt | |
| setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR | |
| setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority | |
| clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together | |
| setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq | |
| // Do a soft reset | |
| boardReset(); | |
| return true; | |
| } | |
| /** | |
| * @description: This is a function that is called once and confiures all pins on | |
| * the PIC32 uC | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| boolean OpenBCI_32bit_Library::boardBeginDebug(void) { | |
| // Initalize the serial port baud rate | |
| Serial0.begin(OPENBCI_BAUD_RATE); | |
| // Initalize the serial debug port | |
| Serial1.begin(OPENBCI_BAUD_RATE); | |
| // Startup for interrupt | |
| setIntVector(_EXTERNAL_4_VECTOR, ADS_DRDY_Service); // connect interrupt to ISR | |
| setIntPriority(_EXTERNAL_4_VECTOR, 4, 0); // set interrupt priority and sub priority | |
| clearIntFlag(_EXTERNAL_4_IRQ); // these two need to be done together | |
| setIntEnable(_EXTERNAL_4_IRQ); // clear any flags before enabing the irq | |
| // Do a soft reset | |
| boardReset(); | |
| return true; | |
| } | |
| /** | |
| * @description: This is a function that is called once and confiures the Pic to run in secondary serial mode | |
| * @param baudRate {int} - The baudRate you want the secondary serial port to run at. | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| boolean OpenBCI_32bit_Library::boardBeginDebug(int baudRate) { | |
| // Initalize the serial port baud rate | |
| Serial0.begin(OPENBCI_BAUD_RATE); | |
| // Initalize the serial debug port | |
| Serial1.begin(baudRate); | |
| // Do a soft reset | |
| boardReset(); | |
| return true; | |
| } | |
| /** | |
| * @description: This is a function that can be called multiple times, this is | |
| * what we refer to as a `soft reset`. You will hear/see this | |
| * many times. | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::boardReset(void) { | |
| initialize(); // initalizes accelerometer and on-board ADS and on-daisy ADS if present | |
| delay(500); | |
| configureLeadOffDetection(LOFF_MAG_6NA, LOFF_FREQ_31p2HZ); | |
| Serial0.println("OpenBCI V3 8-16 channel"); | |
| Serial0.print("On Board ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_BOARD),HEX); | |
| if(daisyPresent){ // library will set this in initialize() if daisy present and functional | |
| Serial0.print("On Daisy ADS1299 Device ID: 0x"); Serial0.println(ADS_getDeviceID(ON_DAISY),HEX); | |
| } | |
| Serial0.print("LIS3DH Device ID: 0x"); Serial0.println(LIS3DH_getDeviceID(),HEX); | |
| Serial0.println("Firmware: v2.0.1"); | |
| sendEOT(); | |
| } | |
| /** | |
| * @description: Simple method to send the EOT over serial... | |
| * @author: AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::sendEOT(void) { | |
| Serial0.print("$$$"); | |
| } | |
| void OpenBCI_32bit_Library::activateAllChannelsToTestCondition(byte testInputCode, byte amplitudeCode, byte freqCode) | |
| { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| //set the test signal to the desired state | |
| configureInternalTestSignal(amplitudeCode,freqCode); | |
| //change input type settings for all channels | |
| changeInputType(testInputCode); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description When a 'z' is found on the serial port, we jump to this function | |
| * where we continue to read from the serial port and read the | |
| * remaining 4 bytes. | |
| * @param `character` - {char} - The character you want to process... | |
| */ | |
| void OpenBCI_32bit_Library::processIncomingBoardMode(char c) { | |
| if (isValidBoardType(c)) { | |
| curBoardMode = c; | |
| if (!streaming) { | |
| Serial0.print("Success: Board type set"); | |
| sendEOT(); | |
| } | |
| } else { | |
| if (!streaming) { | |
| Serial0.print("Failure: invalid board mode"); | |
| sendEOT(); | |
| } | |
| } | |
| settingBoardMode = false; | |
| } | |
| /** | |
| * @description When a 'x' is found on the serial port, we jump to this function | |
| * where we continue to read from the serial port and read the | |
| * remaining 7 bytes. | |
| */ | |
| void OpenBCI_32bit_Library::processIncomingChannelSettings(char character) { | |
| if (character == OPENBCI_CHANNEL_CMD_LATCH && numberOfIncomingSettingsProcessedChannel < OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL - 1) { | |
| // We failed somehow and should just abort | |
| numberOfIncomingSettingsProcessedChannel = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsChannel = false; | |
| if (!streaming) { | |
| Serial0.print("Channel setting failure: too few chars"); sendEOT(); | |
| } | |
| return; | |
| } | |
| switch (numberOfIncomingSettingsProcessedChannel) { | |
| case 1: // channel number | |
| currentChannelSetting = getChannelCommandForAsciiChar(character); | |
| break; | |
| case 2: // POWER_DOWN | |
| channelSettings[currentChannelSetting][POWER_DOWN] = getNumberForAsciiChar(character); | |
| break; | |
| case 3: // GAIN_SET | |
| channelSettings[currentChannelSetting][GAIN_SET] = getGainForAsciiChar(character); | |
| break; | |
| case 4: // INPUT_TYPE_SET | |
| channelSettings[currentChannelSetting][INPUT_TYPE_SET] = getNumberForAsciiChar(character); | |
| break; | |
| case 5: // BIAS_SET | |
| channelSettings[currentChannelSetting][BIAS_SET] = getNumberForAsciiChar(character); | |
| break; | |
| case 6: // SRB2_SET | |
| channelSettings[currentChannelSetting][SRB2_SET] = getNumberForAsciiChar(character); | |
| break; | |
| case 7: // SRB1_SET | |
| channelSettings[currentChannelSetting][SRB1_SET] = getNumberForAsciiChar(character); | |
| break; | |
| case 8: // 'X' latch | |
| if (character != OPENBCI_CHANNEL_CMD_LATCH) { | |
| if (!streaming) { | |
| Serial0.print("Err: 9th char not "); | |
| Serial0.println(OPENBCI_CHANNEL_CMD_LATCH); | |
| sendEOT(); | |
| } | |
| // We failed somehow and should just abort | |
| numberOfIncomingSettingsProcessedChannel = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsChannel = false; | |
| } | |
| break; | |
| default: // should have exited | |
| if (!streaming) { | |
| Serial0.print("Err: too many chars"); | |
| sendEOT(); | |
| } | |
| // We failed somehow and should just abort | |
| numberOfIncomingSettingsProcessedChannel = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsChannel = false; | |
| return; | |
| } | |
| // increment the number of bytes processed | |
| numberOfIncomingSettingsProcessedChannel++; | |
| if (numberOfIncomingSettingsProcessedChannel == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_CHANNEL)) { | |
| // We are done processing channel settings... | |
| if (!streaming) { | |
| Serial0.print("Channel set for "); Serial0.println(currentChannelSetting + 1); sendEOT(); | |
| } | |
| if (sniffMode && Serial1) { | |
| Serial1.print("Channel set for "); Serial1.println(currentChannelSetting + 1); | |
| } | |
| // Set channel settings | |
| 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]); | |
| // Reset | |
| numberOfIncomingSettingsProcessedChannel = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsChannel = false; | |
| } | |
| } | |
| /** | |
| * @description When a 'z' is found on the serial port, we jump to this function | |
| * where we continue to read from the serial port and read the | |
| * remaining 4 bytes. | |
| * @param `character` - {char} - The character you want to process... | |
| */ | |
| void OpenBCI_32bit_Library::processIncomingLeadOffSettings(char character) { | |
| if (character == OPENBCI_CHANNEL_IMPEDANCE_LATCH && numberOfIncomingSettingsProcessedLeadOff < OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF - 1) { | |
| // We failed somehow and should just abort | |
| // reset numberOfIncomingSettingsProcessedLeadOff | |
| numberOfIncomingSettingsProcessedLeadOff = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsLeadOff = false; | |
| if (!streaming) { | |
| Serial0.print("Lead off failure: too few chars"); sendEOT(); | |
| } | |
| return; | |
| } | |
| switch (numberOfIncomingSettingsProcessedLeadOff) { | |
| case 1: // channel number | |
| currentChannelSetting = getChannelCommandForAsciiChar(character); | |
| break; | |
| case 2: // pchannel setting | |
| leadOffSettings[currentChannelSetting][PCHAN] = getNumberForAsciiChar(character); | |
| break; | |
| case 3: // nchannel setting | |
| leadOffSettings[currentChannelSetting][NCHAN] = getNumberForAsciiChar(character); | |
| break; | |
| case 4: // 'Z' latch | |
| if (character != OPENBCI_CHANNEL_IMPEDANCE_LATCH) { | |
| if (!streaming) { | |
| Serial0.print("Err: 5th char not "); | |
| Serial0.println(OPENBCI_CHANNEL_IMPEDANCE_LATCH); | |
| sendEOT(); | |
| } | |
| // We failed somehow and should just abort | |
| // reset numberOfIncomingSettingsProcessedLeadOff | |
| numberOfIncomingSettingsProcessedLeadOff = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsLeadOff = false; | |
| } | |
| break; | |
| default: // should have exited | |
| if (!streaming) { | |
| Serial0.print("Err: too many chars "); | |
| sendEOT(); | |
| } | |
| // We failed somehow and should just abort | |
| // reset numberOfIncomingSettingsProcessedLeadOff | |
| numberOfIncomingSettingsProcessedLeadOff = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsLeadOff = false; | |
| return; | |
| } | |
| // increment the number of bytes processed | |
| numberOfIncomingSettingsProcessedLeadOff++; | |
| if (numberOfIncomingSettingsProcessedLeadOff == (OPENBCI_NUMBER_OF_BYTES_SETTINGS_LEAD_OFF)) { | |
| // We are done processing lead off settings... | |
| if (!streaming) { | |
| Serial0.print("Lead off set for "); Serial0.println(currentChannelSetting + 1); sendEOT(); | |
| } | |
| if (sniffMode && Serial1) { | |
| Serial1.print("Lead off set for "); Serial1.println(currentChannelSetting + 1); | |
| } | |
| // Set lead off settings | |
| streamSafeLeadOffSetForChannel(currentChannelSetting + 1,leadOffSettings[currentChannelSetting][PCHAN],leadOffSettings[currentChannelSetting][NCHAN]); | |
| // reset numberOfIncomingSettingsProcessedLeadOff | |
| numberOfIncomingSettingsProcessedLeadOff = 0; | |
| // put flag back down | |
| isProcessingIncomingSettingsLeadOff = false; | |
| } | |
| } | |
| boolean OpenBCI_32bit_Library::isValidBoardType(char c) { | |
| switch (c) { | |
| case OPENBCI_BOARD_MODE_DEFAULT: | |
| case OPENBCI_BOARD_MODE_DEBUG: | |
| case OPENBCI_BOARD_MODE_WIFI: | |
| case OPENBCI_BOARD_MODE_INPUT_ANALOG: | |
| case OPENBCI_BOARD_MODE_INPUT_DIGITAL: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| // <<<<<<<<<<<<<<<<<<<<<<<<< BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| void OpenBCI_32bit_Library::initialize(){ | |
| pinMode(SD_SS,OUTPUT); digitalWrite(SD_SS,HIGH); // de-select SDcard if present | |
| pinMode(BOARD_ADS, OUTPUT); digitalWrite(BOARD_ADS,HIGH); | |
| pinMode(DAISY_ADS, OUTPUT); digitalWrite(DAISY_ADS,HIGH); | |
| pinMode(LIS3DH_SS,OUTPUT); digitalWrite(LIS3DH_SS,HIGH); | |
| spi.begin(); | |
| spi.setSpeed(4000000); // use 4MHz for ADS and LIS3DH | |
| spi.setMode(DSPI_MODE0); // default to SD card mode! | |
| initialize_ads(); // hard reset ADS, set pin directions | |
| initialize_accel(SCALE_4G); // set pin directions, G scale, DRDY interrupt, power down | |
| initializeVariables(); | |
| } | |
| // void __USER_ISR ADS_DRDY_Service() { | |
| void __USER_ISR ADS_DRDY_Service() { | |
| clearIntFlag(_EXTERNAL_4_IRQ); // clear the irq, or else it will continually interrupt! | |
| if(bitRead(PORTA,0) == 0){ | |
| board.channelDataAvailable = true; | |
| } | |
| } | |
| void OpenBCI_32bit_Library::initializeVariables(void) { | |
| streaming = false; | |
| sendTimeSyncUpPacket = false; | |
| timeSynced = false; | |
| isProcessingIncomingSettingsChannel = false; | |
| isProcessingIncomingSettingsLeadOff = false; | |
| settingBoardMode = false; | |
| numberOfIncomingSettingsProcessedChannel = 0; | |
| numberOfIncomingSettingsProcessedLeadOff = 0; | |
| currentChannelSetting = 0; | |
| timeOffset = 0; | |
| timeSetCharArrived = 0; | |
| streamPacketType = (char)OPENBCI_PACKET_TYPE_V3; | |
| verbosity = false; // when verbosity is true, there will be Serial feedback | |
| } | |
| void OpenBCI_32bit_Library::printAllRegisters(){ | |
| if(!isRunning){ | |
| Serial0.println("\nBoard ADS Registers"); | |
| printADSregisters(BOARD_ADS); | |
| if(daisyPresent){ | |
| Serial0.println("\nDaisy ADS Registers"); | |
| printADSregisters(DAISY_ADS); | |
| } | |
| Serial0.println("\nLIS3DH Registers"); | |
| LIS3DH_readAllRegs(); | |
| sendEOT(); | |
| } | |
| } | |
| /** | |
| * @description Writes channel data and `axisData` array to serial port in | |
| * the correct stream packet format. | |
| * | |
| * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h` | |
| */ | |
| void OpenBCI_32bit_Library::sendChannelDataWithAccel(void) { | |
| Serial0.write('A'); // 0x41 | |
| Serial0.write(sampleCounter); // 1 byte | |
| ADS_writeChannelData(); // 24 bytes | |
| accelWriteAxisData(); // 6 bytes | |
| Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xC0 | |
| sampleCounter++; | |
| } | |
| /** | |
| * @description Writes channel data and `auxData` array to serial port in | |
| * the correct stream packet format. | |
| * | |
| * Adds stop byte `OPENBCI_EOP_STND_RAW_AUX`. See `OpenBCI_32bit_Library_Definitions.h` | |
| */ | |
| void OpenBCI_32bit_Library::sendChannelDataWithRawAux(void) { | |
| Serial0.write('A'); // 1 byte | |
| Serial0.write(sampleCounter); // 1 byte | |
| ADS_writeChannelData(); // 24 bytes | |
| writeAuxData(); // 6 bytes | |
| Serial0.write(OPENBCI_EOP_STND_RAW_AUX); // 0xC1 - 1 byte | |
| sampleCounter++; | |
| } | |
| /** | |
| * @description Writes channel data, `axisData` array, and 4 byte unsigned time | |
| * stamp in ms to serial port in the correct stream packet format. | |
| * | |
| * `axisData` will be split up and sent on the samples with `sampleCounter` of | |
| * 7, 8, and 9 for X, Y, and Z respectively. Driver writers parse accordingly. | |
| * | |
| * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar` | |
| * getting a time sync set `<` command) then: | |
| * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SET` and sets `sendTimeSyncUpPacket` | |
| * to `false`. | |
| * Else if `sendTimeSyncUpPacket` is `false` then: | |
| * Adds stop byte `OPENBCI_EOP_ACCEL_TIME_SYNCED` | |
| */ | |
| void OpenBCI_32bit_Library::sendChannelDataWithTimeAndAccel(void) { | |
| Serial0.write('A'); | |
| Serial0.write(sampleCounter); // 1 byte | |
| ADS_writeChannelData(); // 24 bytes | |
| // send two bytes of either accel data or blank | |
| switch (sampleCounter % 10) { | |
| case ACCEL_AXIS_X: // 7 | |
| LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_X); | |
| break; | |
| case ACCEL_AXIS_Y: // 8 | |
| LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Y); | |
| break; | |
| case ACCEL_AXIS_Z: // 9 | |
| LIS3DH_writeAxisDataForAxis(ACCEL_AXIS_Z); | |
| break; | |
| default: | |
| Serial0.write((byte)0x00); // high byte | |
| Serial0.write((byte)0x00); // low byte | |
| break; | |
| } | |
| writeTimeCurrent(); // 4 bytes | |
| if (sendTimeSyncUpPacket) { | |
| sendTimeSyncUpPacket = false; | |
| Serial0.write(OPENBCI_EOP_ACCEL_TIME_SET); // 0xC3 | |
| } else { | |
| Serial0.write(OPENBCI_EOP_ACCEL_TIME_SYNCED); // 0xC4 | |
| } | |
| sampleCounter++; | |
| } | |
| /** | |
| * @description Writes channel data, `auxData[0]` 2 bytes, and 4 byte unsigned | |
| * time stamp in ms to serial port in the correct stream packet format. | |
| * | |
| * If the global variable `sendTimeSyncUpPacket` is `true` (set by `processChar` | |
| * getting a time sync set `<` command) then: | |
| * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SET` and sets `sendTimeSyncUpPacket` | |
| * to `false`. | |
| * Else if `sendTimeSyncUpPacket` is `false` then: | |
| * Adds stop byte `OPENBCI_EOP_RAW_AUX_TIME_SYNCED` | |
| */ | |
| void OpenBCI_32bit_Library::sendChannelDataWithTimeAndRawAux(void) { | |
| Serial0.print('A'); | |
| Serial0.write(sampleCounter); // 1 byte | |
| ADS_writeChannelData(); // 24 bytes | |
| Serial0.write(highByte(auxData[0])); // 2 bytes of aux data | |
| Serial0.write(lowByte(auxData[0])); | |
| writeTimeCurrent(); // 4 bytes | |
| if (sendTimeSyncUpPacket) { | |
| sendTimeSyncUpPacket = false; | |
| Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SET); // 0xC5 | |
| } else { | |
| Serial0.write(OPENBCI_EOP_RAW_AUX_TIME_SYNCED); // 0xC6 | |
| } | |
| sampleCounter++; | |
| } | |
| /** | |
| * @description Writes channel data, aux data, and footer to serial port. This | |
| * is the old way to send channel data. Based on global variables `useAux` | |
| * and `useAccel` Must keep for portability. Will look to deprecate in 3.0.0. | |
| * | |
| * If `useAccel` is `true` then sends data from `axisData` array and sets the | |
| * contents of `axisData` to `0`. | |
| * If `useAux` is `true` then sends data from `auxData` array and sets the | |
| * contents of `auxData` to `0`. | |
| * | |
| * Adds stop byte `OPENBCI_EOP_STND_ACCEL`. See `OpenBCI_32bit_Library_Definitions.h` | |
| */ | |
| void OpenBCI_32bit_Library::sendChannelData(void) { | |
| Serial0.print('A'); | |
| Serial0.write(sampleCounter); // 1 byte | |
| ADS_writeChannelData(); // 24 bytes | |
| if(useAux){ | |
| writeAuxData(); // 6 bytes of aux data | |
| } else if(useAccel){ // or | |
| LIS3DH_writeAxisData(); // 6 bytes of accelerometer data | |
| } else{ | |
| for(int i=0; i<6; i++){ | |
| Serial0.write((byte)0x00); | |
| } | |
| } | |
| Serial0.write(OPENBCI_EOP_STND_ACCEL); // 0xF0 | |
| sampleCounter++; | |
| } | |
| void OpenBCI_32bit_Library::writeAuxData(){ | |
| for(int i=0; i<3; i++){ | |
| Serial0.write(highByte(auxData[i])); // write 16 bit axis data MSB first | |
| Serial0.write(lowByte(auxData[i])); // axisData is array of type short (16bit) | |
| auxData[i] = 0; // reset auxData bytes to 0 | |
| } | |
| } | |
| void OpenBCI_32bit_Library::writeTimeCurrent(void) { | |
| uint32_t newTime = millis(); // serialize the number, placing the MSB in lower packets | |
| for (int j = 3; j >= 0; j--) { | |
| Serial0.write(newTime >> (j*8)); | |
| } | |
| } | |
| //SPI communication method | |
| byte OpenBCI_32bit_Library::xfer(byte _data) | |
| { | |
| byte inByte; | |
| inByte = spi.transfer(_data); | |
| return inByte; | |
| } | |
| //SPI chip select method | |
| void OpenBCI_32bit_Library::csLow(int SS) | |
| { // select an SPI slave to talk to | |
| switch(SS){ | |
| case BOARD_ADS: | |
| spi.setMode(DSPI_MODE1); | |
| spi.setSpeed(4000000); | |
| digitalWrite(BOARD_ADS, LOW); | |
| break; | |
| case LIS3DH_SS: | |
| spi.setMode(DSPI_MODE3); | |
| spi.setSpeed(4000000); | |
| digitalWrite(LIS3DH_SS, LOW); | |
| break; | |
| case SD_SS: | |
| spi.setMode(DSPI_MODE0); | |
| spi.setSpeed(20000000); | |
| digitalWrite(SD_SS, LOW); | |
| break; | |
| case DAISY_ADS: | |
| spi.setMode(DSPI_MODE1); | |
| spi.setSpeed(4000000); | |
| digitalWrite(DAISY_ADS, LOW); | |
| break; | |
| case BOTH_ADS: | |
| spi.setMode(DSPI_MODE1); | |
| spi.setSpeed(4000000); | |
| digitalWrite(BOARD_ADS,LOW); | |
| digitalWrite(DAISY_ADS,LOW); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void OpenBCI_32bit_Library::csHigh(int SS) | |
| { // deselect SPI slave | |
| switch(SS){ | |
| case BOARD_ADS: | |
| digitalWrite(BOARD_ADS, HIGH); | |
| spi.setSpeed(20000000); | |
| break; | |
| case LIS3DH_SS: | |
| digitalWrite(LIS3DH_SS, HIGH); | |
| spi.setSpeed(20000000); | |
| break; | |
| case SD_SS: | |
| digitalWrite(SD_SS, HIGH); | |
| spi.setSpeed(4000000); | |
| break; | |
| case DAISY_ADS: | |
| digitalWrite(DAISY_ADS, HIGH); | |
| spi.setSpeed(20000000); | |
| break; | |
| case BOTH_ADS: | |
| digitalWrite(BOARD_ADS, HIGH); | |
| digitalWrite(DAISY_ADS, HIGH); | |
| spi.setSpeed(20000000); break; | |
| default: | |
| break; | |
| } | |
| spi.setMode(DSPI_MODE0); // DEFAULT TO SD MODE! | |
| } | |
| // <<<<<<<<<<<<<<<<<<<<<<<<< END OF BOARD WIDE FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| // ************************************************************************************* | |
| // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| void OpenBCI_32bit_Library::initialize_ads(){ | |
| // recommended power up sequence requiers >Tpor (~32mS) | |
| delay(50); | |
| pinMode(ADS_RST,OUTPUT); | |
| digitalWrite(ADS_RST,LOW); // reset pin connected to both ADS ICs | |
| delayMicroseconds(4); // toggle reset pin | |
| digitalWrite(ADS_RST,HIGH); // this will reset the Daisy if it is present | |
| delayMicroseconds(20); // recommended to wait 18 Tclk before using device (~8uS); | |
| // initalize the data ready chip select and reset pins: | |
| pinMode(ADS_DRDY, INPUT); // we get DRDY asertion from the on-board ADS | |
| delay(40); | |
| resetADS(BOARD_ADS); // reset the on-board ADS registers, and stop DataContinuousMode | |
| delay(10); | |
| WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output its clk, set the data rate to 250SPS | |
| delay(40); | |
| resetADS(DAISY_ADS); // software reset daisy module if present | |
| delay(10); | |
| daisyPresent = smellDaisy(); // check to see if daisy module is present | |
| if(!daisyPresent){ | |
| WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present | |
| numChannels = 8; // expect up to 8 ADS channels | |
| }else{ | |
| numChannels = 16; // expect up to 16 ADS channels | |
| } | |
| // DEFAULT CHANNEL SETTINGS FOR ADS | |
| defaultChannelSettings[POWER_DOWN] = NO; // on = NO, off = YES | |
| defaultChannelSettings[GAIN_SET] = ADS_GAIN24; // Gain setting | |
| defaultChannelSettings[INPUT_TYPE_SET] = ADSINPUT_NORMAL;// input muxer setting | |
| defaultChannelSettings[BIAS_SET] = YES; // add this channel to bias generation | |
| defaultChannelSettings[SRB2_SET] = YES; // connect this P side to SRB2 | |
| defaultChannelSettings[SRB1_SET] = NO; // don't use SRB1 | |
| for(int i=0; i<numChannels; i++){ | |
| for(int j=0; j<6; j++){ | |
| channelSettings[i][j] = defaultChannelSettings[j]; // assign default settings | |
| } | |
| useInBias[i] = true; // keeping track of Bias Generation | |
| useSRB2[i] = true; // keeping track of SRB2 inclusion | |
| } | |
| boardUseSRB1 = daisyUseSRB1 = false; | |
| writeChannelSettings(); // write settings to the on-board and on-daisy ADS if present | |
| WREG(CONFIG3,0b11101100,BOTH_ADS); delay(1); // enable internal reference drive and etc. | |
| for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal | |
| leadOffSettings[i][PCHAN] = OFF; | |
| leadOffSettings[i][NCHAN] = OFF; | |
| } | |
| firstDataPacket = true; | |
| streaming = false; | |
| } | |
| ////////////////////////////////////////////// | |
| ///////////// STREAM METHODS ///////////////// | |
| ////////////////////////////////////////////// | |
| /** | |
| * @description Used to activate a channel, if running must stop and start after... | |
| * @param channelNumber int the channel you want to change | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeChannelActivate(byte channelNumber) { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| // Activate the channel | |
| activateChannel(channelNumber); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Used to deactivate a channel, if running must stop and start after... | |
| * @param channelNumber int the channel you want to change | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeChannelDeactivate(byte channelNumber){ | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| // deactivate the channel | |
| deactivateChannel(channelNumber); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Used to set lead off for a channel, if running must stop and start after... | |
| * @param `channelNumber` - [byte] - The channel you want to change | |
| * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0) | |
| * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0) | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeLeadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| changeChannelLeadOffDetect(channelNumber); | |
| // leadOffSetForChannel(channelNumber, pInput, nInput); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Used to set lead off for a channel, if running must stop and start after... | |
| * @param see `.channelSettingsSetForChannel()` for parameters | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeChannelSettingsForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| writeChannelSettings(channelNumber); | |
| // channelSettingsSetForChannel(channelNumber, powerDown, gain, inputType, bias, srb2, srb1); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Used to report (Serial0.print) the default channel settings | |
| * if running must stop and start after... | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeReportAllChannelDefaults(void) { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| reportDefaultChannelSettings(); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Used to set all channels on Board (and Daisy) to the default | |
| * channel settings if running must stop and start after... | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| void OpenBCI_32bit_Library::streamSafeSetAllChannelsToDefault(void) { | |
| boolean wasStreaming = streaming; | |
| // Stop streaming if you are currently streaming | |
| if (streaming) { | |
| streamStop(); | |
| } | |
| setChannelsToDefault(); | |
| // Restart stream if need be | |
| if (wasStreaming) { | |
| streamStart(); | |
| } | |
| } | |
| /** | |
| * @description Call this to start the streaming data from the ADS1299 | |
| * @returns boolean if able to start streaming | |
| */ | |
| void OpenBCI_32bit_Library::streamStart(){ // needs daisy functionality | |
| streaming = true; | |
| startADS(); | |
| if (sniffMode && Serial1) { | |
| Serial1.println("ADS Started"); | |
| } | |
| } | |
| /** | |
| * @description Call this to stop streaming from the ADS1299 | |
| * @returns boolean if able to stop streaming | |
| */ | |
| void OpenBCI_32bit_Library::streamStop(){ | |
| streaming = false; | |
| stopADS(); | |
| if (sniffMode && Serial1) { | |
| Serial1.println("ADS Stopped"); | |
| } | |
| } | |
| ////////////////////////////////////////////// | |
| ////////////// DAISY METHODS ///////////////// | |
| ////////////////////////////////////////////// | |
| boolean OpenBCI_32bit_Library::smellDaisy(void){ // check if daisy present | |
| boolean isDaisy = false; | |
| byte setting = RREG(ID_REG,DAISY_ADS); // try to read the daisy product ID | |
| if(verbosity){Serial0.print("Daisy ID 0x"); Serial0.println(setting,HEX); sendEOT();} | |
| if(setting == ADS_ID) {isDaisy = true;} // should read as 0x3E | |
| return isDaisy; | |
| } | |
| void OpenBCI_32bit_Library::removeDaisy(void){ | |
| if(daisyPresent){ | |
| // Daisy removed | |
| SDATAC(DAISY_ADS); | |
| RESET(DAISY_ADS); | |
| STANDBY(DAISY_ADS); | |
| daisyPresent = false; | |
| if(!isRunning) { | |
| Serial0.println("daisy removed"); | |
| sendEOT(); | |
| } | |
| }else{ | |
| if(!isRunning) { | |
| Serial0.println("no daisy to remove!"); | |
| sendEOT(); | |
| } | |
| } | |
| } | |
| void OpenBCI_32bit_Library::attachDaisy(void){ | |
| WREG(CONFIG1,0xB6,BOARD_ADS); // tell on-board ADS to output the clk, set the data rate to 250SPS | |
| delay(40); | |
| resetADS(DAISY_ADS); // software reset daisy module if present | |
| delay(10); | |
| daisyPresent = smellDaisy(); | |
| if(!daisyPresent){ | |
| WREG(CONFIG1,0x96,BOARD_ADS); // turn off clk output if no daisy present | |
| numChannels = 8; // expect up to 8 ADS channels | |
| if(!isRunning) Serial0.println("no daisy to attach!"); | |
| }else{ | |
| numChannels = 16; // expect up to 16 ADS channels | |
| if(!isRunning) Serial0.println("daisy attached"); | |
| } | |
| } | |
| //reset all the ADS1299's settings. Stops all data acquisition | |
| void OpenBCI_32bit_Library::resetADS(int targetSS) | |
| { | |
| int startChan, stopChan; | |
| if(targetSS == BOARD_ADS) {startChan = 1; stopChan = 8;} | |
| if(targetSS == DAISY_ADS) {startChan = 9; stopChan = 16;} | |
| RESET(targetSS); // send RESET command to default all registers | |
| SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS | |
| delay(100); | |
| // turn off all channels | |
| for (int chan=startChan; chan <= stopChan; chan++) { | |
| deactivateChannel(chan); | |
| } | |
| } | |
| void OpenBCI_32bit_Library::setChannelsToDefault(void){ | |
| for(int i=0; i<numChannels; i++){ | |
| for(int j=0; j<6; j++){ | |
| channelSettings[i][j] = defaultChannelSettings[j]; | |
| } | |
| useInBias[i] = true; // keeping track of Bias Generation | |
| useSRB2[i] = true; // keeping track of SRB2 inclusion | |
| } | |
| boardUseSRB1 = daisyUseSRB1 = false; | |
| writeChannelSettings(); // write settings to on-board ADS | |
| for(int i=0; i<numChannels; i++){ // turn off the impedance measure signal | |
| leadOffSettings[i][PCHAN] = OFF; | |
| leadOffSettings[i][NCHAN] = OFF; | |
| } | |
| changeChannelLeadOffDetect(); // write settings to all ADS | |
| WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board | |
| if(daisyPresent){ WREG(MISC1,0x00,DAISY_ADS); } // open SRB1 switch on-daisy | |
| } | |
| // void OpenBCI_32bit_Library::setChannelsToDefault(void){ | |
| // // Reset the global channel settings array to default | |
| // resetChannelSettingsArrayToDefault(channelSettings); | |
| // // Write channel settings to board (and daisy) ADS | |
| // channelSettingsArraySetForAll(); | |
| // // Reset the global lead off settings array to default | |
| // resetLeadOffArrayToDefault(leadOffSettings); | |
| // // Write lead off settings to board (and daisy) ADS | |
| // leadOffSetForAllChannels(); | |
| // WREG(MISC1,0x00,BOARD_ADS); // open SRB1 switch on-board | |
| // if(daisyPresent){ // open SRB1 switch on-daisy | |
| // WREG(MISC1,0x00,DAISY_ADS); | |
| // } | |
| // } | |
| /** | |
| * @description Writes the default channel settings over the serial port | |
| */ | |
| void OpenBCI_32bit_Library::reportDefaultChannelSettings(void){ | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(POWER_DOWN)); // on = NO, off = YES | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(GAIN_SET)); // Gain setting | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(INPUT_TYPE_SET)); // input muxer setting | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(BIAS_SET)); // add this channel to bias generation | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(SRB2_SET)); // connect this P side to SRB2 | |
| Serial0.write(getDefaultChannelSettingForSettingAscii(SRB1_SET)); // don't use SRB1 | |
| sendEOT(); | |
| } | |
| /** | |
| * @description Set all channels using global channelSettings array | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::channelSettingsArraySetForAll(void) { | |
| // byte channelNumberUpperLimit; | |
| // // The upper limit of the channels, either 8 or 16 | |
| // channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; | |
| // // Loop through all channels | |
| // for (byte i = 1; i <= channelNumberUpperLimit; i++) { | |
| // // Set for this channel | |
| // 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]); | |
| // } | |
| // } | |
| /** | |
| * @description Set channel using global channelSettings array for channelNumber | |
| * @param `channelNumber` - [byte] - 1-16 channel number | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::channelSettingsArraySetForChannel(byte channelNumber) { | |
| // // contstrain the channel number to 0-15 | |
| // char index = getConstrainedChannelNumber(channelNumber); | |
| // // Set for this channel | |
| // 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]); | |
| // } | |
| /** | |
| * @description To add a usability abstraction layer above channel setting commands. Due to the | |
| * extensive and highly specific nature of the channel setting command chain. | |
| * @param `channelNumber` - [byte] (1-16) for index, so convert channel to array prior | |
| * @param `powerDown` - [byte] - YES (1) or NO (0) | |
| * Powers channel down | |
| * @param `gain` - [byte] - Sets the gain for the channel | |
| * ADS_GAIN01 (0b00000000) // 0x00 | |
| * ADS_GAIN02 (0b00010000) // 0x10 | |
| * ADS_GAIN04 (0b00100000) // 0x20 | |
| * ADS_GAIN06 (0b00110000) // 0x30 | |
| * ADS_GAIN08 (0b01000000) // 0x40 | |
| * ADS_GAIN12 (0b01010000) // 0x50 | |
| * ADS_GAIN24 (0b01100000) // 0x60 | |
| * @param `inputType` - [byte] - Selects the ADC channel input source, either: | |
| * ADSINPUT_NORMAL (0b00000000) | |
| * ADSINPUT_SHORTED (0b00000001) | |
| * ADSINPUT_BIAS_MEAS (0b00000010) | |
| * ADSINPUT_MVDD (0b00000011) | |
| * ADSINPUT_TEMP (0b00000100) | |
| * ADSINPUT_TESTSIG (0b00000101) | |
| * ADSINPUT_BIAS_DRP (0b00000110) | |
| * ADSINPUT_BIAL_DRN (0b00000111) | |
| * @param `bias` - [byte] (YES (1) -> Include in bias (default), NO (0) -> remove from bias) | |
| * selects to include the channel input in bias generation | |
| * @param `srb2` - [byte] (YES (1) -> Connect this input to SRB2 (default), | |
| * NO (0) -> Disconnect this input from SRB2) | |
| * Select to connect (YES) this channel's P input to the SRB2 pin. This closes | |
| * a switch between P input and SRB2 for the given channel, and allows the | |
| * P input to also remain connected to the ADC. | |
| * @param `srb1` - [byte] (YES (1) -> connect all N inputs to SRB1, | |
| * NO (0) -> Disconnect all N inputs from SRB1 (default)) | |
| * Select to connect (YES) all channels' N inputs to SRB1. This effects all pins, | |
| * and disconnects all N inputs from the ADC. | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::channelSettingsSetForChannel(byte channelNumber, byte powerDown, byte gain, byte inputType, byte bias, byte srb2, byte srb1) { | |
| // byte setting, targetSS; | |
| // // contstrain the channel number to 0-15 | |
| // char index = getConstrainedChannelNumber(channelNumber); | |
| // // Get the slave select pin for this channel | |
| // targetSS = getTargetSSForConstrainedChannelNumber(index); | |
| // if (sniffMode && Serial1) { | |
| // if (targetSS == BOARD_ADS) { | |
| // Serial1.print("Set channel "); Serial1.print(channelNumber); Serial1.println(" settings"); | |
| // } | |
| // } | |
| // // first, disable any data collection | |
| // SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| // setting = 0x00; | |
| // // Set the power down bit | |
| // if(powerDown == YES) { | |
| // setting |= 0x80; | |
| // } | |
| // // Set the gain bits | |
| // setting |= gain; | |
| // // Set input type bits | |
| // setting |= inputType; | |
| // if(srb2 == YES){ | |
| // setting |= 0x08; // close this SRB2 switch | |
| // useSRB2[index] = true; // keep track of SRB2 usage | |
| // }else{ | |
| // useSRB2[index] = false; | |
| // } | |
| // byte channelNumberRegister = 0x00; | |
| // // Since we are addressing 8 bit registers, we need to subtract 8 from the | |
| // // channelNumber if we are addressing the Daisy ADS | |
| // if (targetSS == DAISY_ADS) { | |
| // channelNumberRegister = index - OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; | |
| // } else { | |
| // channelNumberRegister = index; | |
| // } | |
| // WREG(CH1SET+channelNumberRegister, setting, targetSS); // write this channel's register settings | |
| // // add or remove from inclusion in BIAS generation | |
| // setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings | |
| // if(bias == YES){ | |
| // useInBias[index] = true; | |
| // bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation | |
| // }else{ | |
| // useInBias[index] = false; | |
| // bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation | |
| // } | |
| // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings | |
| // if(bias == YES){ | |
| // bitSet(setting,channelNumberRegister); //set this channel's bit to add it to the bias generation | |
| // }else{ | |
| // bitClear(setting,channelNumberRegister); // clear this channel's bit to remove from bias generation | |
| // } | |
| // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // byte startChan = targetSS == BOARD_ADS ? 0 : OPENBCI_CHANNEL_MAX_NUMBER_8 - 1; | |
| // byte endChan = targetSS == BOARD_ADS ? OPENBCI_CHANNEL_MAX_NUMBER_8 : OPENBCI_CHANNEL_MAX_NUMBER_16 - 1; | |
| // // if SRB1 is closed or open for one channel, it will be the same for all channels | |
| // if(srb1 == YES){ | |
| // for(int i=startChan; i<endChan; i++){ | |
| // channelSettings[i][SRB1_SET] = YES; | |
| // } | |
| // if(targetSS == BOARD_ADS) boardUseSRB1 = true; | |
| // if(targetSS == DAISY_ADS) daisyUseSRB1 = true; | |
| // setting = 0x20; // close SRB1 swtich | |
| // } | |
| // if(srb1 == NO){ | |
| // for(int i=startChan; i<endChan; i++){ | |
| // channelSettings[i][SRB1_SET] = NO; | |
| // } | |
| // if(targetSS == BOARD_ADS) boardUseSRB1 = false; | |
| // if(targetSS == DAISY_ADS) daisyUseSRB1 = false; | |
| // setting = 0x00; // open SRB1 switch | |
| // } | |
| // WREG(MISC1,setting,targetSS); | |
| // } | |
| // write settings for ALL 8 channels for a given ADS board | |
| // channel settings: powerDown, gain, inputType, SRB2, SRB1 | |
| void OpenBCI_32bit_Library::writeChannelSettings(){ | |
| boolean use_SRB1 = false; | |
| byte setting, startChan, endChan, targetSS; | |
| for(int b=0; b<2; b++){ | |
| if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; } | |
| if(b == 1){ | |
| if(!daisyPresent){ return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| for(byte i=startChan; i<endChan; i++){ // write 8 channel settings | |
| setting = 0x00; | |
| if(channelSettings[i][POWER_DOWN] == YES){setting |= 0x80;} | |
| setting |= channelSettings[i][GAIN_SET]; // gain | |
| setting |= channelSettings[i][INPUT_TYPE_SET]; // input code | |
| if(channelSettings[i][SRB2_SET] == YES){ | |
| setting |= 0x08; // close this SRB2 switch | |
| useSRB2[i] = true; // remember SRB2 state for this channel | |
| }else{ | |
| useSRB2[i] = false; // rememver SRB2 state for this channel | |
| } | |
| WREG(CH1SET+(i-startChan),setting,targetSS); // write this channel's register settings | |
| // add or remove this channel from inclusion in BIAS generation | |
| setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings | |
| if(channelSettings[i][BIAS_SET] == YES){ | |
| bitSet(setting,i-startChan); useInBias[i] = true; //add this channel to the bias generation | |
| }else{ | |
| bitClear(setting,i-startChan); useInBias[i] = false; //remove this channel from bias generation | |
| } | |
| WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings | |
| if(channelSettings[i][BIAS_SET] == YES){ | |
| bitSet(setting,i-startChan); //set this channel's bit to add it to the bias generation | |
| }else{ | |
| bitClear(setting,i-startChan); // clear this channel's bit to remove from bias generation | |
| } | |
| WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| if(channelSettings[i][SRB1_SET] == YES){ | |
| use_SRB1 = true; // if any of the channel setting closes SRB1, it is closed for all | |
| } | |
| } // end of CHnSET and BIAS settings | |
| } // end of board select loop | |
| if(use_SRB1){ | |
| for(int i=startChan; i<endChan; i++){ | |
| channelSettings[i][SRB1_SET] = YES; | |
| } | |
| WREG(MISC1,0x20,targetSS); // close SRB1 swtich | |
| if(targetSS == BOARD_ADS){ boardUseSRB1 = true; } | |
| if(targetSS == DAISY_ADS){ daisyUseSRB1 = true; } | |
| }else{ | |
| for(int i=startChan; i<endChan; i++){ | |
| channelSettings[i][SRB1_SET] = NO; | |
| } | |
| WREG(MISC1,0x00,targetSS); // open SRB1 switch | |
| if(targetSS == BOARD_ADS){ boardUseSRB1 = false; } | |
| if(targetSS == DAISY_ADS){ daisyUseSRB1 = false; } | |
| } | |
| } | |
| // write settings for a SPECIFIC channel on a given ADS board | |
| void OpenBCI_32bit_Library::writeChannelSettings(byte N){ | |
| byte setting, startChan, endChan, targetSS; | |
| if(N < 9){ // channels 1-8 on board | |
| targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| }else{ // channels 9-16 on daisy module | |
| if(!daisyPresent) { return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| // function accepts channel 1-16, must be 0 indexed to work with array | |
| N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 | |
| // first, disable any data collection | |
| SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| setting = 0x00; | |
| if(channelSettings[N][POWER_DOWN] == YES) setting |= 0x80; | |
| setting |= channelSettings[N][GAIN_SET]; // gain | |
| setting |= channelSettings[N][INPUT_TYPE_SET]; // input code | |
| if(channelSettings[N][SRB2_SET] == YES){ | |
| setting |= 0x08; // close this SRB2 switch | |
| useSRB2[N] = true; // keep track of SRB2 usage | |
| }else{ | |
| useSRB2[N] = false; | |
| } | |
| WREG(CH1SET+(N-startChan), setting, targetSS); // write this channel's register settings | |
| // add or remove from inclusion in BIAS generation | |
| setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings | |
| if(channelSettings[N][BIAS_SET] == YES){ | |
| useInBias[N] = true; | |
| bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| }else{ | |
| useInBias[N] = false; | |
| bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| } | |
| WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings | |
| if(channelSettings[N][BIAS_SET] == YES){ | |
| bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| }else{ | |
| bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| } | |
| WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // if SRB1 is closed or open for one channel, it will be the same for all channels | |
| if(channelSettings[N][SRB1_SET] == YES){ | |
| for(int i=startChan; i<endChan; i++){ | |
| channelSettings[i][SRB1_SET] = YES; | |
| } | |
| if(targetSS == BOARD_ADS) boardUseSRB1 = true; | |
| if(targetSS == DAISY_ADS) daisyUseSRB1 = true; | |
| setting = 0x20; // close SRB1 swtich | |
| } | |
| if(channelSettings[N][SRB1_SET] == NO){ | |
| for(int i=startChan; i<endChan; i++){ | |
| channelSettings[i][SRB1_SET] = NO; | |
| } | |
| if(targetSS == BOARD_ADS) boardUseSRB1 = false; | |
| if(targetSS == DAISY_ADS) daisyUseSRB1 = false; | |
| setting = 0x00; // open SRB1 switch | |
| } | |
| WREG(MISC1,setting,targetSS); | |
| } | |
| // deactivate the given channel. | |
| void OpenBCI_32bit_Library::deactivateChannel(byte N) | |
| { | |
| byte setting, startChan, endChan, targetSS; | |
| if(N < 9){ | |
| targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| }else{ | |
| if(!daisyPresent) { return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 | |
| setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings | |
| bitSet(setting,7); // set bit7 to shut down channel | |
| bitClear(setting,3); // clear bit3 to disclude from SRB2 if used | |
| WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel | |
| //remove the channel from the bias generation... | |
| setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings | |
| bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation | |
| WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings | |
| bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation | |
| WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| leadOffSettings[N][0] = leadOffSettings[N][1] = NO; | |
| changeChannelLeadOffDetect(N+1); | |
| } | |
| void OpenBCI_32bit_Library::activateChannel(byte N) | |
| { | |
| byte setting, startChan, endChan, targetSS; | |
| if(N < 9){ | |
| targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| }else{ | |
| if(!daisyPresent) { return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15 | |
| SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS | |
| setting = 0x00; | |
| // channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE? | |
| setting |= channelSettings[N][GAIN_SET]; // gain | |
| setting |= channelSettings[N][INPUT_TYPE_SET]; // input code | |
| if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;} | |
| if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch | |
| WREG(CH1SET+(N-startChan),setting,targetSS); | |
| // add or remove from inclusion in BIAS generation | |
| if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;} | |
| setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings | |
| if(channelSettings[N][BIAS_SET] == YES){ | |
| bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| useInBias[N] = true; | |
| }else{ | |
| bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| useInBias[N] = false; | |
| } | |
| WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings | |
| if(channelSettings[N][BIAS_SET] == YES){ | |
| bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| }else{ | |
| bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| } | |
| WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| setting = 0x00; | |
| if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20; | |
| if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20; | |
| WREG(MISC1,setting,targetSS); // close all SRB1 swtiches | |
| } | |
| // change the lead off detect settings for all channels | |
| void OpenBCI_32bit_Library::changeChannelLeadOffDetect() | |
| { | |
| byte setting, startChan, endChan, targetSS; | |
| for(int b=0; b<2; b++){ | |
| if(b == 0){ targetSS = BOARD_ADS; startChan = 0; endChan = 8; } | |
| if(b == 1){ | |
| if(!daisyPresent){ return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| byte P_setting = RREG(LOFF_SENSP,targetSS); | |
| byte N_setting = RREG(LOFF_SENSN,targetSS); | |
| for(int i=startChan; i<endChan; i++){ | |
| if(leadOffSettings[i][PCHAN] == ON){ | |
| bitSet(P_setting,i-startChan); | |
| }else{ | |
| bitClear(P_setting,i-startChan); | |
| } | |
| if(leadOffSettings[i][NCHAN] == ON){ | |
| bitSet(N_setting,i-startChan); | |
| }else{ | |
| bitClear(N_setting,i-startChan); | |
| } | |
| WREG(LOFF_SENSP,P_setting,targetSS); | |
| WREG(LOFF_SENSN,N_setting,targetSS); | |
| } | |
| } | |
| } | |
| // change the lead off detect settings for specified channel | |
| void OpenBCI_32bit_Library::changeChannelLeadOffDetect(byte N) | |
| { | |
| byte setting, targetSS, startChan, endChan; | |
| if(N < 9){ | |
| targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| }else{ | |
| if(!daisyPresent) { return; } | |
| targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| } | |
| N = constrain(N-1,startChan,endChan-1); | |
| SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| byte P_setting = RREG(LOFF_SENSP,targetSS); | |
| byte N_setting = RREG(LOFF_SENSN,targetSS); | |
| if(leadOffSettings[N][PCHAN] == ON){ | |
| bitSet(P_setting,N-startChan); | |
| }else{ | |
| bitClear(P_setting,N-startChan); | |
| } | |
| if(leadOffSettings[N][NCHAN] == ON){ | |
| bitSet(N_setting,N-startChan); | |
| }else{ | |
| bitClear(N_setting,N-startChan); | |
| } | |
| WREG(LOFF_SENSP,P_setting,targetSS); | |
| WREG(LOFF_SENSN,N_setting,targetSS); | |
| } | |
| void OpenBCI_32bit_Library::configureLeadOffDetection(byte amplitudeCode, byte freqCode) | |
| { | |
| amplitudeCode &= 0b00001100; //only these two bits should be used | |
| freqCode &= 0b00000011; //only these two bits should be used | |
| byte setting, targetSS; | |
| for(int i=0; i<2; i++){ | |
| if(i == 0){ targetSS = BOARD_ADS; } | |
| if(i == 1){ | |
| if(!daisyPresent){ return; } | |
| targetSS = DAISY_ADS; | |
| } | |
| setting = RREG(LOFF,targetSS); //get the current bias settings | |
| //reconfigure the byte to get what we want | |
| setting &= 0b11110000; //clear out the last four bits | |
| setting |= amplitudeCode; //set the amplitude | |
| setting |= freqCode; //set the frequency | |
| //send the config byte back to the hardware | |
| WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| } | |
| } | |
| // // deactivate the given channel. | |
| // void OpenBCI_32bit_Library::deactivateChannel(byte N) | |
| // { | |
| // byte setting, startChan, endChan, targetSS; | |
| // if(N < 9){ | |
| // targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| // }else{ | |
| // if(!daisyPresent) { return; } | |
| // targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| // } | |
| // SDATAC(targetSS); delay(1); // exit Read Data Continuous mode to communicate with ADS | |
| // N = constrain(N-1,startChan,endChan-1); //subtracts 1 so that we're counting from 0, not 1 | |
| // setting = RREG(CH1SET+(N-startChan),targetSS); delay(1); // get the current channel settings | |
| // bitSet(setting,7); // set bit7 to shut down channel | |
| // bitClear(setting,3); // clear bit3 to disclude from SRB2 if used | |
| // WREG(CH1SET+(N-startChan),setting,targetSS); delay(1); // write the new value to disable the channel | |
| // //remove the channel from the bias generation... | |
| // setting = RREG(BIAS_SENSP,targetSS); delay(1); //get the current bias settings | |
| // bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation | |
| // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // setting = RREG(BIAS_SENSN,targetSS); delay(1); //get the current bias settings | |
| // bitClear(setting,N-startChan); //clear this channel's bit to remove from bias generation | |
| // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // leadOffSettings[N][PCHAN] = leadOffSettings[N][NCHAN] = NO; | |
| // leadOffSetForChannel(N+1, NO, NO); | |
| // } | |
| // void OpenBCI_32bit_Library::activateChannel(byte N) | |
| // { | |
| // byte setting, startChan, endChan, targetSS; | |
| // if(N < 9){ | |
| // targetSS = BOARD_ADS; startChan = 0; endChan = 8; | |
| // }else{ | |
| // if(!daisyPresent) { return; } | |
| // targetSS = DAISY_ADS; startChan = 8; endChan = 16; | |
| // } | |
| // N = constrain(N-1,startChan,endChan-1); // 0-7 or 8-15 | |
| // SDATAC(targetSS); // exit Read Data Continuous mode to communicate with ADS | |
| // setting = 0x00; | |
| // // channelSettings[N][POWER_DOWN] = NO; // keep track of channel on/off in this array REMOVE? | |
| // setting |= channelSettings[N][GAIN_SET]; // gain | |
| // setting |= channelSettings[N][INPUT_TYPE_SET]; // input code | |
| // if(useSRB2[N] == true){channelSettings[N][SRB2_SET] = YES;}else{channelSettings[N][SRB2_SET] = NO;} | |
| // if(channelSettings[N][SRB2_SET] == YES) {bitSet(setting,3);} // close this SRB2 switch | |
| // WREG(CH1SET+(N-startChan),setting,targetSS); | |
| // // add or remove from inclusion in BIAS generation | |
| // if(useInBias[N]){channelSettings[N][BIAS_SET] = YES;}else{channelSettings[N][BIAS_SET] = NO;} | |
| // setting = RREG(BIAS_SENSP,targetSS); //get the current P bias settings | |
| // if(channelSettings[N][BIAS_SET] == YES){ | |
| // bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| // useInBias[N] = true; | |
| // }else{ | |
| // bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| // useInBias[N] = false; | |
| // } | |
| // WREG(BIAS_SENSP,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // setting = RREG(BIAS_SENSN,targetSS); //get the current N bias settings | |
| // if(channelSettings[N][BIAS_SET] == YES){ | |
| // bitSet(setting,N-startChan); //set this channel's bit to add it to the bias generation | |
| // }else{ | |
| // bitClear(setting,N-startChan); // clear this channel's bit to remove from bias generation | |
| // } | |
| // WREG(BIAS_SENSN,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // setting = 0x00; | |
| // if(targetSS == BOARD_ADS && boardUseSRB1 == true) setting = 0x20; | |
| // if(targetSS == DAISY_ADS && daisyUseSRB1 == true) setting = 0x20; | |
| // WREG(MISC1,setting,targetSS); // close all SRB1 swtiches | |
| // } | |
| ////////////////////////////////////////////// | |
| ///////////// LEAD OFF METHODS /////////////// | |
| ////////////////////////////////////////////// | |
| /** | |
| * @description Runs through the `leadOffSettings` global array to set/change | |
| * the lead off signals for all inputs of all channels. | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::leadOffSetForAllChannels(void) { | |
| // byte channelNumberUpperLimit; | |
| // // The upper limit of the channels, either 8 or 16 | |
| // channelNumberUpperLimit = daisyPresent ? OPENBCI_NUMBER_OF_CHANNELS_DAISY : OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; | |
| // // Loop through all channels | |
| // for (int i = 1; i <= channelNumberUpperLimit; i++) { | |
| // leadOffSetForChannel((byte)i,leadOffSettings[i-1][PCHAN],leadOffSettings[i-1][NCHAN]); | |
| // } | |
| // } | |
| /** | |
| * @description Used to set lead off for a channel | |
| * @param `channelNumber` - [byte] - The channel you want to change | |
| * @param `pInput` - [byte] - Apply signal to P input, either ON (1) or OFF (0) | |
| * @param `nInput` - [byte] - Apply signal to N input, either ON (1) or OFF (0) | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::leadOffSetForChannel(byte channelNumber, byte pInput, byte nInput) { | |
| // // contstrain the channel number to 0-15 | |
| // channelNumber = getConstrainedChannelNumber(channelNumber); | |
| // // Get the slave select pin for this channel | |
| // byte targetSS = getTargetSSForConstrainedChannelNumber(channelNumber); | |
| // // exit Read Data Continuous mode to communicate with ADS | |
| // SDATAC(targetSS); | |
| // delay(1); | |
| // // Read P register | |
| // byte P_setting = RREG(LOFF_SENSP,targetSS); | |
| // // Read N register | |
| // byte N_setting = RREG(LOFF_SENSN,targetSS); | |
| // // Since we are addressing 8 bit registers, we need to subtract 8 from the | |
| // // channelNumber if we are addressing the Daisy ADS | |
| // if (targetSS == DAISY_ADS) { | |
| // channelNumber -= OPENBCI_NUMBER_OF_CHANNELS_DEFAULT; | |
| // } | |
| // // If pInput is ON then we want to set, otherwise we want to clear | |
| // if (pInput == ON) { | |
| // bitSet(P_setting, channelNumber); | |
| // } else { | |
| // bitClear(P_setting, channelNumber); | |
| // } | |
| // // Write to the P register | |
| // WREG(LOFF_SENSP,P_setting,targetSS); | |
| // // If nInput is ON then we want to set, otherwise we want to clear | |
| // if (nInput == ON) { | |
| // bitSet(N_setting, channelNumber); | |
| // } else { | |
| // bitClear(N_setting, channelNumber); | |
| // } | |
| // // Write to the N register | |
| // WREG(LOFF_SENSN,N_setting,targetSS); | |
| // } | |
| /** | |
| * @description This sets the LOFF register on the Board ADS and the Daisy ADS | |
| * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal. | |
| * See `.setleadOffForSS()` for complete description | |
| * @param `freqCode` - [byte] - The frequency of the impedance signal can be either. | |
| * See `.setleadOffForSS()` for complete description | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| // void OpenBCI_32bit_Library::leadOffConfigureSignalForAll(byte amplitudeCode, byte freqCode) | |
| // { | |
| // // Set the lead off detection for the on board ADS | |
| // leadOffConfigureSignalForTargetSS(BOARD_ADS, amplitudeCode, freqCode); | |
| // // if the daisy board is present, set that register as well | |
| // if (daisyPresent) { | |
| // leadOffConfigureSignalForTargetSS(DAISY_ADS, amplitudeCode, freqCode); | |
| // } | |
| // } | |
| /** | |
| * @description This sets the LOFF (lead off) register for the given ADS with slave | |
| * select | |
| * @param `targetSS` - [byte] - The Slave Select pin. | |
| * @param `amplitudeCode` - [byte] - The amplitude of the of impedance signal. | |
| * LOFF_MAG_6NA (0b00000000) | |
| * LOFF_MAG_24NA (0b00000100) | |
| * LOFF_MAG_6UA (0b00001000) | |
| * LOFF_MAG_24UA (0b00001100) | |
| * @param `freqCode` - [byte] - The frequency of the impedance signal can be either. | |
| * LOFF_FREQ_DC (0b00000000) | |
| * LOFF_FREQ_7p8HZ (0b00000001) | |
| * LOFF_FREQ_31p2HZ (0b00000010) | |
| * LOFF_FREQ_FS_4 (0b00000011) | |
| * @author Joel/Leif/Conor (@OpenBCI) Summer 2014 | |
| */ | |
| // void OpenBCI_32bit_Library::leadOffConfigureSignalForTargetSS(byte targetSS, byte amplitudeCode, byte freqCode) { | |
| // byte setting; | |
| // amplitudeCode &= 0b00001100; //only these two bits should be used | |
| // freqCode &= 0b00000011; //only these two bits should be used | |
| // setting = RREG(LOFF,targetSS); //get the current bias settings | |
| // //reconfigure the byte to get what we want | |
| // setting &= 0b11110000; //clear out the last four bits | |
| // setting |= amplitudeCode; //set the amplitude | |
| // setting |= freqCode; //set the frequency | |
| // //send the config byte back to the hardware | |
| // WREG(LOFF,setting,targetSS); delay(1); //send the modified byte back to the ADS | |
| // } | |
| //Configure the test signals that can be inernally generated by the ADS1299 | |
| void OpenBCI_32bit_Library::configureInternalTestSignal(byte amplitudeCode, byte freqCode) | |
| { | |
| byte setting, targetSS; | |
| for(int i=0; i<2; i++){ | |
| if(i == 0){ targetSS = BOARD_ADS;} | |
| if(i == 1){ | |
| if(daisyPresent == false){ return; } | |
| targetSS = DAISY_ADS; | |
| } | |
| if (amplitudeCode == ADSTESTSIG_NOCHANGE) amplitudeCode = (RREG(CONFIG2,targetSS) & (0b00000100)); | |
| if (freqCode == ADSTESTSIG_NOCHANGE) freqCode = (RREG(CONFIG2,targetSS) & (0b00000011)); | |
| freqCode &= 0b00000011; //only the last two bits are used | |
| amplitudeCode &= 0b00000100; //only this bit is used | |
| byte setting = 0b11010000 | freqCode | amplitudeCode; //compose the code | |
| WREG(CONFIG2,setting,targetSS); delay(1); | |
| if (sniffMode && Serial1) { | |
| Serial1.print("Wrote to CONFIG2: "); | |
| Serial1.print(setting,BIN); | |
| } | |
| } | |
| } | |
| void OpenBCI_32bit_Library::changeInputType(byte inputCode){ | |
| for(int i=0; i<numChannels; i++){ | |
| channelSettings[i][INPUT_TYPE_SET] = inputCode; | |
| } | |
| // OLD CODE REVERT | |
| //channelSettingsArraySetForAll(); | |
| writeChannelSettings(); | |
| } | |
| // Start continuous data acquisition | |
| void OpenBCI_32bit_Library::startADS(void) // NEEDS ADS ADDRESS, OR BOTH? | |
| { | |
| sampleCounter = 0; | |
| firstDataPacket = true; | |
| RDATAC(BOTH_ADS); // enter Read Data Continuous mode | |
| delay(1); | |
| START(BOTH_ADS); // start the data acquisition | |
| delay(1); | |
| isRunning = true; | |
| } | |
| /** | |
| * @description Check status register to see if data is available from the ADS1299. | |
| * @returns {boolean} - `true` if data is available | |
| */ | |
| boolean OpenBCI_32bit_Library::waitForNewChannelData(void) { | |
| return !isADSDataAvailable(); | |
| } | |
| /** | |
| * @description Check status register to see if data is available from the ADS1299. | |
| * @returns {boolean} - `true` if data is available | |
| */ | |
| boolean OpenBCI_32bit_Library::isADSDataAvailable(void) { | |
| return (!(digitalRead(ADS_DRDY))); | |
| } | |
| // CALLED WHEN DRDY PIN IS ASSERTED. NEW ADS DATA AVAILABLE! | |
| void OpenBCI_32bit_Library::updateChannelData(){ | |
| // this needs to be reset, or else it will constantly flag us | |
| channelDataAvailable = false; | |
| updateBoardData(); | |
| if(daisyPresent) {updateDaisyData();} | |
| } | |
| void OpenBCI_32bit_Library::updateBoardData(){ | |
| byte inByte; | |
| int byteCounter = 0; | |
| if(daisyPresent && !firstDataPacket){ | |
| for(int i=0; i < 8; i++){ // shift and average the byte arrays | |
| lastBoardChannelDataInt[i] = boardChannelDataInt[i]; // remember the last samples | |
| } | |
| } | |
| csLow(BOARD_ADS); // open SPI | |
| for(int i=0; i<3; i++){ | |
| inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) | |
| boardStat = (boardStat << 8) | inByte; | |
| } | |
| for(int i = 0; i<8; i++){ | |
| for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks | |
| inByte = xfer(0x00); | |
| boardChannelDataRaw[byteCounter] = inByte; // raw data goes here | |
| byteCounter++; | |
| boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; // int data goes here | |
| } | |
| } | |
| csHigh(BOARD_ADS); // close SPI | |
| // need to convert 24bit to 32bit if using the filter | |
| for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment | |
| if(bitRead(boardChannelDataInt[i],23) == 1){ | |
| boardChannelDataInt[i] |= 0xFF000000; | |
| } else{ | |
| boardChannelDataInt[i] &= 0x00FFFFFF; | |
| } | |
| } | |
| if(daisyPresent && !firstDataPacket){ | |
| byteCounter = 0; | |
| for(int i=0; i<8; i++){ // take the average of this and the last sample | |
| meanBoardChannelDataInt[i] = (lastBoardChannelDataInt[i] + boardChannelDataInt[i])/2; | |
| } | |
| for(int i=0; i<8; i++){ // place the average values in the meanRaw array | |
| for(int b=2; b>=0; b--){ | |
| meanBoardDataRaw[byteCounter] = (meanBoardChannelDataInt[i] >> (b*8)) & 0xFF; | |
| byteCounter++; | |
| } | |
| } | |
| } | |
| if(firstDataPacket == true){ | |
| firstDataPacket = false; | |
| } | |
| } | |
| void OpenBCI_32bit_Library::updateDaisyData(){ | |
| byte inByte; | |
| int byteCounter = 0; | |
| if(daisyPresent && !firstDataPacket){ | |
| for(int i=0; i<8; i++){ // shift and average the byte arrays | |
| lastDaisyChannelDataInt[i] = daisyChannelDataInt[i]; // remember the last samples | |
| } | |
| } | |
| csLow(DAISY_ADS); // open SPI | |
| for(int i=0; i<3; i++){ | |
| inByte = xfer(0x00); // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) | |
| daisyStat = (daisyStat << 8) | inByte; | |
| } | |
| for(int i = 0; i<8; i++){ | |
| for(int j=0; j<3; j++){ // read 24 bits of channel data in 8 3 byte chunks | |
| inByte = xfer(0x00); | |
| daisyChannelDataRaw[byteCounter] = inByte; // raw data goes here | |
| byteCounter++; | |
| daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; // int data goes here | |
| } | |
| } | |
| csHigh(DAISY_ADS); // close SPI | |
| // need to convert 24bit to 32bit | |
| for(int i=0; i<8; i++){ // convert 3 byte 2's compliment to 4 byte 2's compliment | |
| if(bitRead(daisyChannelDataInt[i],23) == 1){ | |
| daisyChannelDataInt[i] |= 0xFF000000; | |
| }else{ | |
| daisyChannelDataInt[i] &= 0x00FFFFFF; | |
| } | |
| } | |
| if(daisyPresent && !firstDataPacket){ | |
| byteCounter = 0; | |
| for(int i=0; i<8; i++){ // average this sample with the last sample | |
| meanDaisyChannelDataInt[i] = (lastDaisyChannelDataInt[i] + daisyChannelDataInt[i])/2; | |
| } | |
| for(int i=0; i<8; i++){ // place the average values in the meanRaw array | |
| for(int b=2; b>=0; b--){ | |
| meanDaisyDataRaw[byteCounter] = (meanDaisyChannelDataInt[i] >> (b*8)) & 0xFF; | |
| byteCounter++; | |
| } | |
| } | |
| } | |
| if(firstDataPacket == true) { | |
| firstDataPacket = false; | |
| } | |
| } | |
| // Stop the continuous data acquisition | |
| void OpenBCI_32bit_Library::stopADS() | |
| { | |
| STOP(BOTH_ADS); // stop the data acquisition | |
| delay(1); | |
| SDATAC(BOTH_ADS); // stop Read Data Continuous mode to communicate with ADS | |
| delay(1); | |
| isRunning = false; | |
| } | |
| //write as binary each channel's data | |
| void OpenBCI_32bit_Library::ADS_writeChannelData() | |
| { | |
| if(daisyPresent){ | |
| if(sampleCounter % 2 != 0){ //CHECK SAMPLE ODD-EVEN AND SEND THE APPROPRIATE ADS DATA | |
| for (int i=0; i<24; i++){ | |
| Serial0.write(meanBoardDataRaw[i]); // send board data on odd samples | |
| } | |
| }else{ | |
| for (int i=0; i<24; i++){ | |
| Serial0.write(meanDaisyDataRaw[i]); // send daisy data on even samples | |
| } | |
| } | |
| }else{ | |
| for(int i=0; i<24; i++){ | |
| Serial0.write(boardChannelDataRaw[i]); | |
| } | |
| } | |
| } | |
| //print out the state of all the control registers | |
| void OpenBCI_32bit_Library::printADSregisters(int targetSS) | |
| { | |
| boolean prevverbosityState = verbosity; | |
| verbosity = true; // set up for verbosity output | |
| RREGS(0x00,0x0C,targetSS); // read out the first registers | |
| delay(10); // stall to let all that data get read by the PC | |
| RREGS(0x0D,0x17-0x0D,targetSS); // read out the rest | |
| verbosity = prevverbosityState; | |
| } | |
| byte OpenBCI_32bit_Library::ADS_getDeviceID(int targetSS) { // simple hello world com check | |
| byte data = RREG(ID_REG,targetSS); | |
| if(verbosity){ // verbosity otuput | |
| Serial0.print("On Board ADS ID "); | |
| printHex(data); Serial0.println(); | |
| sendEOT(); | |
| } | |
| return data; | |
| } | |
| //System Commands | |
| void OpenBCI_32bit_Library::WAKEUP(int targetSS) { | |
| csLow(targetSS); | |
| xfer(_WAKEUP); | |
| csHigh(targetSS); | |
| delayMicroseconds(3); //must wait 4 tCLK cycles before sending another command (Datasheet, pg. 35) | |
| } | |
| void OpenBCI_32bit_Library::STANDBY(int targetSS) { // only allowed to send WAKEUP after sending STANDBY | |
| csLow(targetSS); | |
| xfer(_STANDBY); | |
| csHigh(targetSS); | |
| } | |
| void OpenBCI_32bit_Library::RESET(int targetSS) { // reset all the registers to default settings | |
| csLow(targetSS); | |
| xfer(_RESET); | |
| delayMicroseconds(12); //must wait 18 tCLK cycles to execute this command (Datasheet, pg. 35) | |
| csHigh(targetSS); | |
| } | |
| void OpenBCI_32bit_Library::START(int targetSS) { //start data conversion | |
| csLow(targetSS); | |
| xfer(_START); // KEEP ON-BOARD AND ON-DAISY IN SYNC | |
| csHigh(targetSS); | |
| } | |
| void OpenBCI_32bit_Library::STOP(int targetSS) { //stop data conversion | |
| csLow(targetSS); | |
| xfer(_STOP); // KEEP ON-BOARD AND ON-DAISY IN SYNC | |
| csHigh(targetSS); | |
| } | |
| void OpenBCI_32bit_Library::RDATAC(int targetSS) { | |
| csLow(targetSS); | |
| xfer(_RDATAC); // read data continuous | |
| csHigh(targetSS); | |
| delayMicroseconds(3); | |
| } | |
| void OpenBCI_32bit_Library::SDATAC(int targetSS) { | |
| csLow(targetSS); | |
| xfer(_SDATAC); | |
| csHigh(targetSS); | |
| delayMicroseconds(10); //must wait at least 4 tCLK cycles after executing this command (Datasheet, pg. 37) | |
| } | |
| // THIS NEEDS CLEANING AND UPDATING TO THE NEW FORMAT | |
| void OpenBCI_32bit_Library::RDATA(int targetSS) { // use in Stop Read Continuous mode when DRDY goes low | |
| byte inByte; // to read in one sample of the channels | |
| csLow(targetSS); // open SPI | |
| xfer(_RDATA); // send the RDATA command | |
| for(int i=0; i<3; i++){ // read in the status register and new channel data | |
| inByte = xfer(0x00); | |
| boardStat = (boardStat<<8) | inByte; // read status register (1100 + LOFF_STATP + LOFF_STATN + GPIO[7:4]) | |
| } | |
| if(targetSS == BOARD_ADS){ | |
| for(int i = 0; i<8; i++){ | |
| for(int j=0; j<3; j++){ // read in the new channel data | |
| inByte = xfer(0x00); | |
| boardChannelDataInt[i] = (boardChannelDataInt[i]<<8) | inByte; | |
| } | |
| } | |
| for(int i=0; i<8; i++){ | |
| if(bitRead(boardChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment | |
| boardChannelDataInt[i] |= 0xFF000000; | |
| }else{ | |
| boardChannelDataInt[i] &= 0x00FFFFFF; | |
| } | |
| } | |
| }else{ | |
| for(int i = 0; i<8; i++){ | |
| for(int j=0; j<3; j++){ // read in the new channel data | |
| inByte = xfer(0x00); | |
| daisyChannelDataInt[i] = (daisyChannelDataInt[i]<<8) | inByte; | |
| } | |
| } | |
| for(int i=0; i<8; i++){ | |
| if(bitRead(daisyChannelDataInt[i],23) == 1){ // convert 3 byte 2's compliment to 4 byte 2's compliment | |
| daisyChannelDataInt[i] |= 0xFF000000; | |
| }else{ | |
| daisyChannelDataInt[i] &= 0x00FFFFFF; | |
| } | |
| } | |
| } | |
| csHigh(targetSS); // close SPI | |
| } | |
| byte OpenBCI_32bit_Library::RREG(byte _address,int targetSS) { // reads ONE register at _address | |
| byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address | |
| csLow(targetSS); // open SPI | |
| xfer(opcode1); // opcode1 | |
| xfer(0x00); // opcode2 | |
| regData[_address] = xfer(0x00);// update mirror location with returned byte | |
| csHigh(targetSS); // close SPI | |
| if (verbosity){ // verbosity output | |
| printRegisterName(_address); | |
| printHex(_address); | |
| Serial0.print(", "); | |
| printHex(regData[_address]); | |
| Serial0.print(", "); | |
| for(byte j = 0; j<8; j++){ | |
| Serial0.print(bitRead(regData[_address], 7-j)); | |
| if(j!=7) Serial0.print(", "); | |
| } | |
| Serial0.println(); | |
| } | |
| return regData[_address]; // return requested register value | |
| } | |
| // Read more than one register starting at _address | |
| void OpenBCI_32bit_Library::RREGS(byte _address, byte _numRegistersMinusOne, int targetSS) { | |
| byte opcode1 = _address + 0x20; // RREG expects 001rrrrr where rrrrr = _address | |
| csLow(targetSS); // open SPI | |
| xfer(opcode1); // opcode1 | |
| xfer(_numRegistersMinusOne); // opcode2 | |
| for(int i = 0; i <= _numRegistersMinusOne; i++){ | |
| regData[_address + i] = xfer(0x00); // add register byte to mirror array | |
| } | |
| csHigh(targetSS); // close SPI | |
| if(verbosity){ // verbosity output | |
| for(int i = 0; i<= _numRegistersMinusOne; i++){ | |
| printRegisterName(_address + i); | |
| printHex(_address + i); | |
| Serial0.print(", "); | |
| printHex(regData[_address + i]); | |
| Serial0.print(", "); | |
| for(int j = 0; j<8; j++){ | |
| Serial0.print(bitRead(regData[_address + i], 7-j)); | |
| if(j!=7) Serial0.print(", "); | |
| } | |
| Serial0.println(); | |
| delay(30); | |
| } | |
| } | |
| } | |
| void OpenBCI_32bit_Library::WREG(byte _address, byte _value, int target_SS) { // Write ONE register at _address | |
| byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address | |
| csLow(target_SS); // open SPI | |
| xfer(opcode1); // Send WREG command & address | |
| xfer(0x00); // Send number of registers to read -1 | |
| xfer(_value); // Write the value to the register | |
| csHigh(target_SS); // close SPI | |
| regData[_address] = _value; // update the mirror array | |
| if(verbosity){ // verbosity output | |
| Serial0.print("Register "); | |
| printHex(_address); | |
| Serial0.println(" modified."); | |
| sendEOT(); | |
| } | |
| } | |
| void OpenBCI_32bit_Library::WREGS(byte _address, byte _numRegistersMinusOne, int targetSS) { | |
| byte opcode1 = _address + 0x40; // WREG expects 010rrrrr where rrrrr = _address | |
| csLow(targetSS); // open SPI | |
| xfer(opcode1); // Send WREG command & address | |
| xfer(_numRegistersMinusOne); // Send number of registers to read -1 | |
| for (int i=_address; i <=(_address + _numRegistersMinusOne); i++){ | |
| xfer(regData[i]); // Write to the registers | |
| } | |
| csHigh(targetSS); | |
| if(verbosity){ | |
| Serial0.print("Registers "); | |
| printHex(_address); Serial0.print(" to "); | |
| printHex(_address + _numRegistersMinusOne); | |
| Serial0.println(" modified"); | |
| sendEOT(); | |
| } | |
| } | |
| // <<<<<<<<<<<<<<<<<<<<<<<<< END OF ADS1299 FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>> | |
| // ****************************************************************************** | |
| // <<<<<<<<<<<<<<<<<<<<<<<<< LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| void OpenBCI_32bit_Library::initialize_accel(byte g){ | |
| byte setting = g | 0x08; // mask the g range for REG4 | |
| pinMode(LIS3DH_DRDY,INPUT); // setup dataReady interupt from accelerometer | |
| LIS3DH_write(TMP_CFG_REG, 0x00); // DISable ADC inputs, enable temperature sensor | |
| LIS3DH_write(CTRL_REG1, 0x08); // disable accel, low power mode | |
| LIS3DH_write(CTRL_REG2, 0x00); // don't use the high pass filter | |
| LIS3DH_write(CTRL_REG3, 0x00); // no interrupts yet | |
| LIS3DH_write(CTRL_REG4, setting); // set scale to g, high resolution | |
| LIS3DH_write(CTRL_REG5, 0x00); // no boot, no fifo | |
| LIS3DH_write(CTRL_REG6, 0x00); | |
| LIS3DH_write(REFERENCE, 0x00); | |
| DRDYpinValue = lastDRDYpinValue = digitalRead(LIS3DH_DRDY); // take a reading to seed these variables | |
| } | |
| void OpenBCI_32bit_Library::enable_accel(byte Hz){ | |
| for(int i=0; i<3; i++){ | |
| axisData[i] = 0; // clear the axisData array so we don't get any stale news | |
| } | |
| byte setting = Hz | 0x07; // mask the desired frequency | |
| LIS3DH_write(CTRL_REG1, setting); // set freq and enable all axis in normal mode | |
| LIS3DH_write(CTRL_REG3, 0x10); // enable DRDY1 on INT1 (tied to PIC pin 0, LIS3DH_DRDY) | |
| } | |
| void OpenBCI_32bit_Library::disable_accel(){ | |
| LIS3DH_write(CTRL_REG1, 0x08); // power down, low power mode | |
| LIS3DH_write(CTRL_REG3, 0x00); // disable DRDY1 on INT1 | |
| } | |
| byte OpenBCI_32bit_Library::LIS3DH_getDeviceID(){ | |
| return LIS3DH_read(WHO_AM_I); | |
| } | |
| boolean OpenBCI_32bit_Library::LIS3DH_DataAvailable(){ | |
| boolean x = false; | |
| if((LIS3DH_read(STATUS_REG2) & 0x08) > 0) x = true; // read STATUS_REG | |
| return x; | |
| } | |
| boolean OpenBCI_32bit_Library::LIS3DH_DataReady(){ | |
| boolean r = false; | |
| DRDYpinValue = digitalRead(LIS3DH_DRDY); // take a look at LIS3DH_DRDY pin | |
| if(DRDYpinValue != lastDRDYpinValue){ // if the value has changed since last looking | |
| if(DRDYpinValue == HIGH){ // see if this is the rising edge | |
| r = true; // if so, there is fresh data! | |
| } | |
| lastDRDYpinValue = DRDYpinValue; // keep track of the changing pin | |
| } | |
| return r; | |
| } | |
| void OpenBCI_32bit_Library::LIS3DH_writeAxisData(void){ | |
| for(int i=0; i<3; i++){ | |
| Serial0.write(highByte(axisData[i])); // write 16 bit axis data MSB first | |
| Serial0.write(lowByte(axisData[i])); // axisData is array of type short (16bit) | |
| axisData[i] = 0; | |
| } | |
| } | |
| void OpenBCI_32bit_Library::LIS3DH_writeAxisDataForAxis(uint8_t axis) { | |
| if (axis > 2) axis = 0; | |
| Serial0.write(highByte(axisData[axis])); // write 16 bit axis data MSB first | |
| Serial0.write(lowByte(axisData[axis])); // axisData is array of type short (16bit) | |
| axisData[axis] = 0; | |
| } | |
| byte OpenBCI_32bit_Library::LIS3DH_read(byte reg){ | |
| reg |= READ_REG; // add the READ_REG bit | |
| csLow(LIS3DH_SS); // take spi | |
| spi.transfer(reg); // send reg to read | |
| byte inByte = spi.transfer(0x00); // retrieve data | |
| csHigh(LIS3DH_SS); // release spi | |
| return inByte; | |
| } | |
| void OpenBCI_32bit_Library::LIS3DH_write(byte reg, byte value){ | |
| csLow(LIS3DH_SS); // take spi | |
| spi.transfer(reg); // send reg to write | |
| spi.transfer(value); // write value | |
| csHigh(LIS3DH_SS); // release spi | |
| } | |
| int OpenBCI_32bit_Library::LIS3DH_read16(byte reg){ // use for reading axis data. | |
| int inData; | |
| reg |= READ_REG | READ_MULTI; // add the READ_REG and READ_MULTI bits | |
| csLow(LIS3DH_SS); // take spi | |
| spi.transfer(reg); // send reg to start reading from | |
| inData = spi.transfer(0x00) | (spi.transfer(0x00) << 8); // get the data and arrange it | |
| csHigh(LIS3DH_SS); // release spi | |
| return inData; | |
| } | |
| int OpenBCI_32bit_Library::getX(){ | |
| return LIS3DH_read16(OUT_X_L); | |
| } | |
| int OpenBCI_32bit_Library::getY(){ | |
| return LIS3DH_read16(OUT_Y_L); | |
| } | |
| int OpenBCI_32bit_Library::getZ(){ | |
| return LIS3DH_read16(OUT_Z_L); | |
| } | |
| void OpenBCI_32bit_Library::LIS3DH_updateAxisData(){ | |
| axisData[0] = getX(); | |
| axisData[1] = getY(); | |
| axisData[2] = getZ(); | |
| } | |
| void OpenBCI_32bit_Library::LIS3DH_readAllRegs(){ | |
| byte inByte; | |
| for (int i = STATUS_REG_AUX; i <= WHO_AM_I; i++){ | |
| inByte = LIS3DH_read(i); | |
| Serial0.print("0x0");Serial0.print(i,HEX); | |
| Serial0.print("\t");Serial0.println(inByte,HEX); | |
| delay(20); | |
| } | |
| Serial0.println(); | |
| for (int i = TMP_CFG_REG; i <= INT1_DURATION; i++){ | |
| inByte = LIS3DH_read(i); | |
| // printRegisterName(i); | |
| Serial0.print("0x");Serial0.print(i,HEX); | |
| Serial0.print("\t");Serial0.println(inByte,HEX); | |
| delay(20); | |
| } | |
| Serial0.println(); | |
| for (int i = CLICK_CFG; i <= TIME_WINDOW; i++){ | |
| inByte = LIS3DH_read(i); | |
| Serial0.print("0x");Serial0.print(i,HEX); | |
| Serial0.print("\t");Serial0.println(inByte,HEX); | |
| delay(20); | |
| } | |
| } | |
| // <<<<<<<<<<<<<<<<<<<<<<<<< END OF LIS3DH FUNCTIONS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| // String-Byte converters for ADS | |
| void OpenBCI_32bit_Library::printRegisterName(byte _address) { | |
| switch(_address){ | |
| case ID_REG: | |
| Serial0.print("ADS_ID, "); break; | |
| case CONFIG1: | |
| Serial0.print("CONFIG1, "); break; | |
| case CONFIG2: | |
| Serial0.print("CONFIG2, "); break; | |
| case CONFIG3: | |
| Serial0.print("CONFIG3, "); break; | |
| case LOFF: | |
| Serial0.print("LOFF, "); break; | |
| case CH1SET: | |
| Serial0.print("CH1SET, "); break; | |
| case CH2SET: | |
| Serial0.print("CH2SET, "); break; | |
| case CH3SET: | |
| Serial0.print("CH3SET, "); break; | |
| case CH4SET: | |
| Serial0.print("CH4SET, "); break; | |
| case CH5SET: | |
| Serial0.print("CH5SET, "); break; | |
| case CH6SET: | |
| Serial0.print("CH6SET, "); break; | |
| case CH7SET: | |
| Serial0.print("CH7SET, "); break; | |
| case CH8SET: | |
| Serial0.print("CH8SET, "); break; | |
| case BIAS_SENSP: | |
| Serial0.print("BIAS_SENSP, "); break; | |
| case BIAS_SENSN: | |
| Serial0.print("BIAS_SENSN, "); break; | |
| case LOFF_SENSP: | |
| Serial0.print("LOFF_SENSP, "); break; | |
| case LOFF_SENSN: | |
| Serial0.print("LOFF_SENSN, "); break; | |
| case LOFF_FLIP: | |
| Serial0.print("LOFF_FLIP, "); break; | |
| case LOFF_STATP: | |
| Serial0.print("LOFF_STATP, "); break; | |
| case LOFF_STATN: | |
| Serial0.print("LOFF_STATN, "); break; | |
| case GPIO: | |
| Serial0.print("GPIO, "); break; | |
| case MISC1: | |
| Serial0.print("MISC1, "); break; | |
| case MISC2: | |
| Serial0.print("MISC2, "); break; | |
| case CONFIG4: | |
| Serial0.print("CONFIG4, "); break; | |
| default: | |
| break; | |
| } | |
| } | |
| // Used for printing HEX in verbosity feedback mode | |
| void OpenBCI_32bit_Library::printHex(byte _data){ | |
| Serial0.print("0x"); | |
| if(_data < 0x10) Serial0.print("0"); | |
| Serial0.print(_data, HEX); | |
| } | |
| /** | |
| * @description Converts ascii character to byte value for channel setting bytes | |
| * @param `asciiChar` - [char] - The ascii character to convert | |
| * @return [char] - Byte number value of acsii character, defaults to 0 | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| char OpenBCI_32bit_Library::getChannelCommandForAsciiChar(char asciiChar) { | |
| switch(asciiChar){ | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_1: | |
| return 0x00; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_2: | |
| return 0x01; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_3: | |
| return 0x02; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_4: | |
| return 0x03; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_5: | |
| return 0x04; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_6: | |
| return 0x05; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_7: | |
| return 0x06; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_8: | |
| return 0x07; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_9: | |
| return 0x08; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_10: | |
| return 0x09; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_11: | |
| return 0x0A; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_12: | |
| return 0x0B; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_13: | |
| return 0x0C; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_14: | |
| return 0x0D; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_15: | |
| return 0x0E; | |
| case OPENBCI_CHANNEL_CMD_CHANNEL_16: | |
| return 0x0F; | |
| default: | |
| return 0x00; | |
| } | |
| } | |
| /** | |
| * @description Converts ascii '0' to number 0 and ascii '1' to number 1 | |
| * @param `asciiChar` - [char] - The ascii character to convert | |
| * @return [char] - Byte number value of acsii character, defaults to 0 | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| char OpenBCI_32bit_Library::getYesOrNoForAsciiChar(char asciiChar) { | |
| switch (asciiChar) { | |
| case '1': | |
| return ACTIVATE; | |
| case '0': | |
| default: | |
| return DEACTIVATE; | |
| } | |
| } | |
| /** | |
| * @description Converts ascii character to get gain from channel settings | |
| * @param `asciiChar` - [char] - The ascii character to convert | |
| * @return [char] - Byte number value of acsii character, defaults to 0 | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| char OpenBCI_32bit_Library::getGainForAsciiChar(char asciiChar) { | |
| char output = 0x00; | |
| if (asciiChar < '0' || asciiChar > '6') { | |
| asciiChar = '6'; // Default to 24 | |
| } | |
| output = asciiChar - '0'; | |
| return output << 4; | |
| } | |
| /** | |
| * @description Converts ascii character to get gain from channel settings | |
| * @param `asciiChar` - [char] - The ascii character to convert | |
| * @return [char] - Byte number value of acsii character, defaults to 0 | |
| * @author AJ Keller (@pushtheworldllc) | |
| */ | |
| char OpenBCI_32bit_Library::getNumberForAsciiChar(char asciiChar) { | |
| if (asciiChar < '0' || asciiChar > '9') { | |
| asciiChar = '0'; | |
| } | |
| // Convert ascii char to number | |
| asciiChar -= '0'; | |
| return asciiChar; | |
| } | |
| /** | |
| * @description Used to set the channelSettings array to default settings | |
| * @param `setting` - [byte] - The byte you need a setting for.... | |
| * @returns - [byte] - Retuns the proper byte for the input setting, defualts to 0 | |
| */ | |
| byte OpenBCI_32bit_Library::getDefaultChannelSettingForSetting(byte setting) { | |
| switch (setting) { | |
| case POWER_DOWN: | |
| return NO; | |
| case GAIN_SET: | |
| return ADS_GAIN24; | |
| case INPUT_TYPE_SET: | |
| return ADSINPUT_NORMAL; | |
| case BIAS_SET: | |
| return YES; | |
| case SRB2_SET: | |
| return YES; | |
| case SRB1_SET: | |
| default: | |
| return NO; | |
| } | |
| } | |
| /** | |
| * @description Used to set the channelSettings array to default settings | |
| * @param `setting` - [byte] - The byte you need a setting for.... | |
| * @returns - [char] - Retuns the proper ascii char for the input setting, defaults to '0' | |
| */ | |
| char OpenBCI_32bit_Library::getDefaultChannelSettingForSettingAscii(byte setting) { | |
| switch (setting) { | |
| case GAIN_SET: // Special case where GAIN_SET needs to be shifted first | |
| return (ADS_GAIN24 >> 4) + '0'; | |
| default: // All other settings are just adding the ascii value for '0' | |
| return getDefaultChannelSettingForSetting(setting) + '0'; | |
| } | |
| } | |
| /** | |
| * @description Convert user channelNumber for use in array indexs by subtracting 1, | |
| * also make sure N is not greater than 15 or less than 0 | |
| * @param `channelNumber` - [byte] - The channel number | |
| * @return [byte] - Constrained channel number | |
| */ | |
| char OpenBCI_32bit_Library::getConstrainedChannelNumber(byte channelNumber) { | |
| return constrain(channelNumber - 1, 0, OPENBCI_NUMBER_OF_CHANNELS_DAISY - 1); | |
| } | |
| /** | |
| * @description Get slave select pin for channelNumber | |
| * @param `channelNumber` - [byte] - The channel number | |
| * @return [byte] - Constrained channel number | |
| */ | |
| char OpenBCI_32bit_Library::getTargetSSForConstrainedChannelNumber(byte channelNumber) { | |
| // Is channelNumber in the range of default [0,7] | |
| if (channelNumber < OPENBCI_NUMBER_OF_CHANNELS_DEFAULT) { | |
| return BOARD_ADS; | |
| } else { | |
| return DAISY_ADS; | |
| } | |
| } | |
| /** | |
| * @description Used to set the channelSettings array to default settings | |
| * @param `channelSettingsArray` - [byte **] - Takes a two dimensional array of | |
| * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 6 elements | |
| */ | |
| void OpenBCI_32bit_Library::resetChannelSettingsArrayToDefault(byte channelSettingsArray[][OPENBCI_NUMBER_OF_CHANNEL_SETTINGS]) { | |
| // Loop through all channels | |
| for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) { | |
| channelSettingsArray[i][POWER_DOWN] = getDefaultChannelSettingForSetting(POWER_DOWN); // on = NO, off = YES | |
| channelSettingsArray[i][GAIN_SET] = getDefaultChannelSettingForSetting(GAIN_SET); // Gain setting | |
| channelSettingsArray[i][INPUT_TYPE_SET] = getDefaultChannelSettingForSetting(INPUT_TYPE_SET); // input muxer setting | |
| channelSettingsArray[i][BIAS_SET] = getDefaultChannelSettingForSetting(BIAS_SET); // add this channel to bias generation | |
| channelSettingsArray[i][SRB2_SET] = getDefaultChannelSettingForSetting(SRB2_SET); // connect this P side to SRB2 | |
| channelSettingsArray[i][SRB1_SET] = getDefaultChannelSettingForSetting(SRB1_SET); // don't use SRB1 | |
| useInBias[i] = true; // keeping track of Bias Generation | |
| useSRB2[i] = true; // keeping track of SRB2 inclusion | |
| } | |
| boardUseSRB1 = daisyUseSRB1 = false; | |
| } | |
| /** | |
| * @description Used to set the channelSettings array to default settings | |
| * @param `channelSettingsArray` - [byte **] - A two dimensional array of | |
| * length OPENBCI_NUMBER_OF_CHANNELS_DAISY by 2 elements | |
| */ | |
| void OpenBCI_32bit_Library::resetLeadOffArrayToDefault(byte leadOffArray[][OPENBCI_NUMBER_OF_LEAD_OFF_SETTINGS]) { | |
| // Loop through all channels | |
| for (int i = 0; i < OPENBCI_NUMBER_OF_CHANNELS_DAISY; i++) { | |
| leadOffArray[i][PCHAN] = OFF; | |
| leadOffArray[i][NCHAN] = OFF; | |
| } | |
| } | |
| OpenBCI_32bit_Library board; |