[BeBoB/MAudio] Add PreSonus::FireboxDevice class to support functionality to switch...
[ffado.git] / libffado / tests / test-scs.cpp
blob73b05f493a057526862e7df79acdbeaa283de861
1 /*
2 * Copyright (C) 2005-2009 by Pieter Palmers
3 * Copyright (C) 2005-2008 by Daniel Wagner
5 * sysex-buffering: Copyright (C) 2012 by Rob Bothof
7 * This file is part of FFADO
8 * FFADO = Free Firewire (pro-)audio drivers for linux
10 * FFADO is based upon FreeBoB
12 * This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 2 of the License, or
15 * (at your option) version 3 of the License.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <libraw1394/raw1394.h>
28 #include <libiec61883/iec61883.h>
30 #include "debugmodule/debugmodule.h"
32 #include "devicemanager.h"
34 #include "libieee1394/configrom.h"
35 #include "libieee1394/ieee1394service.h"
36 #include "libutil/Configuration.h"
37 #include "libutil/SystemTimeSource.h"
39 #include "genericavc/stanton/scs.h"
40 using namespace GenericAVC;
41 using namespace GenericAVC::Stanton;
43 #include <argp.h>
44 #include <iostream>
45 #include <cstdlib>
46 #include <cstring>
47 #include <string>
49 #include <signal.h>
51 #include <alsa/asoundlib.h>
52 #define ALSA_SEQ_BUFF_SIZE 32
53 #define MIDI_TRANSMIT_BUFFER_SIZE 512
55 using namespace std;
56 using namespace Util;
58 DECLARE_GLOBAL_DEBUG_MODULE;
60 #define MAX_ARGS 1000
62 int run;
63 snd_seq_t *m_seq_handle = NULL;
65 static void sighandler(int sig)
67 run = 0;
69 // send an event to wake the iterator loop
70 if(m_seq_handle) {
71 snd_seq_nonblock(m_seq_handle, 1);
75 ////////////////////////////////////////////////
76 // arg parsing
77 ////////////////////////////////////////////////
78 const char *argp_program_version = "test-scs 0.1";
79 const char *argp_program_bug_address = "<ffado-devel@lists.sf.net>";
80 static char doc[] = "test-scs -- test program to test the Stanton SCS code.";
81 static char args_doc[] = "NODE_ID";
82 static struct argp_option options[] = {
83 {"verbose", 'v', "LEVEL", 0, "Produce verbose output" },
84 {"port", 'p', "PORT", 0, "Set port" },
85 {"node", 'n', "NODE", 0, "Set node" },
86 {"sysexbuf", 's', "1", 0, "Enable Sysex Buffering of 1byte messages" },
87 { 0 }
90 struct arguments
92 arguments()
93 : nargs ( 0 )
94 , verbose( DEBUG_LEVEL_NORMAL )
95 , test( false )
96 , port( -1 )
97 , node( -1 )
98 , sysexbuf ( 0 )
100 args[0] = 0;
103 char* args[MAX_ARGS];
104 int nargs;
105 int verbose;
106 bool test;
107 int port;
108 int node;
109 int sysexbuf;
110 } arguments;
112 // Parse a single option.
113 static error_t
114 parse_opt( int key, char* arg, struct argp_state* state )
116 // Get the input argument from `argp_parse', which we
117 // know is a pointer to our arguments structure.
118 struct arguments* arguments = ( struct arguments* ) state->input;
120 char* tail;
121 errno = 0;
122 switch (key) {
123 case 'v':
124 arguments->verbose = strtol(arg, &tail, 0);
125 break;
126 case 't':
127 arguments->test = true;
128 break;
129 case 'p':
130 arguments->port = strtol(arg, &tail, 0);
131 if (errno) {
132 perror("argument parsing failed:");
133 return errno;
135 break;
136 case 'n':
137 arguments->node = strtol(arg, &tail, 0);
138 if (errno) {
139 perror("argument parsing failed:");
140 return errno;
142 break;
143 case 's':
144 arguments->sysexbuf = strtol(arg, &tail, 0);
145 break;
146 case ARGP_KEY_ARG:
147 if (state->arg_num >= MAX_ARGS) {
148 // Too many arguments.
149 argp_usage (state);
151 arguments->args[state->arg_num] = arg;
152 arguments->nargs++;
153 break;
154 case ARGP_KEY_END:
155 if(arguments->nargs<0) {
156 printf("not enough arguments\n");
157 return -1;
160 break;
161 default:
162 return ARGP_ERR_UNKNOWN;
164 return 0;
167 static struct argp argp = { options, parse_opt, args_doc, doc };
169 class HSS1394AlsaSeqMidiBridge {
170 class HSS1394UserDataHandler;
172 public:
173 HSS1394AlsaSeqMidiBridge(snd_seq_t *seq_handle, GenericAVC::Stanton::ScsDevice &device)
174 : m_seq_handle (seq_handle)
175 , m_device( device )
176 , m_name( "UNSPECIFIED" )
177 , m_out_port_nr( -1 )
178 , m_out_parser( NULL )
179 , m_input_handler( NULL )
182 virtual ~HSS1394AlsaSeqMidiBridge() {
183 if(m_input_handler) {
184 // remove the handler
185 if(!m_device.m_hss1394handler->removeMessageHandler(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_input_handler)) {
186 debugError("Could not register input message handler\n");
188 delete m_input_handler;
189 m_input_handler = NULL;
191 if(m_out_port_nr >= 0) {
192 snd_seq_delete_simple_port(m_seq_handle, m_out_port_nr);
193 m_out_port_nr = -1;
195 if(m_out_parser) {
196 snd_midi_event_free(m_out_parser);
197 m_out_parser = NULL;
201 bool init() {
202 // need local copy as the nickname can change
203 m_name = m_device.getNickname();
204 //m_name="SCS-plug";
206 // create the output port
207 m_out_port_nr = snd_seq_create_simple_port(m_seq_handle, m_name.c_str(),
208 SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE,
209 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
210 if(m_out_port_nr < 0) {
211 debugError("Could not create ALSA Sequencer port\n");
212 return false;
215 // create the output message encoder
216 if(snd_midi_event_new( ALSA_SEQ_BUFF_SIZE, &m_out_parser) < 0) {
217 debugError("could not init output event encoder");
218 return false;
221 // disable running-status
222 snd_midi_event_no_status(m_out_parser, 1);
224 // create a handler
225 HSS1394UserDataHandler *m_input_handler = new HSS1394UserDataHandler(*this);
226 if(m_input_handler == NULL) {
227 debugError("Error creating handler.");
228 return false;
230 if(!m_input_handler->init(m_name)) {
231 debugError("Could not init input message handler\n");
232 return false;
234 if(!m_device.m_hss1394handler->addMessageHandler(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_input_handler)) {
235 debugError("Could not register input message handler\n");
236 return false;
238 return true;
241 bool sendAlsaSeqEvent(snd_seq_event_t *ev) {
242 int bytes_to_send = 0;
244 // decode it to the work buffer
245 if((bytes_to_send = snd_midi_event_decode ( m_out_parser,
246 m_work_buffer,
247 MIDI_TRANSMIT_BUFFER_SIZE,
248 ev)) < 0) { // failed to decode
249 debugError(" Error decoding event for port %d (errcode=%d)", ev->dest.port, bytes_to_send);
250 return false;
251 } else {
252 if (bytes_to_send == 1 && arguments.sysexbuf==1) {
253 switch(m_work_buffer[0]) {
254 case 0xF0:
255 sysex_buffer_count=1;
256 m_sysex_buffer[sysex_buffer_count-1]=m_work_buffer[0];
257 debugOutput(DEBUG_LEVEL_VERBOSE, "Sysexstart-Buffering\n");
258 break;
259 case 0xf7:
260 sysex_buffer_count++;
261 m_sysex_buffer[sysex_buffer_count-1]=m_work_buffer[0];
262 debugOutput(DEBUG_LEVEL_VERBOSE,"SysexEnd-SendBuffer...length: %d\n",sysex_buffer_count);
263 if(!m_device.writeHSS1394Message(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_sysex_buffer, sysex_buffer_count+1)) {
264 debugError("Failed to send message\n");
265 return false;
267 sysex_buffer_count=0;
268 break;
269 case 0xF9:
270 case 0xFA:
271 case 0xFB:
272 case 0xFC:
273 case 0xFD:
274 case 0xFE:
275 case 0xFF:
276 debugOutput(DEBUG_LEVEL_VERBOSE,"Clock or other 1byte message received, send without buffering\n");
277 if(!m_device.writeHSS1394Message(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_work_buffer,bytes_to_send )) {
278 debugError("Failed to send message\n");
279 return false;
281 break;
282 default:
283 if (sysex_buffer_count > 0) { //yes we are buffering
284 sysex_buffer_count++;
285 m_sysex_buffer[sysex_buffer_count-1]=m_work_buffer[0];
288 } else
289 if(!m_device.writeHSS1394Message(GenericAVC::Stanton::ScsDevice::eMT_UserData, m_work_buffer,bytes_to_send )) {
290 debugError("Failed to send message\n");
291 return false;
294 return true;
297 int getAlsaSeqOutputPortNumber() {
298 return m_out_port_nr;
300 int getAlsaSeqInputPortNumber() {
301 if (m_input_handler) {
302 return m_input_handler->getAlsaSeqPortNumber();
303 } else {
304 debugError("input handler not initialized yet");
305 return -1;
309 void setVerboseLevel(int i) {
310 setDebugLevel(i);
313 private:
314 snd_seq_t *m_seq_handle;
315 GenericAVC::Stanton::ScsDevice &m_device;
316 std::string m_name;
317 int m_out_port_nr;
318 snd_midi_event_t *m_out_parser;
320 HSS1394UserDataHandler *m_input_handler;
322 unsigned char m_work_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
323 unsigned char m_sysex_buffer[MIDI_TRANSMIT_BUFFER_SIZE];
324 int sysex_buffer_count;
326 DECLARE_DEBUG_MODULE;
328 private: // the class that handles the async messages from the HSS1394 node
329 class HSS1394UserDataHandler : public GenericAVC::Stanton::ScsDevice::HSS1394Handler::MessageFunctor {
330 public:
331 HSS1394UserDataHandler(HSS1394AlsaSeqMidiBridge &parent)
332 : m_parent( parent )
333 , m_ready(false)
334 , m_seq_port_nr( -1 )
335 , m_parser( NULL )
336 , m_debugModule(parent.m_debugModule)
339 virtual ~HSS1394UserDataHandler() {
340 if(m_seq_port_nr >= 0) {
341 snd_seq_delete_simple_port(m_parent.m_seq_handle, m_seq_port_nr);
342 m_seq_port_nr = -1;
344 if(m_parser) {
345 snd_midi_event_free(m_parser);
346 m_parser = NULL;
348 m_ready = false;
351 bool init(std::string name) {
352 m_seq_port_nr = snd_seq_create_simple_port(m_parent.m_seq_handle, name.c_str(),
353 SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ,
354 SND_SEQ_PORT_TYPE_MIDI_GENERIC);
355 if(m_seq_port_nr < 0) {
356 debugError("Could not create ALSA Sequencer port\n");
357 return false;
360 if(snd_midi_event_new( ALSA_SEQ_BUFF_SIZE, &m_parser) < 0) {
361 debugError("could not init parser");
362 return false;
364 m_ready = true;
365 return m_ready;
368 int getAlsaSeqPortNumber() {
369 return m_seq_port_nr;
372 virtual void operator() (byte_t *buff, size_t len) {
373 if (m_ready) {
374 debugOutput(DEBUG_LEVEL_VERBOSE,
375 "got message len %zd\n",
376 len);
378 for (size_t s=0; s < len; s++) {
379 byte_t *byte = (buff+s);
380 snd_seq_event_t ev;
381 if ((snd_midi_event_encode_byte(m_parser, (*byte) & 0xFF, &ev)) > 0) {
382 // a midi message is complete, send it out to ALSA
383 snd_seq_ev_set_subs(&ev);
384 snd_seq_ev_set_direct(&ev);
385 snd_seq_ev_set_source(&ev, m_seq_port_nr);
386 snd_seq_event_output_direct(m_parent.m_seq_handle, &ev);
389 } else {
390 debugError("Not ready\n");
393 private:
394 HSS1394AlsaSeqMidiBridge &m_parent;
395 bool m_ready;
396 int m_seq_port_nr;
397 snd_midi_event_t *m_parser;
398 DECLARE_DEBUG_MODULE_REFERENCE;
401 IMPL_DEBUG_MODULE( HSS1394AlsaSeqMidiBridge, HSS1394AlsaSeqMidiBridge, DEBUG_LEVEL_NORMAL );
403 ///////////////////////////
404 // main
405 //////////////////////////
407 main(int argc, char **argv)
409 // arg parsing
410 if ( argp_parse ( &argp, argc, argv, 0, 0, &arguments ) ) {
411 printMessage("Could not parse command line\n" );
412 exit(-1);
414 errno = 0;
416 run=1;
418 signal (SIGINT, sighandler);
419 signal (SIGPIPE, sighandler);
421 DeviceManager *m_deviceManager = new DeviceManager();
422 if ( !m_deviceManager ) {
423 printMessage("Could not allocate device manager\n" );
424 return -1;
427 if ( arguments.verbose ) {
428 setDebugLevel(arguments.verbose);
429 m_deviceManager->setVerboseLevel(arguments.verbose);
432 if ( !m_deviceManager->initialize() ) {
433 printMessage("Could not initialize device manager\n" );
434 delete m_deviceManager;
435 return -1;
438 char s[1024];
439 if(arguments.port > -1 && arguments.node > -1) {
440 snprintf(s, 1024, "hw:%d,%d", arguments.port, arguments.node);
441 if ( !m_deviceManager->addSpecString(s) ) {
442 printMessage("Could not add spec string %s to device manager\n", s );
443 delete m_deviceManager;
444 return -1;
446 } else if (arguments.port > -1) {
447 snprintf(s, 1024, "hw:%d", arguments.port);
448 if ( !m_deviceManager->addSpecString(s) ) {
449 printMessage("Could not add spec string %s to device manager\n", s );
450 delete m_deviceManager;
451 return -1;
455 if ( !m_deviceManager->discover(false) ) {
456 printMessage("Could not discover devices\n" );
457 delete m_deviceManager;
458 return -1;
461 // loop over all discovered devices and extract the SCS devices
462 int nb_devices = m_deviceManager->getAvDeviceCount();
463 if(nb_devices == 0) {
464 printMessage("No devices found\n");
465 delete m_deviceManager;
466 return -1;
469 typedef std::vector<ScsDevice*> ScsDeviceVector;
470 typedef std::vector<ScsDevice*>::iterator ScsDeviceVectorIterator;
472 ScsDeviceVector scsDevices;
473 for(int i=0; i<nb_devices; i++) {
474 FFADODevice *device = m_deviceManager->getAvDeviceByIndex(i);
475 GenericAVC::Stanton::ScsDevice* scsDevice = dynamic_cast<GenericAVC::Stanton::ScsDevice*>(device);
476 if(scsDevice == NULL) {
477 printMessage("Device %d (GUID: %s) is not a Stanton SCS device\n", i, device->getConfigRom().getGuidString().c_str() );
478 } else {
479 printMessage("Device %d (GUID: %s) is a Stanton SCS device\n", i, device->getConfigRom().getGuidString().c_str() );
480 scsDevices.push_back(scsDevice);
484 if(scsDevices.size() == 0) {
485 printMessage("No SCS devices found\n");
486 delete m_deviceManager;
487 return -1;
490 // open the alsa sequencer
491 if (snd_seq_open(&m_seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
492 debugError("Error opening ALSA sequencer.");
493 delete m_deviceManager;
494 return -1;
497 snd_seq_set_client_name(m_seq_handle, "STANTON-SCS1");
499 // this maps the alsa sequencer ports to the corresponding bridges
500 typedef std::map<int, HSS1394AlsaSeqMidiBridge*> BridgeMap;
501 typedef std::map<int, HSS1394AlsaSeqMidiBridge*>::iterator BridgeMapIterator;
502 BridgeMap seqport2bridgemap;
504 for ( ScsDeviceVectorIterator it = scsDevices.begin();
505 it != scsDevices.end();
506 ++it )
508 HSS1394AlsaSeqMidiBridge *bridge = new HSS1394AlsaSeqMidiBridge(m_seq_handle, **it);
509 if(bridge == NULL) {
510 debugError("Could not allocate HSS1394 <=> ALSA bridge\n");
511 delete m_deviceManager;
512 return -1;
514 bridge->setVerboseLevel(arguments.verbose);
515 if(!bridge->init()) {
516 debugError("Could not init HSS1394 <=> ALSA bridge\n");
517 delete m_deviceManager;
518 return -1;
520 int portNumber = bridge->getAlsaSeqOutputPortNumber();
521 #ifdef DEBUG
522 if(portNumber < -1) {
523 debugError("BUG: port should be >= 0 after init\n");
525 #endif
527 BridgeMapIterator it2 = seqport2bridgemap.find(portNumber);
528 if(it2 == seqport2bridgemap.end()) {
529 seqport2bridgemap[portNumber] = bridge;
530 } else {
531 debugError("BUG: port already present in bridge map, duplicate port.\n");
532 delete bridge;
536 // enter a wait loop
537 printMessage(" >>> Entering wait loop, use CTRL-C to exit... \n" );
538 while(run) {
539 snd_seq_event_t *ev;
540 int err = 0;
542 // get next event, if one is present, blocks until an event is received
543 err = snd_seq_event_input(m_seq_handle, &ev);
544 if(err > 0 && ev) {
545 debugOutput(DEBUG_LEVEL_VERBOSE, "Got event...\n");
546 if (ev->source.client == SND_SEQ_CLIENT_SYSTEM)
547 continue;
549 // figure out what bridge this is intended for
550 BridgeMapIterator it = seqport2bridgemap.find(ev->dest.port);
551 if(it != seqport2bridgemap.end()) {
552 HSS1394AlsaSeqMidiBridge *bridge = (*it).second;
553 if(bridge) {
554 if(!bridge->sendAlsaSeqEvent(ev)) {
555 debugError("Failed to send event to HSS1394 node\n");
557 } else {
558 debugError("Bogus bridge in seqport2bridgemap\n");
560 } else {
561 debugWarning("Received message for unknown port\n");
564 } else {
565 switch(err) {
566 case -EAGAIN:
567 debugOutput(DEBUG_LEVEL_VERBOSE, "no events in ALSA-SEQ FIFO\n");
568 break;
569 case -ENOSPC:
570 debugWarning("ALSA-SEQ FIFO overrun, events dropped!\n");
571 break;
572 default:
573 debugError("Failed to receive ALSA-SEQ event (%d)\n", err);
577 printMessage(" <<< Exit wait loop... \n" );
579 // cleanup
580 for ( BridgeMapIterator it = seqport2bridgemap.begin();
581 it != seqport2bridgemap.end();
582 ++it )
584 HSS1394AlsaSeqMidiBridge *bridge = (*it).second;
585 delete bridge;
587 seqport2bridgemap.clear();
589 snd_seq_close(m_seq_handle);
590 delete m_deviceManager;
592 printMessage("Bye... \n" );
593 return 0;