2 * Copyright (C) 2006 Paul Davis
3 * Copyright (C) 2007 Michael Taht
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.
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.
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.
21 #include <tranzport_common.h>
22 #include <tranzport_control_protocol.h>
24 using namespace ARDOUR;
31 #include <pbd/abstract_ui.cc>
34 TranzportControlProtocol::_monitor_work (void* arg)
36 return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
39 TranzportControlProtocol::~TranzportControlProtocol ()
44 int TranzportControlProtocol::rtpriority_set(int priority)
46 struct sched_param rtparam;
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;
61 // Running with realtime privs is bad when you have problems
63 int TranzportControlProtocol::rtpriority_unset(int priority)
65 struct sched_param rtparam;
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;
73 PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
79 TranzportControlProtocol::set_active (bool yn)
89 if (pthread_create_and_store (X_("tranzport monitor"), &thread, _monitor_work, this) == 0) {
92 if (pthread_create_and_store (X_("tranzport read"), &thread_read, _read_work, this) == 0) {
94 if (pthread_create_and_store (X_("tranzport write"), &thread_write, _write_work, this) == 0) {
96 if (pthread_create_and_store (X_("tranzport process"), &thread_process, _process_work, this) == 0) {
97 _active_process = true;
98 if (pthread_create_and_store (X_("tranzport timer"), &thread_timer, _process_timer, this) == 0) {
99 _active_process = true;
106 cerr << "Begin tranzport shutdown\n";
107 // if we got here due to an error, prettifying things will only make it worse
108 // And with threads involved, oh boy...
109 if(!(last_write_error || last_read_error)) {
110 bling_mode = BlingExit;
112 // thread FIXME - wait til all writes are done
113 for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
115 #if TRANZPORT_THREADS
116 pthread_cancel_one (_thread_timer);
117 pthread_cancel_one (_thread_process);
118 pthread_cancel_one (_thread_read);
119 pthread_cancel_one (_thread_write);
121 pthread_cancel_one (thread);
123 cerr << "Tranzport Thread dead\n";
126 cerr << "End tranzport shutdown\n";
133 TranzportControlProtocol::TranzportControlProtocol (Session& s)
134 : ControlProtocol (s, X_("Tranzport"))
136 /* tranzport controls one track at a time */
138 set_route_table_size (1);
139 timeout = 6000; // what is this for?
142 _device_status = STATUS_OFFLINE;
144 current_track_id = 0;
145 last_where = max_frames;
146 wheel_mode = WheelTimeline;
147 wheel_shift_mode = WheelShiftGain;
148 wheel_increment = WheelIncrScreen;
149 bling_mode = BlingEnter;
150 last_notify_msg[0] = '\0';
152 timerclear (&last_wheel_motion);
154 last_track_gain = FLT_MAX;
155 last_write_error = 0;
157 display_mode = DisplayBling;
162 // FIXME: Wait til device comes online somewhere
163 // About 3 reads is enough
164 // enter_bling_mode();
169 TranzportControlProtocol::monitor_work ()
171 uint8_t buf[8]; // = { 0,0,0,0,0,0,0,0 };
172 int val = 0, pending = 0;
173 bool first_time = true;
176 register_thread (X_("Tranzport"));
177 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
178 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
183 // wait for the device to come online
188 // There has to be some specific command to enable the device!!
189 // while((val = read(buf,DEFAULT_USB_TIMEOUT*5)) == -110 && pending !=0) {
190 // pending = lights_flush(); // poke the device for a while
194 // while(intro-- > 0 && pending != 0) {
196 // pending = screen_flush(); // kinder, gentler init
200 // while(flush()!=0) ;
202 display_mode = DisplayNormal;
206 /* bInterval for this beastie is 10ms */
208 if (_device_status == STATUS_OFFLINE) {
209 first_time = true; offline++;
210 #if TRANZPORT_DEBUG > 3
212 cerr << "Transport has gone offline\n";
216 offline = 0; // hate writing this
218 unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
220 case 0: val = read(buf,DEFAULT_USB_TIMEOUT); break;
221 case 1: val = read(buf,DEFAULT_USB_TIMEOUT); break;
222 case 2: val = read(buf,DEFAULT_USB_TIMEOUT); break;
223 case 3: val = read(buf,DEFAULT_USB_TIMEOUT*2); break; // Hoo, boy, we're in trouble
224 default: break; // not reached
227 #if DEBUG_TRANZPORT_BITS > 9
228 if(_device_status != STATUS_OFFLINE && _device_status != STATUS_ONLINE && _device_status != STATUS_OK) {
229 printf("The device has more status bits than off or online: %d\n",_device_status);
233 #if DEBUG_TRANZPORT_BITS > 99
235 printf("val = %d errno = %d\n",val,errno);
236 buf[0] = buf[1] = buf[2] = buf[3] =
237 buf[4] = buf[5] = buf[6] = buf[7] =
243 last_write_error = 0;
247 #if DEBUG_TRANZPORT > 9
248 if(inflight > 1) printf("Inflight: %d\n", inflight);
251 if (_device_status == STATUS_ONLINE) {
257 last_write_error = 0;
259 pending = 3; // Give some time for the device to recover
261 #if DEBUG_TRANZPORT_BITS > 10
262 // Perhaps an online message indicates something
264 if(_device_status != buf[1]) {
265 printf("WTF- val: %d, device status != buf! %d != %d \n",val,_device_status,buf[1]); _device_status = buf[1];
271 #if DEBUG_TRANZPORT_BITS > 10
275 if(_device_status == STATUS_ONLINE) {
276 printf("ONLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
277 buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
279 if(_device_status == STATUS_OFFLINE) {
280 printf("OFFLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
281 buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
284 if(_device_status == STATUS_OK) {
285 printf("OK : %02x %02x %02x %02x %02x %02x %02x %02x\n",
286 buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
293 /* update whatever needs updating */
294 if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
297 /* still struggling with a good means of exerting flow control without having to create threads */
298 // pending = flush();
304 pending = --inflight; // we just did a whole bunch of writes so wait