|
|
@@ -0,0 +1,233 @@ |
|
|
|
/* |
|
|
|
Copyright (C) 2013 Matt Flax <flatmax@> |
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
|
|
|
it under the terms of the GNU General Public License as published by |
|
|
|
the Free Software Foundation; either version 2 of the License, or |
|
|
|
(at your option) any later version. |
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
GNU General Public License for more details. |
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
|
|
|
along with this program; if not, write to the Free Software |
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#include "JackIIODriver.h" |
|
|
|
#include "driver_interface.h" |
|
|
|
#include "JackEngineControl.h" |
|
|
|
#include "JackGraphManager.h" |
|
|
|
|
|
|
|
#include <values.h> |
|
|
|
|
|
|
|
#define IIO_DEFAULT_CHIP "AD7476A" ///< The default IIO recording chip to look for. |
|
|
|
#define IIO_DEFAULT_READ_FS 1.e6 ///< The default IIO sample rate for the default chip. |
|
|
|
#define IIO_DEFAULT_PERIOD_SIZE 2048 ///< The default period size is in the ms range |
|
|
|
#define IIO_DEFAULT_PERIOD_COUNT 2 ///< The default number of periods |
|
|
|
#define IIO_DEFAULT_CAPUTURE_PORT_COUNT MAXINT ///< The default number of capture ports is exceedingly big, trimmed down to a realistic size in driver_initialize |
|
|
|
//#define IIO_SAFETY_FACTOR 2./3. ///< The default safety factor, allow consumption of this fraction of the available DMA buffer before we don't allow the driver to continue. |
|
|
|
#define IIO_SAFETY_FACTOR 1. ///< The default safety factor, allow consumption of this fraction of the available DMA buffer before we don't allow the driver to continue. |
|
|
|
|
|
|
|
namespace Jack { |
|
|
|
|
|
|
|
int JackIIODriver::Attach() { |
|
|
|
//cout<<"JackIIODriver::Attach\n"; |
|
|
|
JackAudioDriver::SetSampleRate((jack_nframes_t)IIO_DEFAULT_READ_FS); |
|
|
|
|
|
|
|
int ret; |
|
|
|
if ((ret=iio.enable(true))!=NO_ERROR) { // start the DMA |
|
|
|
iio.close(); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
return JackAudioDriver::Attach(); |
|
|
|
} |
|
|
|
|
|
|
|
int JackIIODriver::Detach() { |
|
|
|
//cout<<"JackIIODriver::Detach\n"; |
|
|
|
iio.enable(false); // stop the DMA |
|
|
|
return JackAudioDriver::Detach(); |
|
|
|
} |
|
|
|
|
|
|
|
int JackIIODriver::Read() { |
|
|
|
//cout<<"JackIIODriver::Read\n"; |
|
|
|
|
|
|
|
if (iio.getDeviceCnt()<1) { |
|
|
|
jack_error("JackIIODriver:: No IIO devices are present "); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
uint devChCnt=iio[0].getChCnt(); // the number of channels per device |
|
|
|
|
|
|
|
jack_nframes_t nframes=data.rows()/devChCnt; |
|
|
|
if (nframes != fEngineControl->fBufferSize) |
|
|
|
jack_error("JackIIODriver::Read warning : Jack period size = %ld IIO period size = %ld", fEngineControl->fBufferSize, nframes); |
|
|
|
|
|
|
|
// cout<<"processing buffer size : "<<fEngineControl->fBufferSize<<endl; |
|
|
|
// cout<<"processing channel count : "<<fCaptureChannels<<endl; |
|
|
|
|
|
|
|
int ret=iio.read(nframes, data); // read the data from the IIO subsystem |
|
|
|
if (ret!=NO_ERROR) |
|
|
|
return -1; |
|
|
|
|
|
|
|
|
|
|
|
// Keep begin cycle time |
|
|
|
JackDriver::CycleTakeBeginTime(); // is this necessary ? |
|
|
|
|
|
|
|
int maxAvailChCnt=data.cols()*devChCnt; |
|
|
|
jack_default_audio_sample_t scaleFactor=1./32768.; |
|
|
|
|
|
|
|
if (fCaptureChannels>maxAvailChCnt) |
|
|
|
jack_error("JackIIODriver::Read warning : Jack period size = %ld IIO period size = %ld", fEngineControl->fBufferSize, nframes); |
|
|
|
|
|
|
|
for (int i = 0; i < fCaptureChannels; i++) { |
|
|
|
int col=i/devChCnt; // find the column and offset to read from |
|
|
|
int rowOffset=i%devChCnt; |
|
|
|
if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) { |
|
|
|
jack_default_audio_sample_t *dest=GetInputBuffer(i); |
|
|
|
|
|
|
|
for (jack_nframes_t j=0; j<nframes; j++){ |
|
|
|
// dest[j]=(float)j/(float)nframes; |
|
|
|
dest[j]=(jack_default_audio_sample_t)(data(j*devChCnt+rowOffset, col))*scaleFactor; |
|
|
|
// cout<<dest[j]<<'\t'<<data(j*devChCnt+rowOffset, col)<<"\t\t"; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int JackIIODriver::Write() { |
|
|
|
// cout<<"JackIIODriver::Write\n"; |
|
|
|
JackDriver::CycleTakeEndTime(); // is this necessary ? |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
} // end namespace Jack |
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus |
|
|
|
extern "C" |
|
|
|
{ |
|
|
|
#endif |
|
|
|
|
|
|
|
SERVER_EXPORT const jack_driver_desc_t * |
|
|
|
driver_get_descriptor () { |
|
|
|
jack_driver_desc_t * desc; |
|
|
|
jack_driver_desc_filler_t filler; |
|
|
|
jack_driver_param_value_t value; |
|
|
|
|
|
|
|
desc = jack_driver_descriptor_construct("iio", JackDriverMaster, "Linux Industrial IO backend", &filler); |
|
|
|
|
|
|
|
strcpy(value.str, IIO_DEFAULT_CHIP); |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "chip", 'C', JackDriverParamString, &value, NULL, "The name of the chip to search for in the IIO devices", NULL); |
|
|
|
|
|
|
|
value.ui = IIO_DEFAULT_CAPUTURE_PORT_COUNT; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'i', JackDriverParamUInt, &value, NULL, "Provide capture count (block size).", NULL); |
|
|
|
|
|
|
|
value.ui = IIO_DEFAULT_PERIOD_SIZE; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames (samples per channel) per period", NULL); |
|
|
|
|
|
|
|
value.ui = IIO_DEFAULT_PERIOD_COUNT; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of available periods (block count)", NULL); |
|
|
|
|
|
|
|
return desc; |
|
|
|
} |
|
|
|
|
|
|
|
SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) { |
|
|
|
|
|
|
|
// As of this implementation the IIO driver is only capture... to be expanded. |
|
|
|
|
|
|
|
string chipName(IIO_DEFAULT_CHIP); // the default chip name to search for in the IIO devices. |
|
|
|
float fs = IIO_DEFAULT_READ_FS; // IIO sample rate is fixed. |
|
|
|
jack_nframes_t periodSize = IIO_DEFAULT_PERIOD_SIZE; // default block size |
|
|
|
jack_nframes_t periodCount = IIO_DEFAULT_PERIOD_COUNT; // default block count |
|
|
|
uint inChCnt = IIO_DEFAULT_CAPUTURE_PORT_COUNT; // The default number of physical input channels - a very large number, to be reduced. |
|
|
|
|
|
|
|
for (const JSList *node = params; node; node = jack_slist_next (node)) { |
|
|
|
jack_driver_param_t *param = (jack_driver_param_t *) node->data; |
|
|
|
|
|
|
|
switch (param->character) { |
|
|
|
case 'C': // we are specifying a new chip name |
|
|
|
chipName = param->value.str; |
|
|
|
break; |
|
|
|
case 'i': // we are specifying the number of capture channels |
|
|
|
inChCnt = param->value.ui; |
|
|
|
break; |
|
|
|
case 'p': |
|
|
|
periodSize = param->value.ui; |
|
|
|
break; |
|
|
|
case 'n': |
|
|
|
periodCount = param->value.ui; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// create the driver which contains the IIO class |
|
|
|
Jack::JackIIODriver* iio_driver = new Jack::JackIIODriver("system", "iio_pcm", engine, table); |
|
|
|
if (!iio_driver) { |
|
|
|
jack_error("\nHave you run out of memory ? I tried to create the IIO driver in memory but failed!\n"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
// interrogate the available iio devices searching for the chip name |
|
|
|
if (iio_driver->iio.findDevicesByChipName(chipName)!=NO_ERROR) { // find all devices with a particular chip which are present. |
|
|
|
jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str()); |
|
|
|
delete iio_driver; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
if (iio_driver->iio.getDeviceCnt()<1) { // If there are no devices found by that chip name, then indicate. |
|
|
|
jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str()); |
|
|
|
delete iio_driver; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
iio_driver->iio.printInfo(); // print out detail about the devices which were found ... |
|
|
|
|
|
|
|
// if the available number of ports is less then the requested number, then restrict to the number of physical ports. |
|
|
|
if (iio_driver->iio.getChCnt()<inChCnt) |
|
|
|
inChCnt=iio_driver->iio.getChCnt(); |
|
|
|
|
|
|
|
// resize the data buffer column count to match the device count |
|
|
|
int colCnt=(int)ceil((float)inChCnt/(float)iio_driver->iio[0].getChCnt()); // check whether we require less then the available number of channels |
|
|
|
int ret=iio_driver->iio.getReadArray(periodSize, iio_driver->data); // resize the array to be able to read enough memory |
|
|
|
if (ret!=NO_ERROR) { |
|
|
|
jack_error("iio::getReadArray couldn't create the data buffer, indicating the problem."); |
|
|
|
delete iio_driver; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
if (iio_driver->data.cols()>colCnt) // resize the data columns to match the specified number of columns (channels / channels per device) |
|
|
|
iio_driver->data.resize(iio_driver->data.rows(), colCnt); |
|
|
|
|
|
|
|
ret=iio_driver->iio.open(periodCount, periodSize); // try to open all IIO devices |
|
|
|
if (ret!=NO_ERROR) |
|
|
|
delete iio_driver; |
|
|
|
return NULL; |
|
|
|
|
|
|
|
Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(iio_driver); |
|
|
|
if (threaded_driver) { |
|
|
|
bool capture=true, playback=false, monitor=false; |
|
|
|
int outChCnt=0; |
|
|
|
jack_nframes_t inputLatency = periodSize*periodCount, outputLatency=0; |
|
|
|
// Special open for OSS driver... |
|
|
|
if (iio_driver->Open(periodSize, periodCount, capture, playback, inChCnt, outChCnt, monitor, "iio:device", "iio:device", inputLatency, outputLatency)!=0) { |
|
|
|
delete threaded_driver; |
|
|
|
threaded_driver=NULL; |
|
|
|
} |
|
|
|
} else |
|
|
|
jack_error("\nHave you run out of memory ? I tried to create Jack's standard threaded driver in memory but failed! The good news is that you had enough memory to create the IIO driver.\n"); |
|
|
|
|
|
|
|
if (!threaded_driver) { // handle the case that the threaded_driver was not created succ. |
|
|
|
delete iio_driver; |
|
|
|
iio_driver=NULL; |
|
|
|
} |
|
|
|
|
|
|
|
return threaded_driver; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef __cplusplus |
|
|
|
} |
|
|
|
#endif |