diff --git a/Builds/Linux/build/savedState.xml b/Builds/Linux/build/savedState.xml index 67d53f51f7f79e6a754f3ed04b0b08e5c1603ad2..7d087eb0cf0d65e37923f34cf23e79a5bbada203 100644 --- a/Builds/Linux/build/savedState.xml +++ b/Builds/Linux/build/savedState.xml @@ -2,7 +2,7 @@ <PROCESSORGRAPH> <SIGNALCHAIN> - <PROCESSOR name="Sources/Signal Generator" insertionPoint="0"/> + <PROCESSOR name="Sources/Intan Demo Board" insertionPoint="0"/> <PROCESSOR name="Sinks/LFP Viewer" insertionPoint="1"/> </SIGNALCHAIN> </PROCESSORGRAPH> diff --git a/Builds/Linux/build/windowState.xml b/Builds/Linux/build/windowState.xml index 8361e5dcf43dc519c5b344e8819ec4e9a275c5d2..38dad57e4e40f3f0460d946e2ad333503f29dc2c 100644 --- a/Builds/Linux/build/windowState.xml +++ b/Builds/Linux/build/windowState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <MAINWINDOW> - <BOUNDS x="1723" y="79" w="1113" h="793" fullscreen="0"/> + <BOUNDS x="1729" y="52" w="1161" h="968" fullscreen="0"/> </MAINWINDOW> diff --git a/Source/Processors/DataThreads/DataThread.cpp b/Source/Processors/DataThreads/DataThread.cpp index 69cd98626ba43b4966c57250b4dcb3646b55934b..0f31a883ee7c209c62380c56187af9463d7cd02c 100644 --- a/Source/Processors/DataThreads/DataThread.cpp +++ b/Source/Processors/DataThreads/DataThread.cpp @@ -21,7 +21,8 @@ void DataThread::run() { const MessageManagerLock mml (Thread::getCurrentThread()); if (! mml.lockWasGained()) return; - updateBuffer(); + if (!updateBuffer()) + signalThreadShouldExit(); } } @@ -29,3 +30,4 @@ DataBuffer* DataThread::getBufferAddress() { return dataBuffer; } + diff --git a/Source/Processors/DataThreads/DataThread.h b/Source/Processors/DataThreads/DataThread.h index 5393cc9bed8fe83a8f90d5c9a7904eac674d8957..33d1975730aa30cae168ab12475098bf975dc7eb 100644 --- a/Source/Processors/DataThreads/DataThread.h +++ b/Source/Processors/DataThreads/DataThread.h @@ -27,11 +27,15 @@ public: DataBuffer* getBufferAddress(); - virtual void updateBuffer() = 0; + virtual bool updateBuffer() = 0; DataBuffer* dataBuffer; - virtual bool threadStarted() {return true;} + virtual bool foundInputSource() = 0; + virtual bool startAcquisition() = 0; + virtual bool stopAcquisition() = 0; + virtual int getNumChannels() = 0; + virtual float getSampleRate() = 0; }; diff --git a/Source/Processors/DataThreads/FPGAThread.cpp b/Source/Processors/DataThreads/FPGAThread.cpp index 7e1b9e45bee8da1d8d78da2b418e138fd49b6487..59b5b18ffeb066669c211e28acbfd4788cb1c6e2 100644 --- a/Source/Processors/DataThreads/FPGAThread.cpp +++ b/Source/Processors/DataThreads/FPGAThread.cpp @@ -63,7 +63,7 @@ FPGAThread::~FPGAThread() { } -void FPGAThread::updateBuffer() { +bool FPGAThread::updateBuffer() { dev->ReadFromPipeOut(0xA0, sizeof(pBuffer), pBuffer); @@ -101,6 +101,8 @@ void FPGAThread::updateBuffer() { } j++; // keep scanning for timecodes } + + return true; } diff --git a/Source/Processors/DataThreads/FPGAThread.h b/Source/Processors/DataThreads/FPGAThread.h index 7dcb7182e28fb68413987b316c5b4fb96ea490e6..bf68110a5e4089c45316596ce7a0f9dc87d50c3f 100644 --- a/Source/Processors/DataThreads/FPGAThread.h +++ b/Source/Processors/DataThreads/FPGAThread.h @@ -28,6 +28,12 @@ class FPGAThread : public DataThread public: FPGAThread(); ~FPGAThread(); + + bool foundInputSource() {return true;} + bool startAcquisition() {return true;} + bool stopAcquisition() {return true;} + int getNumChannels() {return 32;} + float getSampleRate() {return 25000.0;} private: @@ -49,7 +55,7 @@ private: int numchannels; int Ndatabytes; - void updateBuffer(); + bool updateBuffer(); bool initializeFPGA(okCFrontPanel*, char*); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FPGAThread); diff --git a/Source/Processors/DataThreads/FileReaderThread.cpp b/Source/Processors/DataThreads/FileReaderThread.cpp index e1e75a8ffa906a144f3c923fd1ac8c9acd7e24e6..905793497af84bab6c9799a13bc9aa9bed57886a 100644 --- a/Source/Processors/DataThreads/FileReaderThread.cpp +++ b/Source/Processors/DataThreads/FileReaderThread.cpp @@ -24,23 +24,29 @@ FileReaderThread::FileReaderThread() : DataThread(), std::cout << "File Reader Thread initialized." << std::endl; - startThread(); } FileReaderThread::~FileReaderThread() { - stopThread(500); + deleteAndZero(input); - std::cout << "File reader received disable signal." << std::endl; + deleteAndZero(dataBuffer); - deleteAndZero(input); +} + +bool FileReaderThread::startAcquisition() +{ + startThread(); - delete dataBuffer; - dataBuffer = 0; } +bool FileReaderThread::stopAcquisition() +{ + stopThread(500); + std::cout << "File reader received disable signal." << std::endl; +} -void FileReaderThread::updateBuffer() +bool FileReaderThread::updateBuffer() { while (dataBuffer->getNumSamples() < 4096) @@ -59,4 +65,5 @@ void FileReaderThread::updateBuffer() } + return true; } diff --git a/Source/Processors/DataThreads/FileReaderThread.h b/Source/Processors/DataThreads/FileReaderThread.h index bf4309fb548dee20a5e342496597b853203c7d49..d98afa06ac0918ba2d0100eaea199788b23b42bc 100644 --- a/Source/Processors/DataThreads/FileReaderThread.h +++ b/Source/Processors/DataThreads/FileReaderThread.h @@ -23,6 +23,12 @@ class FileReaderThread : public DataThread public: FileReaderThread(); ~FileReaderThread(); + + bool foundInputSource() {return true;} + bool startAcquisition(); + bool stopAcquisition(); + int getNumChannels() {return 16;} + float getSampleRate() {return 40000.0;} private: @@ -34,7 +40,7 @@ private: float thisSample[16]; - void updateBuffer(); + bool updateBuffer(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileReaderThread); }; diff --git a/Source/Processors/DataThreads/IntanThread.cpp b/Source/Processors/DataThreads/IntanThread.cpp index 71d5cb8840775700a1dbeecf0bf70d2786be646d..607b4fe092a1b1b3e56b1207b7477f0dec586894 100644 --- a/Source/Processors/DataThreads/IntanThread.cpp +++ b/Source/Processors/DataThreads/IntanThread.cpp @@ -23,45 +23,80 @@ IntanThread::IntanThread() : DataThread(), dataBuffer = new DataBuffer(16,4096); - if (initializeUSB()) - { - std::cout << "FTDI interface initialized." << std::endl; - ftdi_write_data(&ftdic, &startCode, 1); - startThread(); - isTransmitting = true; - } - - + deviceFound = initializeUSB(true); + } -IntanThread::~IntanThread() { +IntanThread::~IntanThread() +{ + closeUSB(); + deleteAndZero(dataBuffer); +} - stopThread(500); +int IntanThread::getNumChannels() +{ + return 16; +} - if (isTransmitting) { - ftdi_write_data(&ftdic, &stopCode, 1); - unsigned char buf[4097]; // has to be bigger than the on-chip buffer - ftdi_read_data(&ftdic, buf, sizeof(buf)); +float IntanThread::getSampleRate() +{ + return 25000.0; +} - ftdi_usb_close(&ftdic); - ftdi_deinit(&ftdic); - std::cout << "FTDI interface destroyed." << std::endl; - } +bool IntanThread::foundInputSource() +{ + if (deviceFound) + { + int return_value; + // try to update the baud rate + if ((return_value = ftdi_set_baudrate(&ftdic, baudrate)) < 0) + { + deviceFound = false; + return false; + } + } else { + // try to initialize USB + if (!initializeUSB(false)) + { + return false; + } else { + deviceFound = true; + } + } - deleteAndZero(dataBuffer); + return true; + +} + +bool IntanThread::startAcquisition() +{ + ftdi_write_data(&ftdic, &startCode, 1); + startThread(); } -bool IntanThread::initializeUSB() +bool IntanThread::stopAcquisition() +{ + stopThread(500); + + ftdi_write_data(&ftdic, &stopCode, 1); + unsigned char buf[4097]; // has to be bigger than the on-chip buffer + ftdi_read_data(&ftdic, buf, sizeof(buf)); +} + + +bool IntanThread::initializeUSB(bool verbose) { int return_value; // Step 1: initialise the ftdi_context: if (ftdi_init(&ftdic) < 0) {// -1 = couldn't allocate read buffer // -2 = couldn't allocate struct buffer - fprintf(stderr, "ftdi_init failed\n"); + if (verbose) + fprintf(stderr, "ftdi_init failed\n"); return false; } else { - std::cout << "FTDI context initialized." << std::endl; + if (verbose) + std::cout << "FTDI context initialized." << std::endl; } // Step 2: open USB device @@ -69,7 +104,8 @@ bool IntanThread::initializeUSB() // -8 = wrong permissions if ((return_value = ftdi_usb_open(&ftdic, vendorID, productID)) < 0) { - fprintf(stderr, "unable to open FTDI device: %d (%s)\n", + if (verbose) + fprintf(stderr, "unable to open FTDI device: %d (%s)\n", return_value, ftdi_get_error_string(&ftdic)); return false; @@ -80,7 +116,8 @@ bool IntanThread::initializeUSB() // Step 3: set the baud rate if ((return_value = ftdi_set_baudrate(&ftdic, baudrate)) < 0) { - fprintf(stderr, "unable to set baud rate: %d (%s)\n", + if (verbose) + fprintf(stderr, "unable to set baud rate: %d (%s)\n", return_value, ftdi_get_error_string(&ftdic)); return false; @@ -88,19 +125,33 @@ bool IntanThread::initializeUSB() std::cout << "Baud rate set to 115200" << std::endl; } - - return true; } +bool IntanThread::closeUSB() +{ + ftdi_usb_close(&ftdic); + ftdi_deinit(&ftdic); + std::cout << "FTDI interface destroyed." << std::endl; +} + -void IntanThread::updateBuffer() +bool IntanThread::updateBuffer() { - // Step 1: update buffer - ftdi_read_data(&ftdic, buffer, sizeof(buffer)); + int bytes_read; + // Step 1: update buffer + // error codes: + // -666: USB device unavailable + // <0 : error code from libusb_bulk_transfer() + // 0 : no data available + // >0 : number of bytes read + if ((bytes_read = ftdi_read_data(&ftdic, buffer, sizeof(buffer))) < 0) + { + return false; + } // Step 2: sort data int TTLval, channelVal; @@ -117,7 +168,6 @@ void IntanThread::updateBuffer() } - TTLval = (buffer[index+2] & 4) >> 2; // extract TTL value (bit 3) channelVal = buffer[index+2] & 60; // extract channel value @@ -127,5 +177,8 @@ void IntanThread::updateBuffer() } } + + return true; + } diff --git a/Source/Processors/DataThreads/IntanThread.h b/Source/Processors/DataThreads/IntanThread.h index 14a8c16e070edc17769f54df6477fd8a266ef180..557e08d957173166c10863a865469127672b520a 100644 --- a/Source/Processors/DataThreads/IntanThread.h +++ b/Source/Processors/DataThreads/IntanThread.h @@ -23,7 +23,9 @@ public: IntanThread(); ~IntanThread(); - bool threadStarted() {return isTransmitting;} + bool foundInputSource(); + int getNumChannels(); + float getSampleRate(); private: @@ -31,18 +33,22 @@ private: int vendorID, productID; int baudrate; bool isTransmitting; + bool deviceFound; - bool initializeUSB(); + bool initializeUSB(bool); + bool closeUSB(); + + bool startAcquisition(); + bool stopAcquisition(); unsigned char startCode, stopCode; unsigned char buffer[240]; // should be 5 samples per channel float thisSample[16]; - //float thisSample[64]; int ch; - void updateBuffer(); + bool updateBuffer(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IntanThread); }; diff --git a/Source/Processors/DataThreads/NetworkThread.cpp b/Source/Processors/DataThreads/NetworkThread.cpp index 1591ad729016aead818fca40d18a147069032b21..25a1e7a4288cf423e0949e29401c1142543d5058 100644 --- a/Source/Processors/DataThreads/NetworkThread.cpp +++ b/Source/Processors/DataThreads/NetworkThread.cpp @@ -38,7 +38,7 @@ NetworkThread::~NetworkThread() { } -void NetworkThread::updateBuffer(){ +bool NetworkThread::updateBuffer(){ NetCom::rxWave (my_netcomdat, &lfp); @@ -48,4 +48,6 @@ void NetworkThread::updateBuffer(){ } dataBuffer->addToBuffer(thisSample,1); } + + return true; } \ No newline at end of file diff --git a/Source/Processors/DataThreads/NetworkThread.h b/Source/Processors/DataThreads/NetworkThread.h index 838e03ae01a30dce797c0428886a5a9194535f3a..65ab10c5c0138926c68cead4c93b05b0754fb400 100644 --- a/Source/Processors/DataThreads/NetworkThread.h +++ b/Source/Processors/DataThreads/NetworkThread.h @@ -28,6 +28,12 @@ public: NetworkThread(); ~NetworkThread(); + bool foundInputSource() {return true;} + bool startAcquisition() {return true;} + bool stopAcquisition() {return true;} + int getNumChannels() {return 16;} + float getSampleRate() {return 40000.0;} + private: NetCom my_netcom; @@ -39,7 +45,7 @@ private: float thisSample[8]; - void updateBuffer(); + bool updateBuffer(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NetworkThread); diff --git a/Source/Processors/Editors/GenericEditor.cpp b/Source/Processors/Editors/GenericEditor.cpp index fa21f87a93dc3e8a92117522160b8ee7958c246f..3db1e69996f7c753302675162e31f0a9ca14fdbc 100644 --- a/Source/Processors/Editors/GenericEditor.cpp +++ b/Source/Processors/Editors/GenericEditor.cpp @@ -107,14 +107,16 @@ void GenericEditor::disable() bool GenericEditor::getEnabledState() { - return isEnabled; + GenericProcessor* p = (GenericProcessor*) getProcessor(); + return p->enabledState(); } void GenericEditor::setEnabledState(bool t) { - isEnabled = t; + GenericProcessor* p = (GenericProcessor*) getProcessor(); - p->enabledState(isEnabled); + p->enabledState(t); + isEnabled = p->enabledState(); } void GenericEditor::paint (Graphics& g) diff --git a/Source/Processors/GenericProcessor.h b/Source/Processors/GenericProcessor.h index 158eef84a1218c9388748b9358175a0e29ffe88f..cf0f787cc18e6fff0f2eb33589f07de796608ea3 100644 --- a/Source/Processors/GenericProcessor.h +++ b/Source/Processors/GenericProcessor.h @@ -133,8 +133,8 @@ public: virtual bool enable() {return true;} virtual bool disable() {return true;} - bool enabledState() {return isEnabled;} - void enabledState(bool t) {isEnabled = t;} + virtual bool enabledState() {return isEnabled;} + virtual void enabledState(bool t) {isEnabled = t;} virtual AudioSampleBuffer* getContinuousBuffer() {return 0;} virtual MidiBuffer* getEventBuffer() {return 0;} @@ -155,13 +155,15 @@ public: void checkForMidiEvents(MidiBuffer& mb); void addMidiEvent(MidiBuffer& mb, int a); + bool isEnabled; + private: void processBlock (AudioSampleBuffer &buffer, MidiBuffer &midiMessages); - bool isEnabled; + int getNumSamples(MidiBuffer&); void setNumSamples(MidiBuffer&, int); diff --git a/Source/Processors/SourceNode.cpp b/Source/Processors/SourceNode.cpp index 67ca7a1b0f07d0ea35f3445225e350eb046eede4..7b81329da15958d1f5888c3030b0668e9a2580e3 100644 --- a/Source/Processors/SourceNode.cpp +++ b/Source/Processors/SourceNode.cpp @@ -15,50 +15,71 @@ SourceNode::SourceNode(const String& name_) : GenericProcessor(name_), - dataThread(0) + dataThread(0), + sourceCheckInterval(1500) { if (getName().equalsIgnoreCase("Intan Demo Board")) { - setNumOutputs(16); - setNumInputs(0); + dataThread = new IntanThread(); } else if (getName().equalsIgnoreCase("Custom FPGA")) { - setNumOutputs(32); - setNumInputs(0); + dataThread = new FPGAThread(); } else if (getName().equalsIgnoreCase("File Reader")) { - setNumOutputs(16); - setNumInputs(0); + dataThread = new FileReaderThread(); + } + + setNumInputs(0); + + if (dataThread != 0) { + setNumOutputs(dataThread->getNumChannels()); + inputBuffer = dataThread->getBufferAddress(); + } else { + setNumOutputs(10); } setPlayConfigDetails(getNumInputs(), getNumOutputs(), 44100.0, 128); - //sendActionMessage("Intan Demo Board source created."); - //sendMessage("Intan Demo Board source created."); + if (dataThread != 0) + { + if (!dataThread->foundInputSource()) + { + enabledState(false); + } + } else { + enabledState(false); + } + + // check for input source every two seconds + startTimer(sourceCheckInterval); } SourceNode::~SourceNode() { + if (dataThread != 0) + deleteAndZero(dataThread); + config->removeDataSource(this); } float SourceNode::getSampleRate() { - if (getName().equalsIgnoreCase("Intan Demo Board")) { - return 25000.0; - } else if (getName().equalsIgnoreCase("Custom FPGA")) { - return 25000.0; - } else if (getName().equalsIgnoreCase("File Reader")) { - return 40000.0; - } else { - return 44100.0; - } + if (dataThread != 0) + return dataThread->getSampleRate(); + else + return 44100.0; } -// void SourceNode::setName(const String name_) -// { -// name = name_; +void SourceNode::enabledState(bool t) +{ + if (t && !dataThread->foundInputSource()) + { + isEnabled = false; + } else { + isEnabled = t; + } -// // Source node type determines configuration info + +} void SourceNode::setConfiguration(Configuration* cf) { @@ -114,57 +135,78 @@ AudioProcessorEditor* SourceNode::createEditor() //return 0; } -// void SourceNode::setSourceNode(GenericProcessor* sn) -// { -// sourceNode = 0; -// } - -// void SourceNode::setDestNode(GenericProcessor* dn) -// { -// destNode = dn; -// if (dn != 0) -// dn->setSourceNode(this); -// } - -//void SourceNode::createEditor() { - -//} +void SourceNode::timerCallback() +{ + if (dataThread->foundInputSource() && !isEnabled) + { + std::cout << "Input source found." << std::endl; + //stopTimer(); // check for input source every two seconds + enabledState(true); + GenericEditor* ed = (GenericEditor*) getEditor(); + viewport->updateVisibleEditors(ed, 4); + } else if (!dataThread->foundInputSource() && isEnabled) { + std::cout << "No input source found." << std::endl; + enabledState(false); + GenericEditor* ed = (GenericEditor*) getEditor(); + viewport->updateVisibleEditors(ed, 4); + } +} bool SourceNode::enable() { std::cout << "Source node received enable signal" << std::endl; - bool return_code = true; + if (dataThread != 0) + { + if (dataThread->foundInputSource()) + { + dataThread->startAcquisition(); + return true; + } else { + return false; + } + } else { + return false; + } - if (getName().equalsIgnoreCase("Intan Demo Board")) { + stopTimer(); + + // bool return_code = true; + + // if (getName().equalsIgnoreCase("Intan Demo Board")) { - dataThread = new IntanThread(); - inputBuffer = dataThread->getBufferAddress(); - return_code = dataThread->threadStarted(); + // dataThread = new IntanThread(); + // inputBuffer = dataThread->getBufferAddress(); + // return_code = dataThread->threadStarted(); - if (!return_code) - deleteAndZero(dataThread); + // if (!return_code) + // deleteAndZero(dataThread); - } else if (getName().equalsIgnoreCase("Custom FPGA")) { - dataThread = new FPGAThread(); - inputBuffer = dataThread->getBufferAddress(); - } else if (getName().equalsIgnoreCase("File Reader")) { - dataThread = new FileReaderThread(); - inputBuffer = dataThread->getBufferAddress(); - } + // } else if (getName().equalsIgnoreCase("Custom FPGA")) { + // dataThread = new FPGAThread(); + // inputBuffer = dataThread->getBufferAddress(); + // } else if (getName().equalsIgnoreCase("File Reader")) { + // dataThread = new FileReaderThread(); + // inputBuffer = dataThread->getBufferAddress(); + // } - return return_code; + // return return_code; } bool SourceNode::disable() { - + std::cout << "Source node received disable signal" << std::endl; - if (dataThread != 0) { - delete dataThread; - dataThread = 0; - } + if (dataThread != 0) + dataThread->stopAcquisition(); + + startTimer(2000); + + // if (dataThread != 0) { + // delete dataThread; + // dataThread = 0; + // } return true; } diff --git a/Source/Processors/SourceNode.h b/Source/Processors/SourceNode.h index 89f0f7227fa3525531614a1fbae851913f013192..40cad49f459c397d4ab743e7a34af33c5c27cda4 100644 --- a/Source/Processors/SourceNode.h +++ b/Source/Processors/SourceNode.h @@ -20,7 +20,8 @@ #include "DataThreads/FileReaderThread.h" #include "GenericProcessor.h" -class SourceNode : public GenericProcessor +class SourceNode : public GenericProcessor, + public Timer { public: @@ -29,6 +30,8 @@ public: SourceNode(const String& name); ~SourceNode(); + void enabledState(bool t); + //void setName(const String name_); void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock); @@ -54,7 +57,10 @@ public: private: + int sourceCheckInterval; + //const String name; + void timerCallback(); DataThread* dataThread; DataBuffer* inputBuffer;