Coding style. Fix a valgrind warning. Stop a close on a handle of -1.
[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                 printf ("powermate: Opening of powermate failed - %s\n", strerror(errno));
105                 return false;
106         }
107
108         close (port);
109         return true;
110 }
111
112 int
113 PowermateControlProtocol::set_active (bool inActivate)
114 {
115         if (inActivate != _active) {
116
117                 if (inActivate) {
118
119                         mPort = find_powermate(O_RDONLY);
120                         
121                         if ( mPort < 0 ) {
122                                 return -1;
123                         }
124                         
125                         if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) {
126                                 _active = true;
127                         } else {
128                                 return -1;
129                         }
130
131                         printf("Powermate Control Protocol activated\n");
132
133                 } else {
134                         pthread_cancel (mThread);
135                         close (mPort);
136                         _active = false;
137                         printf("Powermate Control Protocol deactivated\n");
138                 } 
139         }
140
141         return 0;
142 }
143
144 XMLNode&
145 PowermateControlProtocol::get_state () 
146 {
147         XMLNode* node = new XMLNode (X_("Protocol"));
148         node->add_property (X_("name"), _name);
149         return *node;
150 }
151
152 int
153 PowermateControlProtocol::set_state (const XMLNode& /*node*/)
154 {
155         return 0;
156 }
157
158
159 void*
160 PowermateControlProtocol::SerialThreadEntry (void* arg)
161 {
162         return static_cast<PowermateControlProtocol*>(arg)->SerialThread ();
163 }
164
165 #define BUFFER_SIZE 32
166
167 bool held = false;
168 bool skippingMarkers = false;
169
170 void
171 PowermateControlProtocol::ProcessEvent(struct input_event *ev)
172 {
173 #ifdef VERBOSE
174   fprintf(stderr, "type=0x%04x, code=0x%04x, value=%d\n",
175           ev->type, ev->code, (int)ev->value);
176 #endif
177
178   switch(ev->type){
179   case EV_MSC:
180     printf("The LED pulse settings were changed; code=0x%04x, value=0x%08x\n", ev->code, ev->value);
181     break;
182   case EV_REL:
183     if(ev->code != REL_DIAL)
184       fprintf(stderr, "Warning: unexpected rotation event; ev->code = 0x%04x\n", ev->code);
185     else{
186         if (held) {
187                 //click and hold to skip forward and back by markers
188                 skippingMarkers = true;;
189                 if (ev->value > 0)
190                         next_marker();
191                 else
192                         prev_marker();
193         } else {
194                 //scale the range so that we can go from +/-8x within 180 degrees, with less precision at the higher speeds 
195                 float speed = get_transport_speed();
196                 speed += (float)ev->value * 0.05;
197                 if (speed > 1.5 || speed < -1.5 )
198                         speed += ev->value;
199                 set_transport_speed( speed );
200         }
201     }
202     break;
203   case EV_KEY:
204     if(ev->code != BTN_0)
205       fprintf(stderr, "Warning: unexpected key event; ev->code = 0x%04x\n", ev->code);
206     else
207       if (ev->value)
208                 held = true;
209       else {
210                 held = false;
211                 if (skippingMarkers) {
212                         skippingMarkers = false;
213                 } else {
214                         if (get_transport_speed() == 0.0) {
215                                 set_transport_speed(1.0);
216                         } else {
217                                 set_transport_speed(0.0);
218                         }
219                 }
220         }
221     break;
222   }
223
224   fflush(stdout);
225 }
226
227 void*
228 PowermateControlProtocol::SerialThread ()
229 {
230   struct input_event ibuffer[BUFFER_SIZE];
231   int r, events, i;
232
233   while(1){
234     r = read(mPort, ibuffer, sizeof(struct input_event) * BUFFER_SIZE);
235     if( r > 0 ){
236                 events = r / sizeof(struct input_event);
237       for(i=0; i<events; i++)
238                 ProcessEvent(&ibuffer[i]);
239     }else{
240       fprintf(stderr, "read() failed: %s\n", strerror(errno));
241       return (void*) 0;
242     }
243   }
244
245         return (void*) 0;
246 }
247
248