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) {
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;
102 // thread FIXME - wait til all writes are done
103 for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
106 pthread_cancel_one (thread);
108 cerr << "Tranzport Thread dead\n";
111 cerr << "End tranzport shutdown\n";
118 TranzportControlProtocol::TranzportControlProtocol (Session& s)
119 : ControlProtocol (s, X_("Tranzport"))
121 /* tranzport controls one track at a time */
123 set_route_table_size (1);
124 timeout = 6000; // what is this for?
127 _device_status = STATUS_OFFLINE;
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';
137 timerclear (&last_wheel_motion);
139 last_track_gain = FLT_MAX;
140 last_write_error = 0;
142 display_mode = DisplayBling;
147 // FIXME: Wait til device comes online somewhere
148 // About 3 reads is enough
149 // enter_bling_mode();
154 TranzportControlProtocol::monitor_work ()
156 uint8_t buf[8]; // = { 0,0,0,0,0,0,0,0 };
157 int val = 0, pending = 0;
158 bool first_time = true;
161 register_thread (X_("Tranzport"));
162 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
163 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
168 // wait for the device to come online
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
179 // while(intro-- > 0 && pending != 0) {
181 // pending = screen_flush(); // kinder, gentler init
185 // while(flush()!=0) ;
187 display_mode = DisplayNormal;
191 /* bInterval for this beastie is 10ms */
193 if (_device_status == STATUS_OFFLINE) {
194 first_time = true; offline++;
195 #if TRANZPORT_DEBUG > 3
197 cerr << "Transport has gone offline\n";
201 offline = 0; // hate writing this
203 unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
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
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);
218 #if DEBUG_TRANZPORT_BITS > 99
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] =
228 last_write_error = 0;
232 #if DEBUG_TRANZPORT > 9
233 if(inflight > 1) printf("Inflight: %d\n", inflight);
236 if (_device_status == STATUS_ONLINE) {
242 last_write_error = 0;
244 pending = 3; // Give some time for the device to recover
246 #if DEBUG_TRANZPORT_BITS > 10
247 // Perhaps an online message indicates something
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];
256 #if DEBUG_TRANZPORT_BITS > 10
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]);
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]);
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]);
278 /* update whatever needs updating */
279 if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
282 /* still struggling with a good means of exerting flow control without having to create threads */
283 // pending = flush();
289 pending = --inflight; // we just did a whole bunch of writes so wait