enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[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         struct sched_param rtparam;
47         int err;
48         char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
49         memset (&rtparam, 0, sizeof (rtparam));
50         rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
51         // Note - try SCHED_RR with a low limit
52         // - we don't care if we can't write everything this ms
53         // and it will help if we lose the device
54         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
55                 PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
56                 return 1;
57         }
58         return 0;
59 }
60
61 // Running with realtime privs is bad when you have problems
62
63 int TranzportControlProtocol::rtpriority_unset(int priority)
64 {
65         struct sched_param rtparam;
66         int err;
67         memset (&rtparam, 0, sizeof (rtparam));
68         rtparam.sched_priority = priority;
69         if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
70                 PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
71                 return 1;
72         }
73         PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
74         return 0;
75 }
76
77
78 int
79 TranzportControlProtocol::set_active (bool yn)
80 {
81         if (yn != _active) {
82
83                 if (yn) {
84
85                         if (open ()) {
86                                 return -1;
87                         }
88
89                         if (pthread_create_and_store (X_("tranzport monitor"), &thread, _monitor_work, this) == 0) {
90                                 _active = true;
91                         } else {
92                                 return -1;
93                         }
94
95                 } else {
96                         cerr << "Begin tranzport shutdown\n";
97 //                      if we got here due to an error, prettifying things will only make it worse
98 //                      And with threads involved, oh boy...
99                         if(!(last_write_error || last_read_error)) {
100                                 bling_mode   = BlingExit;
101                                 enter_bling_mode();
102 // thread FIXME - wait til all writes are done
103                                 for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
104                         }
105
106                         pthread_cancel_one (thread);
107
108                         cerr << "Tranzport Thread dead\n";
109                         close ();
110                         _active = false;
111                         cerr << "End tranzport shutdown\n";
112                 }
113         }
114
115         return 0;
116 }
117
118 TranzportControlProtocol::TranzportControlProtocol (Session& s)
119         : ControlProtocol  (s, X_("Tranzport"))
120 {
121         /* tranzport controls one track at a time */
122
123         set_route_table_size (1);
124         timeout = 6000; // what is this for?
125         buttonmask = 0;
126         _datawheel = 0;
127         _device_status = STATUS_OFFLINE;
128         udev = 0;
129         current_track_id = 0;
130         last_where = max_frames;
131         wheel_mode = WheelTimeline;
132         wheel_shift_mode = WheelShiftGain;
133         wheel_increment = WheelIncrScreen;
134         bling_mode = BlingEnter;
135         last_notify_msg[0] = '\0';
136         last_notify = 0;
137         timerclear (&last_wheel_motion);
138         last_wheel_dir = 1;
139         last_track_gain = FLT_MAX;
140         last_write_error = 0;
141         last_read_error = 0;
142         display_mode = DisplayBling;
143         gain_fraction = 0.0;
144         invalidate();
145         screen_init();
146         lights_init();
147 // FIXME: Wait til device comes online somewhere
148 // About 3 reads is enough
149 // enter_bling_mode();
150
151 }
152
153 void*
154 TranzportControlProtocol::monitor_work ()
155 {
156         uint8_t buf[8]; //  = { 0,0,0,0,0,0,0,0 };
157         int val = 0, pending = 0;
158         bool first_time = true;
159         uint8_t offline = 0;
160
161         register_thread (X_("Tranzport"));
162         pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
163         pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
164         rtpriority_set();
165         inflight=0;
166         //int intro = 20;
167
168         // wait for the device to come online
169         invalidate();
170         screen_init();
171         lights_init();
172         update_state();
173 //      There has to be some specific command to enable the device!!
174 //      while((val = read(buf,DEFAULT_USB_TIMEOUT*5)) == -110 && pending !=0) {
175 //              pending = lights_flush(); // poke the device for a while
176 //      }
177
178 //      pending = 1;
179 //      while(intro-- > 0 && pending != 0) {
180 //              usleep(1000);
181 //              pending = screen_flush(); // kinder, gentler init
182 //      }
183 //      usleep(1000);
184 //      lights_on();
185 //      while(flush()!=0) ;
186 //      lights_off();
187         display_mode = DisplayNormal;
188
189         while (true) {
190
191                 /* bInterval for this beastie is 10ms */
192
193                 if (_device_status == STATUS_OFFLINE) {
194                         first_time = true; offline++;
195 #if TRANZPORT_DEBUG > 3
196                         if(offline == 1) {
197                                 cerr << "Transport has gone offline\n";
198                         }
199 #endif
200                 } else {
201                         offline = 0; // hate writing this
202                 }
203                 unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
204                 switch (s) {
205                 case 0: val = read(buf,DEFAULT_USB_TIMEOUT); break;
206                 case 1: val = read(buf,DEFAULT_USB_TIMEOUT); break;
207                 case 2: val = read(buf,DEFAULT_USB_TIMEOUT); break;
208                 case 3: val = read(buf,DEFAULT_USB_TIMEOUT*2); break; // Hoo, boy, we're in trouble
209                 default: break; // not reached
210                 }
211
212 #if DEBUG_TRANZPORT_BITS > 9
213                 if(_device_status != STATUS_OFFLINE && _device_status != STATUS_ONLINE && _device_status != STATUS_OK) {
214                         printf("The device has more status bits than off or online: %d\n",_device_status);
215                 }
216 #endif
217
218 #if DEBUG_TRANZPORT_BITS > 99
219                 if (val != 8) {
220                         printf("val = %d errno = %d\n",val,errno);
221                         buf[0] = buf[1] = buf[2] = buf[3] =
222                                 buf[4] = buf[5] = buf[6] = buf[7] =
223                                 buf[8] = 0;
224                 }
225 #endif
226
227                 if(val == 8) {
228                         last_write_error = 0;
229                         process (buf);
230                 }
231
232 #if DEBUG_TRANZPORT > 9
233                 if(inflight > 1) printf("Inflight: %d\n", inflight);
234 #endif
235
236                 if (_device_status == STATUS_ONLINE) {
237                         if (first_time) {
238                                 invalidate();
239                                 lcd_clear ();
240                                 lights_off ();
241                                 first_time = false;
242                                 last_write_error = 0;
243                                 offline = 0;
244                                 pending = 3; // Give some time for the device to recover
245                         }
246 #if DEBUG_TRANZPORT_BITS > 10
247                         // Perhaps an online message indicates something
248
249                         if(_device_status != buf[1]) {
250                                 printf("WTF- val: %d, device status != buf! %d != %d \n",val,_device_status,buf[1]); _device_status = buf[1];
251                         }
252 #endif
253
254                 }
255
256 #if DEBUG_TRANZPORT_BITS > 10
257
258                 if(val == 8) {
259
260                         if(_device_status == STATUS_ONLINE) {
261                                 printf("ONLINE   : %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                         if(_device_status == STATUS_OFFLINE) {
265                                 printf("OFFLINE  : %02x %02x %02x %02x %02x %02x %02x %02x\n",
266                                        buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
267                         }
268
269                         if(_device_status == STATUS_OK) {
270                                 printf("OK       : %02x %02x %02x %02x %02x %02x %02x %02x\n",
271                                        buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
272                         }
273
274                 }
275
276 #endif
277
278                 /* update whatever needs updating */
279                 if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
280                         update_state ();
281
282                         /* still struggling with a good means of exerting flow control without having to create threads */
283                         // pending = flush();
284
285                         if(pending == 0) {
286                                 pending = flush();
287                         } else {
288                                 if(inflight > 0) {
289                                         pending = --inflight; // we just did a whole bunch of writes so wait
290                                 } else {
291                                         pending = 0;
292                                 }
293                         }
294                 }
295                 // pending = 0;
296         }
297         return (void*) 0;
298 }
299