1 /*
2 Copyright (C) 2013 Matt Flax <flatmax@flatmax.org>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include "JackIIODriver.h"
21 #include "driver_interface.h"
22 #include "JackEngineControl.h"
23 #include "JackGraphManager.h"
24 
25 #include <values.h>
26 
27 #define IIO_DEFAULT_CHIP "AD7476A" ///< The default IIO recording chip to look for.
28 #define IIO_DEFAULT_READ_FS 1.e6 ///< The default IIO sample rate for the default chip.
29 #define IIO_DEFAULT_PERIOD_SIZE 2048 ///< The default period size is in the ms range
30 #define IIO_DEFAULT_PERIOD_COUNT 2 ///< The default number of periods
31 #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
32 //#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.
33 #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.
34 
35 namespace Jack {
36 
Open(jack_nframes_t buffer_size,jack_nframes_t samplerate,bool capturing,bool playing,int inchannels,int outchannels,bool monitor,const char * capture_driver_name,const char * playback_driver_name,jack_nframes_t capture_latency,jack_nframes_t playback_latency)37 int JackIIODriver::Open(jack_nframes_t buffer_size, jack_nframes_t samplerate, bool capturing, bool playing, int inchannels, int outchannels, bool monitor, const char* capture_driver_name, const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency) {
38     //cout<<"JackIIODriver::Open\n";
39 
40     int ret=JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
41     if (ret!=NO_ERROR) // check whether the JackAudioDriver opened OK
42         return ret;
43     ret=iio.enable(true); // start the DMA
44     return ret;
45 }
46 
Close()47 int JackIIODriver::Close() {
48     //cout<<"JackIIODriver::Close\n";
49     iio.enable(false); // stop the DMA
50     return JackAudioDriver::Close();
51 }
52 
Read()53 int JackIIODriver::Read() {
54     //cout<<"JackIIODriver::Read\n";
55 
56     if (iio.getDeviceCnt()<1) {
57         jack_error("JackIIODriver:: No IIO devices are present ");
58         return -1;
59     }
60     uint devChCnt=iio[0].getChCnt(); // the number of channels per device
61 
62     jack_nframes_t nframes=data.rows()/devChCnt;
63 
64     // This is left here for future debugging.
65     //    if (nframes != fEngineControl->fBufferSize)
66     //        jack_error("JackIIODriver::Read warning : Jack period size = %ld IIO period size = %ld", fEngineControl->fBufferSize, nframes);
67     //    cout<<"processing buffer size : "<<fEngineControl->fBufferSize<<endl;
68     //    cout<<"processing channel count : "<<fCaptureChannels<<endl;
69 
70     int ret=iio.read(nframes, data); // read the data from the IIO subsystem
71     if (ret!=NO_ERROR)
72         return -1;
73 
74 
75     // Keep begin cycle time
76     JackDriver::CycleTakeBeginTime(); // is this necessary ?
77 
78     jack_default_audio_sample_t scaleFactor=1./32768.;
79 
80     // This is left in for future debugging.
81     //int maxAvailChCnt=data.cols()*devChCnt;
82     //    if (fCaptureChannels>maxAvailChCnt)
83     //        jack_error("JackIIODriver::Read warning : Jack capture ch. cnt = %ld IIO capture ch. cnt = %ld", fCaptureChannels, maxAvailChCnt);
84 
85     for (int i = 0; i < fCaptureChannels; i++) {
86         int col=i/devChCnt; // find the column and offset to read from
87         int rowOffset=i%devChCnt;
88         if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
89             jack_default_audio_sample_t *dest=GetInputBuffer(i);
90 
91             for (jack_nframes_t j=0; j<nframes; j++)
92                 dest[j]=(jack_default_audio_sample_t)(data(j*devChCnt+rowOffset, col))*scaleFactor;
93         }
94     }
95 
96     return 0;
97 }
98 
Write()99 int JackIIODriver::Write() {
100     //        cout<<"JackIIODriver::Write\n";
101     JackDriver::CycleTakeEndTime(); // is this necessary ?
102     return 0;
103 }
104 
105 } // end namespace Jack
106 
107 
108 #ifdef __cplusplus
109 extern "C"
110 {
111 #endif
112 
113 SERVER_EXPORT const jack_driver_desc_t *
driver_get_descriptor()114 driver_get_descriptor () {
115     jack_driver_desc_t * desc;
116     jack_driver_desc_filler_t filler;
117     jack_driver_param_value_t value;
118 
119     desc = jack_driver_descriptor_construct("iio", JackDriverMaster, "Linux Industrial IO backend", &filler);
120 
121     strcpy(value.str, IIO_DEFAULT_CHIP);
122     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);
123 
124     value.ui = IIO_DEFAULT_CAPUTURE_PORT_COUNT;
125     jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'i', JackDriverParamUInt, &value, NULL, "Provide capture count (block size).", NULL);
126 
127     value.ui = IIO_DEFAULT_PERIOD_SIZE;
128     jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames (samples per channel) per period", NULL);
129 
130     value.ui = IIO_DEFAULT_PERIOD_COUNT;
131     jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of available periods (block count)", NULL);
132 
133     return desc;
134 }
135 
driver_initialize(Jack::JackLockedEngine * engine,Jack::JackSynchro * table,const JSList * params)136 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) {
137 
138     // As of this implementation the IIO driver is only capture... to be expanded.
139     int ret, colCnt;
140     Jack::JackDriverClientInterface* threaded_driver=NULL;
141 
142     string chipName(IIO_DEFAULT_CHIP); // the default chip name to search for in the IIO devices.
143     float fs = IIO_DEFAULT_READ_FS; // IIO sample rate is fixed.
144     jack_nframes_t periodSize = IIO_DEFAULT_PERIOD_SIZE; // default block size
145     jack_nframes_t periodCount = IIO_DEFAULT_PERIOD_COUNT; // default block count
146     uint inChCnt = IIO_DEFAULT_CAPUTURE_PORT_COUNT; // The default number of physical input channels - a very large number, to be reduced.
147 
148     for (const JSList *node = params; node; node = jack_slist_next (node)) {
149         jack_driver_param_t *param = (jack_driver_param_t *) node->data;
150 
151         switch (param->character) {
152         case 'C': // we are specifying a new chip name
153             chipName = param->value.str;
154             break;
155         case 'i': // we are specifying the number of capture channels
156             inChCnt = param->value.ui;
157             break;
158         case 'p':
159             periodSize = param->value.ui;
160             break;
161         case 'n':
162             periodCount = param->value.ui;
163             break;
164         }
165     }
166 
167     // create the driver which contains the IIO class
168     Jack::JackIIODriver* iio_driver = new Jack::JackIIODriver("system", "iio_pcm", engine, table);
169     if (!iio_driver) {
170         jack_error("\nHave you run out of memory ? I tried to create the IIO driver in memory but failed!\n");
171         return NULL;
172     }
173 
174     // interrogate the available iio devices searching for the chip name
175     if (iio_driver->iio.findDevicesByChipName(chipName)!=NO_ERROR) { // find all devices with a particular chip which are present.
176         jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str());
177         goto initError;
178     }
179 
180     if (iio_driver->iio.getDeviceCnt()<1) { // If there are no devices found by that chip name, then indicate.
181         jack_error("\nThe iio driver found no devices by the name %s\n", chipName.c_str());
182         goto initError;
183     }
184 
185     iio_driver->iio.printInfo(); // print out detail about the devices which were found ...
186 
187     // if the available number of ports is less then the requested number, then restrict to the number of physical ports.
188     if (iio_driver->iio.getChCnt()<inChCnt)
189         inChCnt=iio_driver->iio.getChCnt();
190 
191     // resize the data buffer column count to match the device count
192     colCnt=(int)ceil((float)inChCnt/(float)iio_driver->iio[0].getChCnt()); // check whether we require less then the available number of channels
193     ret=iio_driver->iio.getReadArray(periodSize, iio_driver->data); // resize the array to be able to read enough memory
194     if (ret!=NO_ERROR) {
195         jack_error("iio::getReadArray couldn't create the data buffer, indicating the problem.");
196         goto initError;
197     }
198     if (iio_driver->data.cols()>colCnt) // resize the data columns to match the specified number of columns (channels / channels per device)
199         iio_driver->data.resize(iio_driver->data.rows(), colCnt);
200 
201     ret=iio_driver->iio.open(periodCount, periodSize); // try to open all IIO devices
202     if (ret!=NO_ERROR)
203         goto initError;
204 
205     threaded_driver = new Jack::JackThreadedDriver(iio_driver);
206     if (threaded_driver) {
207         bool capture=true, playback=false, monitor=false;
208         int outChCnt=0;
209         jack_nframes_t inputLatency = periodSize*periodCount, outputLatency=0;
210         // Special open for OSS driver...
211         if (iio_driver->Open(periodSize, (jack_nframes_t)fs, capture, playback, inChCnt, outChCnt, monitor, "iio:device", "iio:device", inputLatency, outputLatency)!=0) {
212             delete threaded_driver;
213             delete iio_driver;
214             return NULL;
215         }
216     } else
217         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");
218 
219     return threaded_driver;
220 
221 initError: // error during initialisation, delete and return NULL
222         delete iio_driver;
223         return NULL;
224 }
225 
226 #ifdef __cplusplus
227 }
228 #endif
229