rollback to 3428, before the mysterious removal of libs/* at 3431/3432
[ardour.git] / libs / surfaces / powermate / powermate.cc
1 /*
2         powermate.cc
3         Ben Loftis
4         Created: 03/26/07 20:07:56
5 */
6
7
8 #include <linux/input.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14
15 #include <i18n.h>
16 #include <pbd/xml++.h>
17 #include <pbd/error.h>
18 #include <glibmm.h>
19
20 #include "powermate.h"
21
22 using namespace ARDOUR;
23 using namespace std;
24 using namespace sigc;
25 using namespace PBD;
26
27 #define NUM_VALID_PREFIXES 2
28
29 static const char *valid_prefix[NUM_VALID_PREFIXES] = {
30   "Griffin PowerMate",
31   "Griffin SoundKnob"
32 };
33
34 #define NUM_EVENT_DEVICES 16
35
36 int open_powermate(const char *dev, int mode)
37 {
38         if (!Glib::file_test (dev, Glib::FILE_TEST_EXISTS)) {
39                 return -1;
40         }
41         int fd = open(dev, mode);
42         int i;
43         char name[255];
44         
45         if(fd < 0){
46                 if (errno != EACCES) {
47                         error << string_compose ("Unable to open \"%1\": %2", dev, strerror(errno)) << endmsg;
48                 }
49                 return -1;
50         }
51
52   if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0){
53     error << string_compose ("\"%1\": EVIOCGNAME failed: %2", dev, strerror(errno)) << endmsg;
54     close(fd);
55     return -1;
56   }
57
58   // it's the correct device if the prefix matches what we expect it to be:
59   for(i=0; i<NUM_VALID_PREFIXES; i++)
60     if(!strncasecmp(name, valid_prefix[i], strlen(valid_prefix[i])))
61       return fd;
62
63   close(fd);
64   return -1;
65 }
66
67 int find_powermate(int mode)
68 {
69   char devname[256];
70   int i, r;
71
72   for(i=0; i<NUM_EVENT_DEVICES; i++){
73     sprintf(devname, "/dev/input/event%d", i);
74     r = open_powermate(devname, mode);
75     if(r >= 0)
76       return r;
77   }
78
79   return -1;
80 }
81
82 PowermateControlProtocol::PowermateControlProtocol (Session& s)
83         : ControlProtocol  (s, "powermate")
84 {
85 }
86
87 PowermateControlProtocol::~PowermateControlProtocol ()
88 {
89         set_active (false);
90 }
91
92 bool
93 PowermateControlProtocol::probe ()
94 {
95         int port = find_powermate( O_RDONLY ); 
96
97         if (port < 0) {
98                 printf ("powermate: Opening of powermate failed - %s\n", strerror(errno));
99                 close (port);
100                 return false;
101         }
102
103         close (port);
104         return true;
105 }
106
107 int
108 PowermateControlProtocol::set_active (bool inActivate)
109 {
110         if (inActivate != _active) {
111
112                 if (inActivate) {
113
114                         mPort = find_powermate(O_RDONLY);
115                         
116                         if ( mPort < 0 ) {
117                                 return -1;
118                         }
119                         
120                         if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) {
121                                 _active = true;
122                         } else {
123                                 return -1;
124                         }
125
126                         printf("Powermate Control Protocol activated\n");
127
128                 } else {
129                         pthread_cancel (mThread);
130                         close (mPort);
131                         _active = false;
132                         printf("Powermate Control Protocol deactivated\n");
133                 } 
134         }
135
136         return 0;
137 }
138
139 XMLNode&
140 PowermateControlProtocol::get_state () 
141 {
142         XMLNode* node = new XMLNode (X_("Protocol"));
143         node->add_property (X_("name"), _name);
144         return *node;
145 }
146
147 int
148 PowermateControlProtocol::set_state (const XMLNode& node)
149 {
150         return 0;
151 }
152
153
154 void*
155 PowermateControlProtocol::SerialThreadEntry (void* arg)
156 {
157         return static_cast<PowermateControlProtocol*>(arg)->SerialThread ();
158 }
159
160 #define BUFFER_SIZE 32
161
162 bool held = false;
163 bool skippingMarkers = false;
164
165 void
166 PowermateControlProtocol::ProcessEvent(struct input_event *ev)
167 {
168 #ifdef VERBOSE
169   fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n",
170           ev->type, ev->code, (int)ev->value);
171 #endif
172
173   switch(ev->type){
174   case EV_MSC:
175     printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value);
176     break;
177   case EV_REL:
178     if(ev->code != REL_DIAL)
179       fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code);
180     else{
181         if (held) {
182                 //click and hold to skip forward and back by markers
183                 skippingMarkers = true;;
184                 if (ev->value > 0)
185                         next_marker();
186                 else
187                         prev_marker();
188         } else {
189                 //scale the range so that we can go from +/-8x within 180 degrees, with less precision at the higher speeds 
190                 float speed = get_transport_speed();
191                 speed += (float)ev->value * 0.05;
192                 if (speed > 1.5 || speed < -1.5 )
193                         speed += ev->value;
194                 set_transport_speed( speed );
195         }
196     }
197     break;
198   case EV_KEY:
199     if(ev->code != BTN_0)
200       fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code);
201     else
202       if (ev->value)
203                 held = true;
204       else {
205                 held = false;
206                 if (skippingMarkers) {
207                         skippingMarkers = false;
208                 } else {
209                         if (get_transport_speed() == 0.0) {
210                                 set_transport_speed(1.0);
211                         } else {
212                                 set_transport_speed(0.0);
213                         }
214                 }
215         }
216     break;
217   }
218
219   fflush(stdout);
220 }
221
222 void*
223 PowermateControlProtocol::SerialThread ()
224 {
225   struct input_event ibuffer[BUFFER_SIZE];
226   int r, events, i;
227
228   while(1){
229     r = read(mPort, ibuffer, sizeof(struct input_event) * BUFFER_SIZE);
230     if( r > 0 ){
231                 events = r / sizeof(struct input_event);
232       for(i=0; i<events; i++)
233                 ProcessEvent(&ibuffer[i]);
234     }else{
235       fprintf(stderr, "read() failed: %s\n", strerror(errno));
236       return (void*) 0;
237     }
238   }
239
240         return (void*) 0;
241 }
242
243