OSC: add group sharing bit feedback
[ardour.git] / libs / surfaces / tranzport / init.cc
1 /*
2  *   Copyright (C) 2006 Paul Davis
3  *   Copyright (C) 2007 Michael Taht
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20
21 #include <tranzport_common.h>
22 #include <tranzport_control_protocol.h>
23
24 using namespace ARDOUR;
25 using namespace std;
26 using namespace sigc;
27 using namespace PBD;
28
29 #include "pbd/i18n.h"
30
31 #include <pbd/abstract_ui.cc>
32
33 void*
34 TranzportControlProtocol::_monitor_work (void* arg)
35 {
36         return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
37 }
38
39 TranzportControlProtocol::~TranzportControlProtocol ()
40 {
41         set_active (false);
42 }
43
44 int TranzportControlProtocol::rtpriority_set(int priority)
45 {
46         char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
47         // Note - try SCHED_RR with a low limit
48         // - we don't care if we can't write everything this ms
49         // and it will help if we lose the device
50         if (set_thread_priority (SCHED_FIFO, priority)) {
51                 PBD::info << string_compose (_("%1: thread not running with realtime scheduling."), name(), strerror (errno)) << endmsg;
52                 return 1;
53         }
54         return 0;
55 }
56
57 // Running with realtime privs is bad when you have problems
58
59 int TranzportControlProtocol::rtpriority_unset(int priority)
60 {
61         struct sched_param rtparam;
62         int err;
63         memset (&rtparam, 0, sizeof (rtparam));
64         rtparam.sched_priority = priority;
65         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
66                 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
67                 return 1;
68         }
69         PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
70         return 0;
71 }
72
73
74 int
75 TranzportControlProtocol::set_active (bool yn)
76 {
77         if (yn != _active) {
78
79                 if (yn) {
80
81                         if (open ()) {
82                                 return -1;
83                         }
84
85                         if (pthread_create_and_store (X_("tranzport monitor"), &thread, _monitor_work, this) == 0) {
86                                 _active = true;
87                         } else {
88                                 return -1;
89                         }
90
91                 } else {
92                         cerr << "Begin tranzport shutdown\n";
93 //                      if we got here due to an error, prettifying things will only make it worse
94 //                      And with threads involved, oh boy...
95                         if(!(last_write_error || last_read_error)) {
96                                 bling_mode   = BlingExit;
97                                 enter_bling_mode();
98 // thread FIXME - wait til all writes are done
99                                 for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
100                         }
101
102                         pthread_cancel_one (thread);
103
104                         cerr << "Tranzport Thread dead\n";
105                         close ();
106                         _active = false;
107                         cerr << "End tranzport shutdown\n";
108                 }
109         }
110
111         return 0;
112 }
113
114 TranzportControlProtocol::TranzportControlProtocol (Session& s)
115         : ControlProtocol  (s, X_("Tranzport"))
116 {
117         /* tranzport controls one track at a time */
118
119         set_route_table_size (1);
120         timeout = 6000; // what is this for?
121         buttonmask = 0;
122         _datawheel = 0;
123         _device_status = STATUS_OFFLINE;
124         udev = 0;
125         current_track_id = 0;
126         last_where = max_samples;
127         wheel_mode = WheelTimeline;
128         wheel_shift_mode = WheelShiftGain;
129         wheel_increment = WheelIncrScreen;
130         bling_mode = BlingEnter;
131         last_notify_msg[0] = '\0';
132         last_notify = 0;
133         timerclear (&last_wheel_motion);
134         last_wheel_dir = 1;
135         last_track_gain = FLT_MAX;
136         last_write_error = 0;
137         last_read_error = 0;
138         display_mode = DisplayBling;
139         gain_fraction = 0.0;
140         invalidate();
141         screen_init();
142         lights_init();
143 // FIXME: Wait til device comes online somewhere
144 // About 3 reads is enough
145 // enter_bling_mode();
146
147 }
148
149 void*
150 TranzportControlProtocol::monitor_work ()
151 {
152         uint8_t buf[8]; //  = { 0,0,0,0,0,0,0,0 };
153         int val = 0, pending = 0;
154         bool first_time = true;
155         uint8_t offline = 0;
156
157         register_thread (X_("Tranzport"));
158         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
159         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
160         rtpriority_set();
161         inflight=0;
162         //int intro = 20;
163
164         // wait for the device to come online
165         invalidate();
166         screen_init();
167         lights_init();
168         update_state();
169 //      There has to be some specific command to enable the device!!
170 //      while((val = read(buf,DEFAULT_USB_TIMEOUT*5)) == -110 && pending !=0) {
171 //              pending = lights_flush(); // poke the device for a while
172 //      }
173
174 //      pending = 1;
175 //      while(intro-- > 0 && pending != 0) {
176 //              usleep(1000);
177 //              pending = screen_flush(); // kinder, gentler init
178 //      }
179 //      usleep(1000);
180 //      lights_on();
181 //      while(flush()!=0) ;
182 //      lights_off();
183         display_mode = DisplayNormal;
184
185         while (true) {
186
187                 /* bInterval for this beastie is 10ms */
188
189                 if (_device_status == STATUS_OFFLINE) {
190                         first_time = true; offline++;
191 #if TRANZPORT_DEBUG > 3
192                         if(offline == 1) {
193                                 cerr << "Transport has gone offline\n";
194                         }
195 #endif
196                 } else {
197                         offline = 0; // hate writing this
198                 }
199                 unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
200                 switch (s) {
201                 case 0: val = read(buf,DEFAULT_USB_TIMEOUT); break;
202                 case 1: val = read(buf,DEFAULT_USB_TIMEOUT); break;
203                 case 2: val = read(buf,DEFAULT_USB_TIMEOUT); break;
204                 case 3: val = read(buf,DEFAULT_USB_TIMEOUT*2); break; // Hoo, boy, we're in trouble
205                 default: break; // not reached
206                 }
207
208 #if DEBUG_TRANZPORT_BITS > 9
209                 if(_device_status != STATUS_OFFLINE && _device_status != STATUS_ONLINE && _device_status != STATUS_OK) {
210                         printf("The device has more status bits than off or online: %d\n",_device_status);
211                 }
212 #endif
213
214 #if DEBUG_TRANZPORT_BITS > 99
215                 if (val != 8) {
216                         printf("val = %d errno = %d\n",val,errno);
217                         buf[0] = buf[1] = buf[2] = buf[3] =
218                                 buf[4] = buf[5] = buf[6] = buf[7] =
219                                 buf[8] = 0;
220                 }
221 #endif
222
223                 if(val == 8) {
224                         last_write_error = 0;
225                         process (buf);
226                 }
227
228 #if DEBUG_TRANZPORT > 9
229                 if(inflight > 1) printf("Inflight: %d\n", inflight);
230 #endif
231
232                 if (_device_status == STATUS_ONLINE) {
233                         if (first_time) {
234                                 invalidate();
235                                 lcd_clear ();
236                                 lights_off ();
237                                 first_time = false;
238                                 last_write_error = 0;
239                                 offline = 0;
240                                 pending = 3; // Give some time for the device to recover
241                         }
242 #if DEBUG_TRANZPORT_BITS > 10
243                         // Perhaps an online message indicates something
244
245                         if(_device_status != buf[1]) {
246                                 printf("WTF- val: %d, device status != buf! %d != %d \n",val,_device_status,buf[1]); _device_status = buf[1];
247                         }
248 #endif
249
250                 }
251
252 #if DEBUG_TRANZPORT_BITS > 10
253
254                 if(val == 8) {
255
256                         if(_device_status == STATUS_ONLINE) {
257                                 printf("ONLINE   : %02x %02x %02x %02x %02x %02x %02x %02x\n",
258                                        buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
259                         }
260                         if(_device_status == STATUS_OFFLINE) {
261                                 printf("OFFLINE  : %02x %02x %02x %02x %02x %02x %02x %02x\n",
262                                        buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
263                         }
264
265                         if(_device_status == STATUS_OK) {
266                                 printf("OK       : %02x %02x %02x %02x %02x %02x %02x %02x\n",
267                                        buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
268                         }
269
270                 }
271
272 #endif
273
274                 /* update whatever needs updating */
275                 if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
276                         update_state ();
277
278                         /* still struggling with a good means of exerting flow control without having to create threads */
279                         // pending = flush();
280
281                         if(pending == 0) {
282                                 pending = flush();
283                         } else {
284                                 if(inflight > 0) {
285                                         pending = --inflight; // we just did a whole bunch of writes so wait
286                                 } else {
287                                         pending = 0;
288                                 }
289                         }
290                 }
291                 // pending = 0;
292         }
293         return (void*) 0;
294 }
295