root/trunk/libffado/tests/test-scs.cpp

Revision 1595, 16.8 kB (checked in by ppalmers, 13 years ago)

disable running status for SCS

Line 
1 /*
2  * Copyright (C) 2005-2009 by Pieter Palmers
3  * Copyright (C) 2005-2008 by Daniel Wagner
4  *
5  * This file is part of FFADO
6  * FFADO = Free Firewire (pro-)audio drivers for linux
7  *
8  * FFADO is based upon FreeBoB
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) version 3 of the License.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  */
24
25 #include <libraw1394/raw1394.h>
26 #include <libiec61883/iec61883.h>
27
28 #include "debugmodule/debugmodule.h"
29
30 #include "devicemanager.h"
31
32 #include "libieee1394/configrom.h"
33 #include "libieee1394/ieee1394service.h"
34 #include "libutil/Configuration.h"
35 #include "libutil/SystemTimeSource.h"
36
37 #include "genericavc/stanton/scs.h"
38 using namespace GenericAVC;
39 using namespace GenericAVC::Stanton;
40
41 #include <argp.h>
42 #include <iostream>
43 #include <cstdlib>
44 #include <cstring>
45 #include <string>
46
47 #include <signal.h>
48
49 #include <alsa/asoundlib.h>
50 #define ALSA_SEQ_BUFF_SIZE 32
51 #define MIDI_TRANSMIT_BUFFER_SIZE 512
52
53 using namespace std;
54 using namespace Util;
55
56 DECLARE_GLOBAL_DEBUG_MODULE;
57
58 #define MAX_ARGS 1000
59
60 int run;
61 snd_seq_t *m_seq_handle = NULL;
62
63 static void sighandler(int sig)
64 {
65     run = 0;
66
67     // send an event to wake the iterator loop
68     if(m_seq_handle) {
69         snd_seq_nonblock(m_seq_handle, 1);
70     }
71 }
72
73 ////////////////////////////////////////////////
74 // arg parsing
75 ////////////////////////////////////////////////
76 const char *argp_program_version = "test-scs 0.1";
77 const char *argp_program_bug_address = "<ffado-devel@lists.sf.net>";
78 static char doc[] = "test-avccmd -- test program to test the Stanton SCS code.";
79 static char args_doc[] = "NODE_ID";
80 static struct argp_option options[] = {
81     {"verbose",   'v', "LEVEL",     0,  "Produce verbose output" },
82     {"port",      'p', "PORT",      0,  "Set port" },
83     {"node",      'n', "NODE",      0,  "Set node" },
84    { 0 }
85 };
86
87 struct arguments
88 {
89     arguments()
90         : nargs ( 0 )
91         , verbose( DEBUG_LEVEL_NORMAL )
92         , test( false )
93         , port( -1 )
94         , node( -1 )
95         {
96             args[0] = 0;
97         }
98
99     char* args[MAX_ARGS];
100     int   nargs;
101     int  verbose;
102     bool  test;
103     int   port;
104     int   node;
105 } arguments;
106
107 // Parse a single option.
108 static error_t
109 parse_opt( int key, char* arg, struct argp_state* state )
110 {
111     // Get the input argument from `argp_parse', which we
112     // know is a pointer to our arguments structure.
113     struct arguments* arguments = ( struct arguments* ) state->input;
114
115     char* tail;
116     errno = 0;
117     switch (key) {
118     case 'v':
119         arguments->verbose = strtol(arg, &tail, 0);
120         break;
121     case 't':
122         arguments->test = true;
123         break;
124     case 'p':
125         arguments->port = strtol(arg, &tail, 0);
126         if (errno) {
127             perror("argument parsing failed:");
128             return errno;
129         }
130         break;
131     case 'n':
132         arguments->node = strtol(arg, &tail, 0);
133         if (errno) {
134             perror("argument parsing failed:");
135             return errno;
136         }
137         break;
138     case ARGP_KEY_ARG:
139         if (state->arg_num >= MAX_ARGS) {
140             // Too many arguments.
141             argp_usage (state);
142         }
143         arguments->args[state->arg_num] = arg;
144         arguments->nargs++;
145         break;
146     case ARGP_KEY_END:
147         if(arguments->nargs<0) {
148             printf("not enough arguments\n");
149             return -1;
150         }
151        
152         break;
153     default:
154         return ARGP_ERR_UNKNOWN;
155     }
156     return 0;
157 }
158
159 static struct argp argp = { options, parse_opt, args_doc, doc };
160
161 class HSS1394AlsaSeqMidiBridge {
162     class HSS1394UserDataHandler;
163
164 public:
165     HSS1394AlsaSeqMidiBridge(snd_seq_t *seq_handle, GenericAVC::Stanton::ScsDevice &device)
166     : m_seq_handle (seq_handle)
167     , m_device( device )
168     , m_name( "UNSPECIFIED" )
169     , m_out_port_nr( -1 )
170     , m_out_parser( NULL )
171     , m_input_handler( NULL )
172     {};
173
174     virtual ~HSS1394AlsaSeqMidiBridge() {
175         if(m_input_handler) {
176             // remove the handler
177             if(!m_device.m_hss1394handler->removeMessageHandler(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_input_handler)) {
178                 debugError("Could not register input message handler\n");
179             }
180             delete m_input_handler;
181             m_input_handler = NULL;
182         }
183         if(m_out_port_nr >= 0) {
184             snd_seq_delete_simple_port(m_seq_handle, m_out_port_nr);
185             m_out_port_nr = -1;
186         }
187         if(m_out_parser) {
188             snd_midi_event_free(m_out_parser);
189             m_out_parser = NULL;
190         }
191     };
192
193     bool init() {
194         // need local copy as the nickname can change
195         m_name = m_device.getNickname();
196
197         // create the output port
198         m_out_port_nr = snd_seq_create_simple_port(m_seq_handle, m_name.c_str(),
199                             SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
200                             SND_SEQ_PORT_TYPE_MIDI_GENERIC);
201         if(m_out_port_nr < 0) {
202             debugError("Could not create ALSA Sequencer port\n");
203             return false;
204         }
205
206         // create the output message encoder
207         if(snd_midi_event_new( ALSA_SEQ_BUFF_SIZE, &m_out_parser) < 0) {
208             debugError("could not init output event encoder");
209             return false;
210         }
211
212         // disable running-status
213        snd_midi_event_no_status(m_out_parser, 1);
214
215         // create a handler
216         HSS1394UserDataHandler *m_input_handler = new HSS1394UserDataHandler(*this);
217         if(m_input_handler == NULL) {
218             debugError("Error creating handler.");
219             return false;
220         }
221         if(!m_input_handler->init(m_name)) {
222             debugError("Could not init input message handler\n");
223             return false;
224         }
225         if(!m_device.m_hss1394handler->addMessageHandler(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_input_handler)) {
226             debugError("Could not register input message handler\n");
227             return false;
228         }
229         return true;
230     };
231
232     bool sendAlsaSeqEvent(snd_seq_event_t *ev) {
233         int bytes_to_send = 0;
234
235         // decode it to the work buffer
236         if((bytes_to_send = snd_midi_event_decode ( m_out_parser,
237                 m_work_buffer,
238                 MIDI_TRANSMIT_BUFFER_SIZE,
239                 ev)) < 0) { // failed to decode
240                 debugError(" Error decoding event for port %d (errcode=%d)", ev->dest.port, bytes_to_send);
241                 return false;
242         } else {
243             if(!m_device.writeHSS1394Message(GenericAVC::Stanton::ScsDevice::eMT_UserData,
244                                                     m_work_buffer, bytes_to_send)) {
245                 debugError("Failed to send message\n");
246                 return false;
247             }
248         }
249         return true;
250     };
251
252     int getAlsaSeqOutputPortNumber() {
253         return m_out_port_nr;
254     }
255     int getAlsaSeqInputPortNumber() {
256         if (m_input_handler) {
257             return m_input_handler->getAlsaSeqPortNumber();
258         } else {
259             debugError("input handler not initialized yet");
260             return -1;
261         }
262     }
263
264     void setVerboseLevel(int i) {
265         setDebugLevel(i);
266     };
267
268 private:
269     snd_seq_t *m_seq_handle;
270     GenericAVC::Stanton::ScsDevice &m_device;
271     std::string m_name;
272     int m_out_port_nr;
273     snd_midi_event_t *m_out_parser;
274
275     HSS1394UserDataHandler *m_input_handler;
276
277     unsigned char m_work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
278
279     DECLARE_DEBUG_MODULE;
280
281 private: // the class that handles the async messages from the HSS1394 node
282     class HSS1394UserDataHandler : public GenericAVC::Stanton::ScsDevice::HSS1394Handler::MessageFunctor {
283     public:
284         HSS1394UserDataHandler(HSS1394AlsaSeqMidiBridge &parent)
285         : m_parent( parent )
286         , m_ready(false)
287         , m_seq_port_nr( -1 )
288         , m_parser( NULL )
289         , m_debugModule(parent.m_debugModule)
290         {};
291    
292         virtual ~HSS1394UserDataHandler() {
293             if(m_seq_port_nr >= 0) {
294                 snd_seq_delete_simple_port(m_parent.m_seq_handle, m_seq_port_nr);
295                 m_seq_port_nr = -1;
296             }
297             if(m_parser) {
298                 snd_midi_event_free(m_parser);
299                 m_parser = NULL;
300             }
301             m_ready = false;
302         }
303    
304         bool init(std::string name) {
305             m_seq_port_nr = snd_seq_create_simple_port(m_parent.m_seq_handle, name.c_str(),
306                                 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
307                                 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
308             if(m_seq_port_nr < 0) {
309                 debugError("Could not create ALSA Sequencer port\n");
310                 return false;
311             }
312    
313             if(snd_midi_event_new( ALSA_SEQ_BUFF_SIZE, &m_parser) < 0) {
314                 debugError("could not init parser");
315                 return false;
316             }
317             m_ready = true;
318             return m_ready;
319         }
320
321         int getAlsaSeqPortNumber() {
322             return m_seq_port_nr;
323         }
324
325         virtual void operator() (byte_t *buff, size_t len) {
326             if (m_ready) {
327                 debugOutput(DEBUG_LEVEL_NORMAL, "got message len %d\n", len);
328    
329                 for (size_t s=0; s < len; s++) {
330                     byte_t *byte = (buff+s);
331                     snd_seq_event_t ev;
332                     if ((snd_midi_event_encode_byte(m_parser, (*byte) & 0xFF, &ev)) > 0) {
333                             // a midi message is complete, send it out to ALSA
334                             snd_seq_ev_set_subs(&ev);
335                             snd_seq_ev_set_direct(&ev);
336                             snd_seq_ev_set_source(&ev, m_seq_port_nr);
337                             snd_seq_event_output_direct(m_parent.m_seq_handle, &ev);
338                     }
339                 }
340             } else {
341                 debugError("Not ready\n");
342             }
343         };
344     private:
345         HSS1394AlsaSeqMidiBridge &m_parent;
346         bool m_ready;
347         int m_seq_port_nr;
348         snd_midi_event_t *m_parser;
349         DECLARE_DEBUG_MODULE_REFERENCE;
350     };
351 };
352 IMPL_DEBUG_MODULE( HSS1394AlsaSeqMidiBridge, HSS1394AlsaSeqMidiBridge, DEBUG_LEVEL_NORMAL );
353
354 ///////////////////////////
355 // main
356 //////////////////////////
357 int
358 main(int argc, char **argv)
359 {
360     // arg parsing
361     if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
362         printMessage("Could not parse command line\n" );
363         exit(-1);
364     }
365     errno = 0;
366
367     run=1;
368
369     signal (SIGINT, sighandler);
370     signal (SIGPIPE, sighandler);
371
372     DeviceManager *m_deviceManager = new DeviceManager();
373     if ( !m_deviceManager ) {
374         printMessage("Could not allocate device manager\n" );
375         return -1;
376     }
377
378     if ( arguments.verbose ) {
379         setDebugLevel(arguments.verbose);
380         m_deviceManager->setVerboseLevel(arguments.verbose);
381     }
382
383     if ( !m_deviceManager->initialize() ) {
384         printMessage("Could not initialize device manager\n" );
385         delete m_deviceManager;
386         return -1;
387     }
388
389     char s[1024];
390     if(arguments.port > -1 && arguments.node > -1) {
391         snprintf(s, 1024, "hw:%d,%d", arguments.port, arguments.node);
392         if ( !m_deviceManager->addSpecString(s) ) {
393             printMessage("Could not add spec string %s to device manager\n", s );
394             delete m_deviceManager;
395             return -1;
396         }
397     } else if (arguments.port > -1) {
398         snprintf(s, 1024, "hw:%d", arguments.port);
399         if ( !m_deviceManager->addSpecString(s) ) {
400             printMessage("Could not add spec string %s to device manager\n", s );
401             delete m_deviceManager;
402             return -1;
403         }
404     }
405
406     if ( !m_deviceManager->discover(false) ) {
407         printMessage("Could not discover devices\n" );
408         delete m_deviceManager;
409         return -1;
410     }
411
412     // loop over all discovered devices and extract the SCS devices
413     int nb_devices = m_deviceManager->getAvDeviceCount();
414     if(nb_devices == 0) {
415         printMessage("No devices found\n");
416         delete m_deviceManager;
417         return -1;
418     }
419
420     typedef std::vector<ScsDevice*> ScsDeviceVector;
421     typedef std::vector<ScsDevice*>::iterator ScsDeviceVectorIterator;
422
423     ScsDeviceVector scsDevices;
424     for(int i=0; i<nb_devices; i++) {
425         FFADODevice *device = m_deviceManager->getAvDeviceByIndex(i);
426         GenericAVC::Stanton::ScsDevice* scsDevice = dynamic_cast<GenericAVC::Stanton::ScsDevice*>(device);
427         if(scsDevice == NULL) {
428             printMessage("Device %d (GUID: %s) is not a Stanton SCS device\n", i, device->getConfigRom().getGuidString().c_str() );
429         } else {
430             printMessage("Device %d (GUID: %s) is a Stanton SCS device\n", i, device->getConfigRom().getGuidString().c_str() );
431             scsDevices.push_back(scsDevice);
432         }
433     }
434
435     if(scsDevices.size() == 0) {
436         printMessage("No SCS devices found\n");
437         delete m_deviceManager;
438         return -1;
439     }
440
441     // open the alsa sequencer
442     if (snd_seq_open(&m_seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
443         debugError("Error opening ALSA sequencer.");
444         delete m_deviceManager;
445         return -1;
446     }
447
448     snd_seq_set_client_name(m_seq_handle, "SCS MIDI");
449
450     // this maps the alsa sequencer ports to the corresponding bridges
451     typedef std::map<int, HSS1394AlsaSeqMidiBridge*> BridgeMap;
452     typedef std::map<int, HSS1394AlsaSeqMidiBridge*>::iterator BridgeMapIterator;
453     BridgeMap seqport2bridgemap;
454
455     for ( ScsDeviceVectorIterator it = scsDevices.begin();
456           it != scsDevices.end();
457           ++it )
458     {
459         HSS1394AlsaSeqMidiBridge *bridge = new HSS1394AlsaSeqMidiBridge(m_seq_handle, **it);
460         if(bridge == NULL) {
461             debugError("Could not allocate HSS1394 <=> ALSA bridge\n");
462             delete m_deviceManager;
463             return -1;
464         }
465         bridge->setVerboseLevel(arguments.verbose);
466         if(!bridge->init()) {
467             debugError("Could not init HSS1394 <=> ALSA bridge\n");
468             delete m_deviceManager;
469             return -1;
470         }
471         int portNumber = bridge->getAlsaSeqOutputPortNumber();
472         #ifdef DEBUG
473         if(portNumber < -1) {
474             debugError("BUG: port should be >= 0 after init\n");
475         }
476         #endif
477
478         BridgeMapIterator it = seqport2bridgemap.find(portNumber);
479         if(it == seqport2bridgemap.end()) {
480             seqport2bridgemap[portNumber] = bridge;
481         } else {
482             debugError("BUG: port already present in bridge map, duplicate port.\n");
483             delete bridge;
484         }
485     }
486
487     // enter a wait loop
488     printMessage(" >>> Entering wait loop, use CTRL-C to exit... \n" );
489     while(run) {
490         snd_seq_event_t *ev;
491         int err = 0;
492
493         // get next event, if one is present, blocks until an event is received
494         err = snd_seq_event_input(m_seq_handle, &ev);
495         if(err > 0 && ev) {
496             debugOutput(DEBUG_LEVEL_VERBOSE, "Got event...\n");
497             if (ev->source.client == SND_SEQ_CLIENT_SYSTEM)
498                     continue;
499
500             // figure out what bridge this is intended for
501             BridgeMapIterator it = seqport2bridgemap.find(ev->dest.port);
502             if(it != seqport2bridgemap.end()) {
503                 HSS1394AlsaSeqMidiBridge *bridge = (*it).second;
504                 if(bridge) {
505                     if(!bridge->sendAlsaSeqEvent(ev)) {
506                         debugError("Failed to send event to HSS1394 node\n");
507                     }
508                 } else {
509                     debugError("Bogus bridge in seqport2bridgemap\n");
510                 }
511             } else {
512                 debugWarning("Received message for unknown port\n");
513             }
514
515         } else {
516             switch(err) {
517                 case -EAGAIN:
518                     debugOutput(DEBUG_LEVEL_VERBOSE, "no events in ALSA-SEQ FIFO\n");
519                     break;
520                 case -ENOSPC:
521                     debugWarning("ALSA-SEQ FIFO overrun, events dropped!\n");
522                     break;
523                 default:
524                     debugError("Failed to receive ALSA-SEQ event (%d)\n", err);
525             }
526         }
527     }
528     printMessage(" <<< Exit wait loop... \n" );
529
530     // cleanup
531     for ( BridgeMapIterator it = seqport2bridgemap.begin();
532           it != seqport2bridgemap.end();
533           ++it )
534     {
535         HSS1394AlsaSeqMidiBridge *bridge = (*it).second;
536         delete bridge;
537     }
538     seqport2bridgemap.clear();
539
540     snd_seq_close(m_seq_handle);
541     delete m_deviceManager;
542
543     printMessage("Bye... \n" );
544     return 0;
545 }
546
Note: See TracBrowser for help on using the browser.