summaryrefslogtreecommitdiff
path: root/libs/surfaces/mackie/mackie_control_protocol_poll.cc
diff options
context:
space:
mode:
authorJohn Anderson <ardour@semiosix.com>2007-02-14 19:56:16 +0000
committerJohn Anderson <ardour@semiosix.com>2007-02-14 19:56:16 +0000
commite878b365193ad9315e557a8245b767d8a0fe568d (patch)
treed03d6b7bc7bb57c7c55d370010b8c6e6bb6619ae /libs/surfaces/mackie/mackie_control_protocol_poll.cc
parent92c09a6d91fa90bbfaec4d94e2c6e6c11f1e49a3 (diff)
merge r1449 from surfaces branch to include mackie surface and tranzport updates. Thanks to Gerd Flaig for the merge command: svn merge svn+ssh://ardoursvn@ardour.org/ardour2/trunk@1449 svn+ssh://ardoursvn@ardour.org/ardour2/branches/surfaces.
git-svn-id: svn://localhost/ardour2/trunk@1460 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/surfaces/mackie/mackie_control_protocol_poll.cc')
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc194
1 files changed, 194 insertions, 0 deletions
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
new file mode 100644
index 0000000000..f6b2deeb6b
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -0,0 +1,194 @@
+#include "mackie_control_protocol.h"
+
+#include "midi_byte_array.h"
+#include "surface_port.h"
+
+#include <pbd/pthread_utils.h>
+#include <pbd/error.h>
+
+#include <midi++/types.h>
+#include <midi++/port.h>
+#include <midi++/manager.h>
+#include <midi++/port_request.h>
+#include "i18n.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+using namespace std;
+using namespace Mackie;
+using namespace PBD;
+
+const char * MackieControlProtocol::default_port_name = "mcu";
+
+bool MackieControlProtocol::probe()
+{
+ return MIDI::Manager::instance()->port( default_port_name ) != 0;
+}
+
+void * MackieControlProtocol::monitor_work()
+{
+ cout << "MackieControlProtocol::monitor_work" << endl;
+ // What does ThreadCreatedWithRequestSize do?
+ PBD::ThreadCreated (pthread_self(), X_("Mackie"));
+
+#if 0
+ // it seems to do the "block" on poll less often
+ // with this code disabled
+ struct sched_param rtparam;
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
+
+ int err;
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ // do we care? not particularly.
+ PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror( errno )) << endmsg;
+ }
+#endif
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ // read from midi ports
+ cout << "start poll cycle" << endl;
+ while ( true )
+ {
+ update_ports();
+ if ( poll_ports() )
+ {
+ try { read_ports(); }
+ catch ( exception & e ) {
+ cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl;
+ }
+ }
+ // provide a cancellation point
+ pthread_testcancel();
+ }
+
+ // these never get called
+ cout << "MackieControlProtocol::poll_ports exiting" << endl;
+
+ delete[] pfd;
+
+ return (void*) 0;
+}
+
+void MackieControlProtocol::update_ports()
+{
+ // create pollfd structures if necessary
+ if ( _ports_changed )
+ {
+ Glib::Mutex::Lock ul( update_mutex );
+ // yes, this is a double-test locking paradigm, or whatever it's called
+ // because we don't *always* need to acquire the lock for the first test
+ if ( _ports_changed )
+ {
+ cout << "MackieControlProtocol::update_ports updating" << endl;
+ if ( pfd != 0 ) delete[] pfd;
+ // TODO This might be a memory leak. How does thread cancellation cleanup work?
+ pfd = new pollfd[_ports.size()];
+ nfds = 0;
+
+ for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
+ {
+ cout << "adding port " << (*it)->port().name() << " to pollfd" << endl;
+ pfd[nfds].fd = (*it)->port().selectable();
+ pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+ ++nfds;
+ }
+ _ports_changed = false;
+ }
+ update_cond.signal();
+ }
+}
+
+void MackieControlProtocol::read_ports()
+{
+ /* now read any data on the ports */
+ Glib::Mutex::Lock lock( update_mutex );
+ for ( int p = 0; p < nfds; ++p )
+ {
+ // this will cause handle_midi_any in the MackiePort to be triggered
+ if ( pfd[p].revents & POLLIN > 0 )
+ {
+ lock.release();
+ _ports[p]->read();
+ lock.acquire();
+ }
+ }
+}
+
+bool MackieControlProtocol::poll_ports()
+{
+ int timeout = 10; // milliseconds
+ int no_ports_sleep = 10; // milliseconds
+
+ Glib::Mutex::Lock lock( update_mutex );
+ // if there are no ports
+ if ( nfds < 1 )
+ {
+ lock.release();
+ cout << "poll_ports no ports" << endl;
+ usleep( no_ports_sleep * 1000 );
+ return false;
+ }
+
+ int retval = poll( pfd, nfds, timeout );
+ if ( retval < 0 )
+ {
+ // gdb at work, perhaps
+ if ( errno != EINTR )
+ {
+ error << string_compose(_("Mackie MIDI thread poll failed (%1)"), strerror( errno ) ) << endmsg;
+ }
+ return false;
+ }
+
+ return retval > 0;
+}
+
+void MackieControlProtocol::handle_port_changed( SurfacePort * port, bool active )
+{
+ cout << "MackieControlProtocol::handle_port_changed port: " << *port << " active: " << active << endl;
+ if ( active == false )
+ {
+ // port gone away. So stop polling it ASAP
+ {
+ // delete the port instance
+ Glib::Mutex::Lock lock( update_mutex );
+ MackiePorts::iterator it = find( _ports.begin(), _ports.end(), port );
+ if ( it != _ports.end() )
+ {
+ delete *it;
+ _ports.erase( it );
+ }
+ }
+ _ports_changed = true;
+ update_ports();
+ }
+ else
+ {
+ _ports_changed = true;
+ // port added
+ update_ports();
+ update_surface();
+
+ // TODO update bank size
+
+ // rebuild surface
+ }
+}
+
+void MackieControlProtocol::handle_port_init( Mackie::SurfacePort * sport )
+{
+ cout << "MackieControlProtocol::handle_port_init" << endl;
+ _ports_changed = true;
+ update_ports();
+ cout << "MackieControlProtocol::handle_port_init finished" << endl;
+}