Duh, the info stream is available here, so use it.
[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 <cstring>
10 #include <cerrno>
11 #include <cstdio>
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         
42         int fd = open(dev, mode);
43         int i;
44         char name[255];
45         
46         if (fd < 0) {
47                 if (errno != EACCES) {
48                         error << string_compose ("Unable to open \"%1\": %2", dev, strerror(errno)) << endmsg;
49                 }
50                 return -1;
51         }
52
53         /* placate valgrind */
54         name[0] = '\0';
55
56         if (ioctl (fd, EVIOCGNAME (sizeof(name)), name) < 0) {
57                 error << string_compose ("\"%1\": EVIOCGNAME failed: %2", dev, strerror(errno)) << endmsg;
58                 close (fd);
59                 return -1;
60         }
61
62         // it's the correct device if the prefix matches what we expect it to be:
63         for (i = 0; i < NUM_VALID_PREFIXES; ++i) {
64                 if (!strncasecmp (name, valid_prefix[i], strlen (valid_prefix[i]))) {
65                         return fd;
66                 }
67         }
68         
69         close (fd);
70         return -1;
71 }
72
73 int find_powermate(int mode)
74 {
75   char devname[256];
76   int i, r;
77
78   for(i=0; i<NUM_EVENT_DEVICES; i++){
79     sprintf(devname, "/dev/input/event%d", i);
80     r = open_powermate(devname, mode);
81     if(r >= 0)
82       return r;
83   }
84
85   return -1;
86 }
87
88 PowermateControlProtocol::PowermateControlProtocol (Session& s)
89         : ControlProtocol  (s, "powermate")
90 {
91 }
92
93 PowermateControlProtocol::~PowermateControlProtocol ()
94 {
95         set_active (false);
96 }
97
98 bool
99 PowermateControlProtocol::probe ()
100 {
101         int port = find_powermate( O_RDONLY ); 
102
103         if (port < 0) {
104                 if (errno == ENOENT) {
105                         info << "Powermate device not found; perhaps you have no powermate connected" << endmsg;
106                 } else {
107                         printf ("powermate: Opening of powermate failed - %s\n", strerror(errno));
108                 }
109                 return false;
110         }
111
112         close (port);
113         return true;
114 }
115
116 int
117 PowermateControlProtocol::set_active (bool inActivate)
118 {
119         if (inActivate != _active) {
120
121                 if (inActivate) {
122
123                         mPort = find_powermate(O_RDONLY);
124                         
125                         if ( mPort < 0 ) {
126                                 return -1;
127                         }
128                         
129                         if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) {
130                                 _active = true;
131                         } else {
132                                 return -1;
133                         }
134
135                         printf("Powermate Control Protocol activated\n");
136
137                 } else {
138                         pthread_cancel (mThread);
139                         close (mPort);
140                         _active = false;
141                         printf("Powermate Control Protocol deactivated\n");
142                 } 
143         }
144
145         return 0;
146 }
147
148 XMLNode&
149 PowermateControlProtocol::get_state () 
150 {
151         XMLNode* node = new XMLNode (X_("Protocol"));
152         node->add_property (X_("name"), _name);
153         return *node;
154 }
155
156 int
157 PowermateControlProtocol::set_state (const XMLNode& /*node*/)
158 {
159         return 0;
160 }
161
162
163 void*
164 PowermateControlProtocol::SerialThreadEntry (void* arg)
165 {
166         return static_cast<PowermateControlProtocol*>(arg)->SerialThread ();
167 }
168
169 #define BUFFER_SIZE 32
170
171 bool held = false;
172 bool skippingMarkers = false;
173
174 void
175 PowermateControlProtocol::ProcessEvent(struct input_event *ev)
176 {
177 #ifdef VERBOSE
178   fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n",
179           ev->type, ev->code, (int)ev->value);
180 #endif
181
182   switch(ev->type){
183   case EV_MSC:
184     printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value);
185     break;
186   case EV_REL:
187     if(ev->code != REL_DIAL)
188       fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code);
189     else{
190         if (held) {
191                 //click and hold to skip forward and back by markers
192                 skippingMarkers = true;;
193                 if (ev->value > 0)
194                         next_marker();
195                 else
196                         prev_marker();
197         } else {
198                 //scale the range so that we can go from +/-8x within 180 degrees, with less precision at the higher speeds 
199                 float speed = get_transport_speed();
200                 speed += (float)ev->value * 0.05;
201                 if (speed > 1.5 || speed < -1.5 )
202                         speed += ev->value;
203                 set_transport_speed( speed );
204         }
205     }
206     break;
207   case EV_KEY:
208     if(ev->code != BTN_0)
209       fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code);
210     else
211       if (ev->value)
212                 held = true;
213       else {
214                 held = false;
215                 if (skippingMarkers) {
216                         skippingMarkers = false;
217                 } else {
218                         if (get_transport_speed() == 0.0) {
219                                 set_transport_speed(1.0);
220                         } else {
221                                 set_transport_speed(0.0);
222                         }
223                 }
224         }
225     break;
226   }
227
228   fflush(stdout);
229 }
230
231 void*
232 PowermateControlProtocol::SerialThread ()
233 {
234   struct input_event ibuffer[BUFFER_SIZE];
235   int r, events, i;
236
237   while(1){
238     r = read(mPort, ibuffer, sizeof(struct input_event) * BUFFER_SIZE);
239     if( r > 0 ){
240                 events = r / sizeof(struct input_event);
241       for(i=0; i<events; i++)
242                 ProcessEvent(&ibuffer[i]);
243     }else{
244       fprintf(stderr, "read() failed: %s\n", strerror(errno));
245       return (void*) 0;
246     }
247   }
248
249         return (void*) 0;
250 }
251
252