Stop trying to talk to device on startup. Remap some bcf buttons.
[ardour.git] / libs / surfaces / mackie / mackie_control_protocol_poll.cc
1 #include "mackie_control_protocol.h"
2
3 #include "midi_byte_array.h"
4 #include "surface_port.h"
5
6 #include <pbd/pthread_utils.h>
7 #include <pbd/error.h>
8
9 #include <midi++/types.h>
10 #include <midi++/port.h>
11 #include <midi++/manager.h>
12 #include <midi++/port_request.h>
13 #include "i18n.h"
14
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <poll.h>
18 #include <errno.h>
19
20 #include <iostream>
21 #include <string>
22 #include <vector>
23
24 using namespace std;
25 using namespace Mackie;
26 using namespace PBD;
27
28 const char * MackieControlProtocol::default_port_name = "mcu";
29
30 bool MackieControlProtocol::probe()
31 {
32         return MIDI::Manager::instance()->port( default_port_name ) != 0;
33 }
34
35 void * MackieControlProtocol::monitor_work()
36 {
37         // What does ThreadCreatedWithRequestSize do?
38         PBD::ThreadCreated (pthread_self(), X_("Mackie"));
39
40         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
41         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
42
43         // read from midi ports
44         while ( true )
45         {
46                 try
47                 {
48                         if ( poll_ports() )
49                         {
50                                 try { read_ports(); }
51                                 catch ( exception & e ) {
52                                         cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl;
53                                         _ports_changed = true;
54                                         update_ports();
55                                 }
56                         }
57                         // poll for automation data from the routes
58                         poll_automation();
59                 }
60                 catch ( exception & e )
61                 {
62                         cout << "caught exception in MackieControlProtocol::monitor_work " << e.what() << endl;
63                 }
64                 
65                 // provide a cancellation point
66                 pthread_testcancel();
67         }
68
69         // these never get called because of cancellation point above
70         cout << "MackieControlProtocol::poll_ports exiting" << endl;
71         
72         delete[] pfd;
73
74         return (void*) 0;
75 }
76
77 void MackieControlProtocol::update_ports()
78 {
79         if ( _ports_changed )
80         {
81                 Glib::Mutex::Lock ul( update_mutex );
82                 // yes, this is a double-test locking paradigm, or whatever it's called
83                 // because we don't *always* need to acquire the lock for the first test
84                 if ( _ports_changed )
85                 {
86                         // create new pollfd structures
87                         if ( pfd != 0 ) delete[] pfd;
88                         // TODO This might be a memory leak. How does thread cancellation cleanup work?
89                         pfd = new pollfd[_ports.size()];
90                         nfds = 0;
91
92                         for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
93                         {
94                                 cout << "adding port " << (*it)->port().name() << " to pollfd" << endl;
95                                 pfd[nfds].fd = (*it)->port().selectable();
96                                 pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
97                                 ++nfds;
98                         }
99                         _ports_changed = false;
100                 }
101                 update_cond.signal();
102         }
103 }
104
105 void MackieControlProtocol::read_ports()
106 {
107         /* now read any data on the ports */
108         Glib::Mutex::Lock lock( update_mutex );
109         for ( int p = 0; p < nfds; ++p )
110         {
111                 // this will cause handle_midi_any in the MackiePort to be triggered
112                 if ( pfd[p].revents & POLLIN > 0 )
113                 {
114                         // avoid deadlocking?
115                         // doesn't seem to make a difference
116                         //lock.release();
117                         _ports[p]->read();
118                         //lock.acquire();
119                 }
120         }
121 }
122
123 bool MackieControlProtocol::poll_ports()
124 {
125         int timeout = 10; // milliseconds
126         int no_ports_sleep = 1000; // milliseconds
127
128         Glib::Mutex::Lock lock( update_mutex );
129         // if there are no ports
130         if ( nfds < 1 )
131         {
132                 lock.release();
133                 cout << "poll_ports no ports" << endl;
134                 usleep( no_ports_sleep * 1000 );
135                 return false;
136         }
137
138         int retval = poll( pfd, nfds, timeout );
139         if ( retval < 0 )
140         {
141                 // gdb at work, perhaps
142                 if ( errno != EINTR )
143                 {
144                         error << string_compose(_("Mackie MIDI thread poll failed (%1)"), strerror( errno ) ) << endmsg;
145                 }
146                 return false;
147         }
148         
149         return retval > 0;
150 }
151
152 void MackieControlProtocol::handle_port_inactive( SurfacePort * port )
153 {
154         // port gone away. So stop polling it ASAP
155         {
156                 // delete the port instance
157                 Glib::Mutex::Lock lock( update_mutex );
158                 MackiePorts::iterator it = find( _ports.begin(), _ports.end(), port );
159                 if ( it != _ports.end() )
160                 {
161                         delete *it;
162                         _ports.erase( it );
163                 }
164         }
165         _ports_changed = true;
166         update_ports();
167         
168         // TODO all the rebuilding of surfaces and so on
169 }
170
171 void MackieControlProtocol::handle_port_active( SurfacePort * port )
172 {
173         // no need to re-add port because it was already added
174         // during the init phase. So just update the local surface
175         // representation and send the representation to 
176         // all existing ports
177         
178         // TODO update bank size
179         
180         // TODO rebuild surface, to have new units
181         
182         // finally update session state to the surface
183         // TODO but this is also done in set_active, and
184         // in fact update_surface won't execute unless
185         // _active == true
186         cout << "update_surface in handle_port_active" << endl;
187         update_surface();
188 }
189
190 void MackieControlProtocol::handle_port_init( Mackie::SurfacePort * sport )
191 {
192         cout << "MackieControlProtocol::handle_port_init" << endl;
193         _ports_changed = true;
194         update_ports();
195 }