2 * \brief gamepad handling implementation
3 * \author Sylvain Gaeremynck <sylvain.gaeremynck@parrot.fr>
6 * \warning Subject to completion
16 #include <linux/joystick.h>
18 #include <ardrone_api.h>
19 #include <VP_Os/vp_os_print.h>
27 char name[MAX_NAME_LENGTH];
28 char handlers[MAX_NAME_LENGTH];
31 extern int32_t MiscVar[];
33 static C_RESULT add_device(device_t* device, const int32_t id);
35 static C_RESULT parse_proc_input_devices(FILE* f, const int32_t id);
37 input_device_t gamepad = {
44 static int32_t joy_dev = 0;
46 input_device_t radioGP = {
54 input_device_t ps3pad = {
61 ///////////////////////////////
62 // RadioGP input functions //
63 ///////////////////////////////
64 C_RESULT open_radioGP(void)
66 C_RESULT res = C_FAIL;
68 FILE* f = fopen("/proc/bus/input/devices", "r");
72 res = parse_proc_input_devices( f, RADIO_GP_ID);
76 if( SUCCEED( res ) && strcmp(radioGP.name, "GreatPlanes")!=0)
78 char dev_path[20]="/dev/input/";
79 strcat(dev_path, radioGP.name);
80 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
93 C_RESULT update_radioGP(void)
95 static float32_t roll = 0, pitch = 0, gaz=0, yaw=0;
96 static bool_t refresh_values = FALSE;
98 static struct js_event js_e_buffer[64];
100 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
102 if( !res || (res < 0 && errno == EAGAIN) )
108 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
111 // Buffer decomposition in blocs (if the last is incomplete, it's ignored)
113 refresh_values = FALSE;
114 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
116 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
120 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
122 switch( js_e_buffer[idx].number )
125 ardrone_tool_set_ui_pad_start(js_e_buffer[idx].value);
128 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
131 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
133 case GP_SIDE_LEFT_DOWN :
134 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
136 case GP_SIDE_LEFT_UP :
137 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
142 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
144 refresh_values = TRUE;
145 switch( js_e_buffer[idx].number )
148 pitch = js_e_buffer[idx].value;
151 gaz = js_e_buffer[idx].value;
154 roll = js_e_buffer[idx].value;
159 yaw = js_e_buffer[idx].value;
166 {// TODO: default: ERROR (non-supported)
170 if(refresh_values)// Axis values to refresh
172 ardrone_at_set_progress_cmd( 1,
182 C_RESULT close_radioGP(void)
190 ///////////////////////////////
191 // GamePad input functions //
192 ///////////////////////////////
194 C_RESULT open_gamepad(void)
196 C_RESULT res = C_FAIL;
198 FILE* f = fopen("/proc/bus/input/devices", "r");
202 res = parse_proc_input_devices( f, GAMEPAD_LOGICTECH_ID);
206 if( SUCCEED( res ) && strcmp(gamepad.name, "Gamepad")!=0)
208 char dev_path[20]="/dev/input/";
209 strcat(dev_path, gamepad.name);
210 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
221 C_RESULT update_gamepad(void)
223 static int32_t x = 0, y = 0;
224 static bool_t refresh_values = FALSE;
226 static struct js_event js_e_buffer[64];
227 static int32_t start = 0;
228 input_state_t* input_state;
230 static int32_t theta_trim = 0;
231 static int32_t phi_trim = 0;
232 static int32_t yaw_trim = 0;
235 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
237 if( !res || (res < 0 && errno == EAGAIN) )
243 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
246 // Buffer decomposition in blocs (if the last is incomplete, it's ignored)
248 refresh_values = FALSE;
249 input_state = ardrone_tool_get_input_state();
250 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
252 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
256 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
258 switch( js_e_buffer[idx].number )
261 ardrone_tool_set_ui_pad_ag(js_e_buffer[idx].value);
264 ardrone_tool_set_ui_pad_ab(js_e_buffer[idx].value);
267 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
270 ardrone_tool_set_ui_pad_ah(js_e_buffer[idx].value);
273 if( js_e_buffer[idx].value )
277 if( input_state->r2 )
283 ardrone_tool_set_ui_pad_l1(1);
285 // ui_pad_yaw_trim( yaw_trim );
290 ardrone_tool_set_ui_pad_l1(0);
291 // ui_pad_yaw_trim( yaw_trim );
295 if( js_e_buffer[idx].value )
299 if( input_state->r2 )
305 ardrone_tool_set_ui_pad_r1(1);
307 // ui_pad_yaw_trim( yaw_trim );
312 ardrone_tool_set_ui_pad_r1(0);
313 // ui_pad_yaw_trim( yaw_trim );
317 ardrone_tool_set_ui_pad_l2(js_e_buffer[idx].value);
318 if( !js_e_buffer[idx].value )
320 ardrone_at_set_pmode( MiscVar[0] );
321 ardrone_at_set_ui_misc( MiscVar[0], MiscVar[1], MiscVar[2], MiscVar[3] );
325 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
326 if( !js_e_buffer[idx].value )
327 ardrone_at_set_flat_trim();
330 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
333 if( js_e_buffer[idx].value )
336 ardrone_tool_set_ui_pad_start( start );
344 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
346 refresh_values = TRUE;
347 switch( js_e_buffer[idx].number )
350 x = ( js_e_buffer[idx].value + 1 ) >> 15;
353 y = ( js_e_buffer[idx].value + 1 ) >> 15;
360 {// TODO: default: ERROR (non-supported)
364 if(refresh_values)// Axis values to refresh
370 if( input_state->r2 )
393 // We are triming so we don't want to update ardrone position
397 ardrone_tool_set_ui_pad_xy( x, y );
398 //ui_pad_phi_trim( phi_trim );
399 //ui_pad_theta_trim( theta_trim );
404 C_RESULT close_gamepad(void)
416 ///////////////////////////////
417 // Playstation 3 Gamepad input functions //
418 ///////////////////////////////
420 C_RESULT open_ps3pad(void)
422 PRINT("Searching PS3 Pad device ...\n");
424 C_RESULT res = C_FAIL;
426 FILE* f = fopen("/proc/bus/input/devices", "r");
430 res = parse_proc_input_devices( f, GAMEPAD_PLAYSTATION3_ID );
434 if( SUCCEED( res ) && strcmp(ps3pad.name, "PS3Gamepad")!=0)
436 char dev_path[20]="/dev/input/";
437 strcat(dev_path, ps3pad.name);
438 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
442 printf("Joydev %s ouvert\n",dev_path);
445 printf("Joydev %s pas ouvert\n",dev_path);
450 PRINT("PS3 Pad device not found.\n");
459 C_RESULT update_ps3pad(void)
462 static int32_t stick1LR = 0, stick1UD = 0 , stick2LR = 0 , stick2UD = 0;
463 static bool_t refresh_values = FALSE;
465 static struct js_event js_e_buffer[64];
466 static int32_t start = 0;
467 input_state_t* input_state;
469 static int center_x1=0;
470 static int center_y1=0;
471 static int center_x2=0;
472 static int center_y2=0;
474 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
477 if( !res || (res < 0 && errno == EAGAIN) )
485 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
490 refresh_values = FALSE;
491 input_state = ardrone_tool_get_input_state();
492 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
494 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
498 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
500 switch( js_e_buffer[idx].number )
502 case PS3BTN_LEFTARROW :
503 ardrone_tool_set_ui_pad_ag(js_e_buffer[idx].value);
505 case PS3BTN_DOWNARROW :
506 ardrone_tool_set_ui_pad_ab(js_e_buffer[idx].value);
508 case PS3BTN_RIGHTARROW :
509 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
511 case PS3BTN_UPARROW :
512 ardrone_tool_set_ui_pad_ah(js_e_buffer[idx].value);
515 ardrone_tool_set_ui_pad_l1(js_e_buffer[idx].value);
518 ardrone_tool_set_ui_pad_r1(js_e_buffer[idx].value);
521 ardrone_tool_set_ui_pad_l2(js_e_buffer[idx].value);
524 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
527 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
530 if( js_e_buffer[idx].value ) { start ^= 1; ardrone_tool_set_ui_pad_start( start ); }
533 /* Calibrate joystick */
534 /* center_x1 = stick1LR;
535 center_y1 = stick1UD;
536 center_x2 = stick2UD;
537 center_y2 = stick2LR;*/
543 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
545 refresh_values = TRUE;
546 switch( js_e_buffer[idx].number )
548 case PS3AXIS_STICK1_LR:
549 stick1LR = ( js_e_buffer[idx].value ) ;
551 case PS3AXIS_STICK1_UD:
552 stick1UD = ( js_e_buffer[idx].value ) ;
555 case PS3AXIS_STICK2_LR:
556 stick2LR = ( js_e_buffer[idx].value ) ;
558 case PS3AXIS_STICK2_UD:
559 stick2UD = ( js_e_buffer[idx].value ) ;
567 {// TODO: default: ERROR (non-supported)
571 if(refresh_values)// Axis values to refresh
573 ardrone_at_set_progress_cmd( 1,
574 /*roll*/(float)(stick1LR-center_x1)/32767.0f,
575 /*pitch*/(float)(stick1UD-center_y1)/32767.0f,
576 /*gaz*/-(float)(stick2UD-center_x2)/32767.0f,
577 /*yaw*/(float)(stick2LR-center_y2)/32767.0f );
586 C_RESULT close_ps3pad(void)
597 static int32_t make_id(device_t* device)
599 return ( (device->vendor << 16) & 0xffff0000) | (device->product & 0xffff);
602 static C_RESULT add_device(device_t* device, const int32_t id_wanted)
604 int32_t id = make_id(device);
606 if( id_wanted == GAMEPAD_LOGICTECH_ID && id == id_wanted)
608 PRINT("Input device %s found\n", device->name);
609 strncpy(gamepad.name, device->handlers, MAX_NAME_LENGTH);
613 if(id_wanted == RADIO_GP_ID && id==id_wanted)
615 PRINT("Input device %s found\n", device->name);
616 strncpy(radioGP.name, device->handlers, MAX_NAME_LENGTH);
620 if(id_wanted == GAMEPAD_PLAYSTATION3_ID && id==id_wanted)
622 PRINT("PS3 : Input device %s found\n", device->name);
623 strncpy(ps3pad.name, device->handlers, MAX_NAME_LENGTH);
634 /** simple /proc/bus/input/devices generic LL(1) parser **/
636 #define KW_MAX_LEN 64
655 value_type_t value_type;
656 int32_t value_offset;
659 static int current_c;
660 static int next_c; // look ahead buffer
662 static device_t current_device;
664 static const int separators[] = { ' ', ':', '=', '\"', '\n' };
665 static const int quote = '\"';
666 static const int eol = '\n';
668 static kw_tab_entry_t kw_tab[] = {
669 [KW_BUS] = { "Bus", INT, offsetof(device_t, bus) },
670 [KW_VENDOR] = { "Vendor", INT, offsetof(device_t, vendor) },
671 [KW_PRODUCT] = { "Product", INT, offsetof(device_t, product) },
672 [KW_VERSION] = { "Version", INT, offsetof(device_t, version) },
673 [KW_NAME] = { "Name", STRING, offsetof(device_t, name) },
674 [KW_HANDLERS] = { "Handlers", STRING, offsetof(device_t, handlers) }
677 static const char* handler_names[] = {
685 static bool_t is_separator(int c)
688 bool_t found = FALSE;
690 for( i = 0; i < sizeof separators && !found; i++ )
692 found = ( c == separators[i] );
698 static bool_t is_quote(int c)
703 static bool_t is_eol(int c)
708 static C_RESULT fetch_char(FILE* f)
710 C_RESULT res = C_FAIL;
720 // PRINT("current_c = %c, next_c = %c\n", current_c, next_c );
725 static C_RESULT parse_string(FILE* f, char* str, int32_t maxlen)
728 bool_t is_quoted = is_quote(current_c);
732 while( SUCCEED(fetch_char(f)) && ! ( is_separator(current_c) && is_quote(current_c) ) ) {
739 while( SUCCEED(fetch_char(f)) && !is_separator(current_c) ) {
746 // PRINT("parse_string: %s\n", str);
748 return is_eol( current_c ) ? C_FAIL : C_OK;
751 static C_RESULT parse_int(FILE* f, int32_t* i)
758 while( !is_separator(next_c) && SUCCEED(fetch_char(f)) && res == C_OK ) {
759 value = current_c - '0';
761 if (value > 9 || value < 0)
763 value = current_c - 'a' + 10;
764 res = (value > 0xF || value < 0xa) ? C_FAIL : C_OK;
774 static C_RESULT skip_line(FILE* f)
776 while( !is_eol(next_c) && SUCCEED(fetch_char(f)) );
781 static C_RESULT match_keyword( const char* keyword, keyword_t* kw )
784 C_RESULT res = C_FAIL;
786 for( i = 0; i < KW_MAX && res != C_OK; i++ )
788 res = ( strcmp( keyword, kw_tab[i].name ) == 0 ) ? C_OK : C_FAIL;
796 static C_RESULT match_handler( void )
799 bool_t found = FALSE;
801 while( !found && handler_names[i] != 0 )
803 found = strcmp( (char*)((char*)¤t_device + kw_tab[KW_HANDLERS].value_offset), handler_names[i] ) == 0;
810 strcpy(current_device.handlers, handler_names[i-1]);
813 return found ? C_OK : C_FAIL;
816 static C_RESULT parse_keyword( FILE* f, keyword_t kw )
820 while( is_separator(next_c) && SUCCEED(fetch_char(f)) );
822 switch( kw_tab[kw].value_type ) {
824 parse_int( f, (int32_t*)((char*)¤t_device + kw_tab[kw].value_offset) );
825 //PRINT("%s = %x\n", kw_tab[kw].name, *(int32_t*)((char*)¤t_device + kw_tab[kw].value_offset) );
829 parse_string( f, (char*)((char*)¤t_device + kw_tab[kw].value_offset), KW_MAX_LEN );
830 //PRINT("%s = %s\n", kw_tab[kw].name, (char*)((char*)¤t_device + kw_tab[kw].value_offset) );
841 static C_RESULT parse_I(FILE* f)
843 char keyword[KW_MAX_LEN];
845 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
847 while( !is_eol(next_c) ) {
850 parse_string( f, keyword, KW_MAX_LEN );
851 if( SUCCEED( match_keyword( keyword, &kw ) ) )
853 parse_keyword( f, kw );
860 static C_RESULT parse_N(FILE* f)
862 char keyword[KW_MAX_LEN];
864 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
866 while( !is_eol(next_c) ) {
869 parse_string( f, keyword, KW_MAX_LEN );
870 if( SUCCEED( match_keyword( keyword, &kw ) ) )
872 parse_keyword( f, kw );
880 static C_RESULT parse_H(FILE* f)
882 C_RESULT res = C_FAIL;
883 char keyword[KW_MAX_LEN];
885 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
887 while( !is_eol(next_c) ) {
888 parse_string( f, keyword, KW_MAX_LEN );
889 if( strcmp( keyword, kw_tab[KW_HANDLERS].name ) == 0 )
891 while( FAILED(res) && SUCCEED( parse_string(f,
892 (char*)((char*)¤t_device + kw_tab[KW_HANDLERS].value_offset),
895 res = match_handler();
903 static C_RESULT end_device(const int32_t id)
905 C_RESULT res = C_FAIL;
906 res=add_device(¤t_device, id);
907 vp_os_memset( ¤t_device, 0, sizeof(device_t) );
912 static C_RESULT parse_proc_input_devices(FILE* f, const int32_t id)
914 C_RESULT res = C_FAIL;
917 vp_os_memset( ¤t_device, 0, sizeof(device_t) );
919 while( res != C_OK && SUCCEED( fetch_char(f) ) )
923 case 'I': parse_I(f); break;
924 case 'N': parse_N(f); break;
925 case 'H': if( SUCCEED( parse_H(f) ) ) res = end_device(id); break;
929 default: skip_line(f); break;