summaryrefslogtreecommitdiff
path: root/libs/surfaces/tranzport/init.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaces/tranzport/init.cc')
-rw-r--r--libs/surfaces/tranzport/init.cc314
1 files changed, 314 insertions, 0 deletions
diff --git a/libs/surfaces/tranzport/init.cc b/libs/surfaces/tranzport/init.cc
new file mode 100644
index 0000000000..94f85bdc56
--- /dev/null
+++ b/libs/surfaces/tranzport/init.cc
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2007 Michael Taht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <tranzport_common.h>
+#include <tranzport_control_protocol.h>
+
+using namespace ARDOUR;
+using namespace std;
+using namespace sigc;
+using namespace PBD;
+
+#include "i18n.h"
+
+#include <pbd/abstract_ui.cc>
+
+void*
+TranzportControlProtocol::_monitor_work (void* arg)
+{
+ return static_cast<TranzportControlProtocol*>(arg)->monitor_work ();
+}
+
+TranzportControlProtocol::~TranzportControlProtocol ()
+{
+ set_active (false);
+}
+
+int TranzportControlProtocol::rtpriority_set(int priority)
+{
+ struct sched_param rtparam;
+ int err;
+ char *a = (char*) alloca(4096*2); a[0] = 'a'; a[4096] = 'b';
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = priority; /* XXX should be relative to audio (JACK) thread */
+ // Note - try SCHED_RR with a low limit
+ // - we don't care if we can't write everything this ms
+ // and it will help if we lose the device
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ PBD::info << string_compose (_("%1: thread not running with realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
+ }
+ return 0;
+}
+
+// Running with realtime privs is bad when you have problems
+
+int TranzportControlProtocol::rtpriority_unset(int priority)
+{
+ struct sched_param rtparam;
+ int err;
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = priority;
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ PBD::info << string_compose (_("%1: can't stop realtime scheduling (%2)"), name(), strerror (errno)) << endmsg;
+ return 1;
+ }
+ PBD::info << string_compose (_("%1: realtime scheduling stopped (%2)"), name(), strerror (errno)) << endmsg;
+ return 0;
+}
+
+
+int
+TranzportControlProtocol::set_active (bool yn)
+{
+ if (yn != _active) {
+
+ if (yn) {
+
+ if (open ()) {
+ return -1;
+ }
+
+ if (pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _monitor_work, this) == 0) {
+ _active = true;
+#if TRANZPORT_THREADS
+ if (pthread_create_and_store (X_("tranzport read"), &thread_read, 0, _read_work, this) == 0) {
+ _active_read = true;
+ if (pthread_create_and_store (X_("tranzport write"), &thread_write, 0, _write_work, this) == 0) {
+ _active_write = true;
+ if (pthread_create_and_store (X_("tranzport process"), &thread_process, 0, _process_work, this) == 0) {
+ _active_process = true;
+ if (pthread_create_and_store (X_("tranzport timer"), &thread_timer, 0, _process_timer, this) == 0) {
+ _active_process = true;
+#endif
+ } else {
+ return -1;
+ }
+
+ } else {
+ cerr << "Begin tranzport shutdown\n";
+// if we got here due to an error, prettifying things will only make it worse
+// And with threads involved, oh boy...
+ if(!(last_write_error || last_read_error)) {
+ bling_mode = BlingExit;
+ enter_bling_mode();
+// thread FIXME - wait til all writes are done
+ for(int x = 0; (x < 20/MAX_TRANZPORT_INFLIGHT) && flush(); x++) { usleep(100); }
+ }
+#if TRANZPORT_THREADS
+ pthread_cancel_one (_thread_timer);
+ pthread_cancel_one (_thread_process);
+ pthread_cancel_one (_thread_read);
+ pthread_cancel_one (_thread_write);
+#endif
+ pthread_cancel_one (thread);
+
+ cerr << "Tranzport Thread dead\n";
+ close ();
+ _active = false;
+ cerr << "End tranzport shutdown\n";
+ }
+ }
+
+ return 0;
+}
+
+TranzportControlProtocol::TranzportControlProtocol (Session& s)
+ : ControlProtocol (s, X_("Tranzport"))
+{
+ /* tranzport controls one track at a time */
+
+ set_route_table_size (1);
+ timeout = 6000; // what is this for?
+ buttonmask = 0;
+ _datawheel = 0;
+ _device_status = STATUS_OFFLINE;
+ udev = 0;
+ current_track_id = 0;
+ last_where = max_frames;
+ wheel_mode = WheelTimeline;
+ wheel_shift_mode = WheelShiftGain;
+ wheel_increment = WheelIncrScreen;
+ bling_mode = BlingEnter;
+ last_notify_msg[0] = '\0';
+ last_notify = 0;
+ timerclear (&last_wheel_motion);
+ last_wheel_dir = 1;
+ last_track_gain = FLT_MAX;
+ last_write_error = 0;
+ last_read_error = 0;
+ display_mode = DisplayBling;
+ gain_fraction = 0.0;
+ invalidate();
+ screen_init();
+ lights_init();
+// FIXME: Wait til device comes online somewhere
+// About 3 reads is enough
+// enter_bling_mode();
+
+}
+
+void*
+TranzportControlProtocol::monitor_work ()
+{
+ uint8_t buf[8]; // = { 0,0,0,0,0,0,0,0 };
+ int val = 0, pending = 0;
+ bool first_time = true;
+ uint8_t offline = 0;
+
+ PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+ rtpriority_set();
+ inflight=0;
+ //int intro = 20;
+
+ // wait for the device to come online
+ invalidate();
+ screen_init();
+ lights_init();
+ update_state();
+// There has to be some specific command to enable the device!!
+// while((val = read(buf,DEFAULT_USB_TIMEOUT*5)) == -110 && pending !=0) {
+// pending = lights_flush(); // poke the device for a while
+// }
+
+// pending = 1;
+// while(intro-- > 0 && pending != 0) {
+// usleep(1000);
+// pending = screen_flush(); // kinder, gentler init
+// }
+// usleep(1000);
+// lights_on();
+// while(flush()!=0) ;
+// lights_off();
+ display_mode = DisplayNormal;
+
+ while (true) {
+
+ /* bInterval for this beastie is 10ms */
+
+ if (_device_status == STATUS_OFFLINE) {
+ first_time = true; offline++;
+#if TRANZPORT_DEBUG > 3
+ if(offline == 1) {
+ cerr << "Transport has gone offline\n";
+ }
+#endif
+ } else {
+ offline = 0; // hate writing this
+ }
+ unsigned int s = (last_write_error == 0) | ((last_read_error == 0) << 1);
+ switch (s) {
+ case 0: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 1: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 2: val = read(buf,DEFAULT_USB_TIMEOUT); break;
+ case 3: val = read(buf,DEFAULT_USB_TIMEOUT*2); break; // Hoo, boy, we're in trouble
+ default: break; // not reached
+ }
+
+#if DEBUG_TRANZPORT_BITS > 9
+ if(_device_status != STATUS_OFFLINE && _device_status != STATUS_ONLINE && _device_status != STATUS_OK) {
+ printf("The device has more status bits than off or online: %d\n",_device_status);
+ }
+#endif
+
+#if DEBUG_TRANZPORT_BITS > 99
+ if (val != 8) {
+ printf("val = %d errno = %d\n",val,errno);
+ buf[0] = buf[1] = buf[2] = buf[3] =
+ buf[4] = buf[5] = buf[6] = buf[7] =
+ buf[8] = 0;
+ }
+#endif
+
+ if(val == 8) {
+ last_write_error = 0;
+ process (buf);
+ }
+
+#if DEBUG_TRANZPORT > 9
+ if(inflight > 1) printf("Inflight: %d\n", inflight);
+#endif
+
+ if (_device_status == STATUS_ONLINE) {
+ if (first_time) {
+ invalidate();
+ lcd_clear ();
+ lights_off ();
+ first_time = false;
+ last_write_error = 0;
+ offline = 0;
+ pending = 3; // Give some time for the device to recover
+ }
+#if DEBUG_TRANZPORT_BITS > 10
+ // Perhaps an online message indicates something
+
+ if(_device_status != buf[1]) {
+ printf("WTF- val: %d, device status != buf! %d != %d \n",val,_device_status,buf[1]); _device_status = buf[1];
+ }
+#endif
+
+ }
+
+#if DEBUG_TRANZPORT_BITS > 10
+
+ if(val == 8) {
+
+ if(_device_status == STATUS_ONLINE) {
+ printf("ONLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+ if(_device_status == STATUS_OFFLINE) {
+ printf("OFFLINE : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+
+ if(_device_status == STATUS_OK) {
+ printf("OK : %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ buf[0],buf[1],buf[2], buf[3], buf[4], buf[5],buf[6],buf[7]);
+ }
+
+ }
+
+#endif
+
+ /* update whatever needs updating */
+ if(last_write_error == 0 && (_device_status == STATUS_ONLINE || _device_status == STATUS_OK)) {
+ update_state ();
+
+ /* still struggling with a good means of exerting flow control without having to create threads */
+ // pending = flush();
+
+ if(pending == 0) {
+ pending = flush();
+ } else {
+ if(inflight > 0) {
+ pending = --inflight; // we just did a whole bunch of writes so wait
+ } else {
+ pending = 0;
+ }
+ }
+ }
+ // pending = 0;
+ }
+ return (void*) 0;
+}
+