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 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;
57 // Running with realtime privs is bad when you have problems
59 int TranzportControlProtocol::rtpriority_unset(int priority)
61 struct sched_param rtparam;
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;
69 PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
75 TranzportControlProtocol::set_active (bool yn)
85 if (pthread_create_and_store (X_("tranzport monitor"), &thread, _monitor_work, this) == 0) {
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;
98 // thread FIXME - wait til all writes are done
99 for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
102 pthread_cancel_one (thread);
104 cerr << "Tranzport Thread dead\n";
107 cerr << "End tranzport shutdown\n";
114 TranzportControlProtocol::TranzportControlProtocol (Session& s)
115 : ControlProtocol (s, X_("Tranzport"))
117 /* tranzport controls one track at a time */
119 set_route_table_size (1);
120 timeout = 6000; // what is this for?
123 _device_status = STATUS_OFFLINE;
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';
133 timerclear (&last_wheel_motion);
135 last_track_gain = FLT_MAX;
136 last_write_error = 0;
138 display_mode = DisplayBling;
143 // FIXME: Wait til device comes online somewhere
144 // About 3 reads is enough
145 // enter_bling_mode();
150 TranzportControlProtocol::monitor_work ()
152 uint8_t buf[8]; // = { 0,0,0,0,0,0,0,0 };
153 int val = 0, pending = 0;
154 bool first_time = true;
157 register_thread (X_("Tranzport"));
158 pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
159 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
164 // wait for the device to come online
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
175 // while(intro-- > 0 && pending != 0) {
177 // pending = screen_flush(); // kinder, gentler init
181 // while(flush()!=0) ;
183 display_mode = DisplayNormal;
187 /* bInterval for this beastie is 10ms */
189 if (_device_status == STATUS_OFFLINE) {
190 first_time = true; offline++;
191 #if TRANZPORT_DEBUG > 3
193 cerr << "Transport has gone offline\n";
197 offline = 0; // hate writing this
199 unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
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
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);
214 #if DEBUG_TRANZPORT_BITS > 99
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] =
224 last_write_error = 0;
228 #if DEBUG_TRANZPORT > 9
229 if(inflight > 1) printf("Inflight: %d\n", inflight);
232 if (_device_status == STATUS_ONLINE) {
238 last_write_error = 0;
240 pending = 3; // Give some time for the device to recover
242 #if DEBUG_TRANZPORT_BITS > 10
243 // Perhaps an online message indicates something
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];
252 #if DEBUG_TRANZPORT_BITS > 10
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]);
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]);
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]);
274 /* update whatever needs updating */
275 if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
278 /* still struggling with a good means of exerting flow control without having to create threads */
279 // pending = flush();
285 pending = --inflight; // we just did a whole bunch of writes so wait