diff options
Diffstat (limited to 'libs/surfaces/tranzport/init.cc')
-rw-r--r-- | libs/surfaces/tranzport/init.cc | 314 |
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; +} + |