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
;
51 #include <alsa/asoundlib.h>
52 #define ALSA_SEQ_BUFF_SIZE 32
53 #define MIDI_TRANSMIT_BUFFER_SIZE 512
58 DECLARE_GLOBAL_DEBUG_MODULE
;
63 snd_seq_t
*m_seq_handle
= NULL
;
65 static void sighandler(int sig
)
69 // send an event to wake the iterator loop
71 snd_seq_nonblock(m_seq_handle
, 1);
75 ////////////////////////////////////////////////
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" },
94 , verbose( DEBUG_LEVEL_NORMAL
)
103 char* args
[MAX_ARGS
];
112 // Parse a single option.
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
;
124 arguments
->verbose
= strtol(arg
, &tail
, 0);
127 arguments
->test
= true;
130 arguments
->port
= strtol(arg
, &tail
, 0);
132 perror("argument parsing failed:");
137 arguments
->node
= strtol(arg
, &tail
, 0);
139 perror("argument parsing failed:");
144 arguments
->sysexbuf
= strtol(arg
, &tail
, 0);
147 if (state
->arg_num
>= MAX_ARGS
) {
148 // Too many arguments.
151 arguments
->args
[state
->arg_num
] = arg
;
155 if(arguments
->nargs
<0) {
156 printf("not enough arguments\n");
162 return ARGP_ERR_UNKNOWN
;
167 static struct argp argp
= { options
, parse_opt
, args_doc
, doc
};
169 class HSS1394AlsaSeqMidiBridge
{
170 class HSS1394UserDataHandler
;
173 HSS1394AlsaSeqMidiBridge(snd_seq_t
*seq_handle
, GenericAVC::Stanton::ScsDevice
&device
)
174 : m_seq_handle (seq_handle
)
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
);
196 snd_midi_event_free(m_out_parser
);
202 // need local copy as the nickname can change
203 m_name
= m_device
.getNickname();
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");
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");
221 // disable running-status
222 snd_midi_event_no_status(m_out_parser
, 1);
225 HSS1394UserDataHandler
*m_input_handler
= new HSS1394UserDataHandler(*this);
226 if(m_input_handler
== NULL
) {
227 debugError("Error creating handler.");
230 if(!m_input_handler
->init(m_name
)) {
231 debugError("Could not init input message handler\n");
234 if(!m_device
.m_hss1394handler
->addMessageHandler(GenericAVC::Stanton::ScsDevice::eMT_UserData
, m_input_handler
)) {
235 debugError("Could not register input message handler\n");
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
,
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
);
252 if (bytes_to_send
== 1 && arguments
.sysexbuf
==1) {
253 switch(m_work_buffer
[0]) {
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");
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");
267 sysex_buffer_count
=0;
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");
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];
289 if(!m_device
.writeHSS1394Message(GenericAVC::Stanton::ScsDevice::eMT_UserData
, m_work_buffer
,bytes_to_send
)) {
290 debugError("Failed to send message\n");
297 int getAlsaSeqOutputPortNumber() {
298 return m_out_port_nr
;
300 int getAlsaSeqInputPortNumber() {
301 if (m_input_handler
) {
302 return m_input_handler
->getAlsaSeqPortNumber();
304 debugError("input handler not initialized yet");
309 void setVerboseLevel(int i
) {
314 snd_seq_t
*m_seq_handle
;
315 GenericAVC::Stanton::ScsDevice
&m_device
;
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
{
331 HSS1394UserDataHandler(HSS1394AlsaSeqMidiBridge
&parent
)
334 , m_seq_port_nr( -1 )
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
);
345 snd_midi_event_free(m_parser
);
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");
360 if(snd_midi_event_new( ALSA_SEQ_BUFF_SIZE
, &m_parser
) < 0) {
361 debugError("could not init parser");
368 int getAlsaSeqPortNumber() {
369 return m_seq_port_nr
;
372 virtual void operator() (byte_t
*buff
, size_t len
) {
374 debugOutput(DEBUG_LEVEL_VERBOSE
,
375 "got message len %zd\n",
378 for (size_t s
=0; s
< len
; s
++) {
379 byte_t
*byte
= (buff
+s
);
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
);
390 debugError("Not ready\n");
394 HSS1394AlsaSeqMidiBridge
&m_parent
;
397 snd_midi_event_t
*m_parser
;
398 DECLARE_DEBUG_MODULE_REFERENCE
;
401 IMPL_DEBUG_MODULE( HSS1394AlsaSeqMidiBridge
, HSS1394AlsaSeqMidiBridge
, DEBUG_LEVEL_NORMAL
);
403 ///////////////////////////
405 //////////////////////////
407 main(int argc
, char **argv
)
410 if ( argp_parse ( &argp
, argc
, argv
, 0, 0, &arguments
) ) {
411 printMessage("Could not parse command line\n" );
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" );
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
;
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
;
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
;
455 if ( !m_deviceManager
->discover(false) ) {
456 printMessage("Could not discover devices\n" );
457 delete m_deviceManager
;
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
;
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() );
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
;
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
;
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();
508 HSS1394AlsaSeqMidiBridge
*bridge
= new HSS1394AlsaSeqMidiBridge(m_seq_handle
, **it
);
510 debugError("Could not allocate HSS1394 <=> ALSA bridge\n");
511 delete m_deviceManager
;
514 bridge
->setVerboseLevel(arguments
.verbose
);
515 if(!bridge
->init()) {
516 debugError("Could not init HSS1394 <=> ALSA bridge\n");
517 delete m_deviceManager
;
520 int portNumber
= bridge
->getAlsaSeqOutputPortNumber();
522 if(portNumber
< -1) {
523 debugError("BUG: port should be >= 0 after init\n");
527 BridgeMapIterator it2
= seqport2bridgemap
.find(portNumber
);
528 if(it2
== seqport2bridgemap
.end()) {
529 seqport2bridgemap
[portNumber
] = bridge
;
531 debugError("BUG: port already present in bridge map, duplicate port.\n");
537 printMessage(" >>> Entering wait loop, use CTRL-C to exit... \n" );
542 // get next event, if one is present, blocks until an event is received
543 err
= snd_seq_event_input(m_seq_handle
, &ev
);
545 debugOutput(DEBUG_LEVEL_VERBOSE
, "Got event...\n");
546 if (ev
->source
.client
== SND_SEQ_CLIENT_SYSTEM
)
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
;
554 if(!bridge
->sendAlsaSeqEvent(ev
)) {
555 debugError("Failed to send event to HSS1394 node\n");
558 debugError("Bogus bridge in seqport2bridgemap\n");
561 debugWarning("Received message for unknown port\n");
567 debugOutput(DEBUG_LEVEL_VERBOSE
, "no events in ALSA-SEQ FIFO\n");
570 debugWarning("ALSA-SEQ FIFO overrun, events dropped!\n");
573 debugError("Failed to receive ALSA-SEQ event (%d)\n", err
);
577 printMessage(" <<< Exit wait loop... \n" );
580 for ( BridgeMapIterator it
= seqport2bridgemap
.begin();
581 it
!= seqport2bridgemap
.end();
584 HSS1394AlsaSeqMidiBridge
*bridge
= (*it
).second
;
587 seqport2bridgemap
.clear();
589 snd_seq_close(m_seq_handle
);
590 delete m_deviceManager
;
592 printMessage("Bye... \n" );