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 input_device_t joystick = {
68 int current_joystick = JOYSTICK_DEVICE_MAX;
70 int32_t joystick_device_ids[JOYSTICK_DEVICE_MAX] = {
71 [JOYSTICK_DEVICE_SIDEWINDER] = 0x045e001b,
72 [JOYSTICK_DEVICE_CYBORG] = 0x06a30836,
75 int32_t joystick_table_buttons[JOYSTICK_DEVICE_MAX][JOYBTN_NUM] = {
76 [JOYSTICK_DEVICE_SIDEWINDER] = {
81 [JOYSTICK_DEVICE_CYBORG] = {
88 int32_t joystick_table_axis[JOYSTICK_DEVICE_MAX][JOYAXIS_NUM] = {
89 [JOYSTICK_DEVICE_SIDEWINDER] = {
95 [JOYSTICK_DEVICE_CYBORG] = {
102 ///////////////////////////////
103 // RadioGP input functions //
104 ///////////////////////////////
105 C_RESULT open_radioGP(void)
107 C_RESULT res = C_FAIL;
109 FILE* f = fopen("/proc/bus/input/devices", "r");
113 res = parse_proc_input_devices( f, RADIO_GP_ID);
117 if( SUCCEED( res ) && strcmp(radioGP.name, "GreatPlanes")!=0)
119 char dev_path[20]="/dev/input/";
120 strcat(dev_path, radioGP.name);
121 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
134 C_RESULT update_radioGP(void)
136 static float32_t roll = 0, pitch = 0, gaz=0, yaw=0;
137 static bool_t refresh_values = FALSE;
139 static struct js_event js_e_buffer[64];
141 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
143 if( !res || (res < 0 && errno == EAGAIN) )
149 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
152 // Buffer d�composition in blocs (if the last is incomplete, it's ignored)
154 refresh_values = FALSE;
155 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
157 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
161 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
163 switch( js_e_buffer[idx].number )
166 ardrone_tool_set_ui_pad_start(js_e_buffer[idx].value);
169 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
172 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
174 case GP_SIDE_LEFT_DOWN :
175 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
177 case GP_SIDE_LEFT_UP :
178 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
183 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
185 refresh_values = TRUE;
186 switch( js_e_buffer[idx].number )
189 pitch = js_e_buffer[idx].value;
192 gaz = js_e_buffer[idx].value;
195 roll = js_e_buffer[idx].value;
200 yaw = js_e_buffer[idx].value;
207 {// TODO: default: ERROR (non-supported)
211 if(refresh_values)// Axis values to refresh
213 ardrone_at_set_progress_cmd( 1,
223 C_RESULT close_radioGP(void)
231 ///////////////////////////////
232 // GamePad input functions //
233 ///////////////////////////////
235 C_RESULT open_gamepad(void)
237 C_RESULT res = C_FAIL;
239 FILE* f = fopen("/proc/bus/input/devices", "r");
243 res = parse_proc_input_devices( f, GAMEPAD_LOGICTECH_ID);
247 if( SUCCEED( res ) && strcmp(gamepad.name, "Gamepad")!=0)
249 char dev_path[20]="/dev/input/";
250 strcat(dev_path, gamepad.name);
251 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
262 C_RESULT update_gamepad(void)
264 static int32_t x = 0, y = 0;
265 static bool_t refresh_values = FALSE;
267 static struct js_event js_e_buffer[64];
268 static int32_t start = 0;
269 input_state_t* input_state;
271 static int32_t theta_trim = 0;
272 static int32_t phi_trim = 0;
273 static int32_t yaw_trim = 0;
276 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
278 if( !res || (res < 0 && errno == EAGAIN) )
284 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
287 // Buffer d�composition in blocs (if the last is incomplete, it's ignored)
289 refresh_values = FALSE;
290 input_state = ardrone_tool_get_input_state();
291 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
293 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
297 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
299 switch( js_e_buffer[idx].number )
302 ardrone_tool_set_ui_pad_ag(js_e_buffer[idx].value);
305 ardrone_tool_set_ui_pad_ab(js_e_buffer[idx].value);
308 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
311 ardrone_tool_set_ui_pad_ah(js_e_buffer[idx].value);
314 if( js_e_buffer[idx].value )
318 if( input_state->r2 )
324 ardrone_tool_set_ui_pad_l1(1);
326 ui_pad_yaw_trim( yaw_trim );
331 ardrone_tool_set_ui_pad_l1(0);
332 ui_pad_yaw_trim( yaw_trim );
336 if( js_e_buffer[idx].value )
340 if( input_state->r2 )
346 ardrone_tool_set_ui_pad_r1(1);
348 ui_pad_yaw_trim( yaw_trim );
353 ardrone_tool_set_ui_pad_r1(0);
354 ui_pad_yaw_trim( yaw_trim );
358 ardrone_tool_set_ui_pad_l2(js_e_buffer[idx].value);
359 if( !js_e_buffer[idx].value )
361 ardrone_at_set_pmode( MiscVar[0] );
362 ardrone_at_set_ui_misc( MiscVar[0], MiscVar[1], MiscVar[2], MiscVar[3] );
366 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
367 if( !js_e_buffer[idx].value )
368 ardrone_at_set_flat_trim();
371 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
374 if( js_e_buffer[idx].value )
377 ardrone_tool_set_ui_pad_start( start );
385 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
387 refresh_values = TRUE;
388 switch( js_e_buffer[idx].number )
391 x = ( js_e_buffer[idx].value + 1 ) >> 15;
394 y = ( js_e_buffer[idx].value + 1 ) >> 15;
401 {// TODO: default: ERROR (non-supported)
405 if(refresh_values)// Axis values to refresh
411 if( input_state->r2 )
434 // We are triming so we don't want to update ardrone position
438 ardrone_tool_set_ui_pad_xy( x, y );
439 ui_pad_phi_trim( phi_trim );
440 ui_pad_theta_trim( theta_trim );
445 C_RESULT close_gamepad(void)
452 ///////////////////////////////
453 // Joystick input functions //
454 ///////////////////////////////
456 C_RESULT open_joystick(void)
458 PRINT("Searching Joystick device ...\n");
459 C_RESULT res = C_FAIL;
462 for(device = 0 ; (device < JOYSTICK_DEVICE_MAX) && FAILED(res) ; device++)
464 FILE* f = fopen("/proc/bus/input/devices", "r");
468 res = parse_proc_input_devices( f, joystick_device_ids[device]);
472 if( SUCCEED( res ) && strcmp(joystick.name, "Joystick")!=0)
474 char dev_path[20]="/dev/input/";
475 strcat(dev_path, joystick.name);
476 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
480 printf("Joydev %s ouvert\n",dev_path);
484 printf("Joydev %s pas ouvert\n",dev_path);
489 PRINT("Joystick device not found.\n");
496 current_joystick = device - 1;
501 C_RESULT update_joystick(void)
503 static int32_t stick1LR = 0, stick1UD = 0, stick2LR = 0, stick2UD = 0;
504 static bool_t refresh_values = FALSE;
506 static struct js_event js_e_buffer[64];
507 static int32_t start = 0;
508 input_state_t* input_state;
510 static int center_x1=0;
511 static int center_y1=0;
512 static int center_x2=0;
513 static int center_y2=0;
515 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
517 if( !res || (res < 0 && errno == EAGAIN) )
525 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
530 refresh_values = FALSE;
531 input_state = ardrone_tool_get_input_state();
532 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
534 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
538 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
540 // printf("Button event : %d => %d\n", js_e_buffer[idx].number, js_e_buffer[idx].value);
542 if(js_e_buffer[idx].number == joystick_table_buttons[current_joystick][JOYBTN_START])
544 if( js_e_buffer[idx].value )
547 ardrone_tool_set_ui_pad_start( start );
550 else if(js_e_buffer[idx].number == joystick_table_buttons[current_joystick][JOYBTN_SELECT])
553 ardrone_tool_set_ui_pad_start( start );
554 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
557 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
559 // printf("Axes event : %d => %d\n", js_e_buffer[idx].number, js_e_buffer[idx].value);
560 refresh_values = TRUE;
561 if(js_e_buffer[idx].number == joystick_table_axis[current_joystick][JOYAXIS_ROLL])
562 stick1LR = ( js_e_buffer[idx].value ) ;
563 else if(js_e_buffer[idx].number == joystick_table_axis[current_joystick][JOYAXIS_PITCH])
564 stick1UD = ( js_e_buffer[idx].value ) ;
565 else if(js_e_buffer[idx].number == joystick_table_axis[current_joystick][JOYAXIS_YAW])
566 stick2LR = ( js_e_buffer[idx].value ) ;
567 else if(js_e_buffer[idx].number == joystick_table_axis[current_joystick][JOYAXIS_GAZ])
568 stick2UD = ( js_e_buffer[idx].value ) ;
572 // TODO: default: ERROR (non-supported)
576 if(refresh_values)// Axis values to refresh
578 int enable = ((stick1LR-center_x1) != 0) || ((stick1UD-center_y1) != 0) || ((stick2UD-center_x2) != 0) || ((stick2LR-center_y2) != 0);
579 ardrone_at_set_progress_cmd( enable,
580 /*roll*/(float)(stick1LR-center_x1)/32767.0f,
581 /*pitch*/(float)(stick1UD-center_y1)/32767.0f,
582 /*gaz*/-(float)(stick2UD-center_x2)/32767.0f,
583 /*yaw*/(float)(stick2LR-center_y2)/32767.0f );
588 C_RESULT close_joystick(void)
600 ///////////////////////////////
601 // Playstation 3 Gamepad input functions //
602 ///////////////////////////////
604 C_RESULT open_ps3pad(void)
606 PRINT("Searching PS3 Pad device ...\n");
608 C_RESULT res = C_FAIL;
610 FILE* f = fopen("/proc/bus/input/devices", "r");
614 res = parse_proc_input_devices( f, GAMEPAD_PLAYSTATION3_ID );
618 if( SUCCEED( res ) && strcmp(ps3pad.name, "PS3Gamepad")!=0)
620 char dev_path[20]="/dev/input/";
621 strcat(dev_path, ps3pad.name);
622 joy_dev = open(dev_path, O_NONBLOCK | O_RDONLY);
626 printf("Joydev %s ouvert\n",dev_path);
629 printf("Joydev %s pas ouvert\n",dev_path);
634 PRINT("PS3 Pad device not found.\n");
643 C_RESULT update_ps3pad(void)
646 static int32_t stick1LR = 0, stick1UD = 0 , stick2LR = 0 , stick2UD = 0;
647 static bool_t refresh_values = FALSE;
649 static struct js_event js_e_buffer[64];
650 static int32_t start = 0;
651 input_state_t* input_state;
653 static int center_x1=0;
654 static int center_y1=0;
655 static int center_x2=0;
656 static int center_y2=0;
658 res = read(joy_dev, js_e_buffer, sizeof(struct js_event) * 64);
661 if( !res || (res < 0 && errno == EAGAIN) )
669 if (res < (int) sizeof(struct js_event))// If non-complete bloc: ignored
674 refresh_values = FALSE;
675 input_state = ardrone_tool_get_input_state();
676 for (idx = 0; idx < res / sizeof(struct js_event); idx++)
678 if(js_e_buffer[idx].type & JS_EVENT_INIT )// If Init, the first values are ignored
682 else if(js_e_buffer[idx].type & JS_EVENT_BUTTON )// Event Button detected
684 switch( js_e_buffer[idx].number )
686 case PS3BTN_LEFTARROW :
687 ardrone_tool_set_ui_pad_ag(js_e_buffer[idx].value);
689 case PS3BTN_DOWNARROW :
690 ardrone_tool_set_ui_pad_ab(js_e_buffer[idx].value);
692 case PS3BTN_RIGHTARROW :
693 ardrone_tool_set_ui_pad_ad(js_e_buffer[idx].value);
695 case PS3BTN_UPARROW :
696 ardrone_tool_set_ui_pad_ah(js_e_buffer[idx].value);
699 ardrone_tool_set_ui_pad_l1(js_e_buffer[idx].value);
702 ardrone_tool_set_ui_pad_r1(js_e_buffer[idx].value);
705 ardrone_tool_set_ui_pad_l2(js_e_buffer[idx].value);
708 ardrone_tool_set_ui_pad_r2(js_e_buffer[idx].value);
711 ardrone_tool_set_ui_pad_select(js_e_buffer[idx].value);
714 if( js_e_buffer[idx].value ) { start ^= 1; ardrone_tool_set_ui_pad_start( start ); }
717 /* Calibrate joystick */
718 /* center_x1 = stick1LR;
719 center_y1 = stick1UD;
720 center_x2 = stick2UD;
721 center_y2 = stick2LR;*/
727 else if(js_e_buffer[idx].type & JS_EVENT_AXIS )// Event Axis detected
729 refresh_values = TRUE;
730 switch( js_e_buffer[idx].number )
732 case PS3AXIS_STICK1_LR:
733 stick1LR = ( js_e_buffer[idx].value ) ;
735 case PS3AXIS_STICK1_UD:
736 stick1UD = ( js_e_buffer[idx].value ) ;
739 case PS3AXIS_STICK2_LR:
740 stick2LR = ( js_e_buffer[idx].value ) ;
742 case PS3AXIS_STICK2_UD:
743 stick2UD = ( js_e_buffer[idx].value ) ;
751 {// TODO: default: ERROR (non-supported)
755 if(refresh_values)// Axis values to refresh
757 ardrone_at_set_progress_cmd( 1,
758 /*roll*/(float)(stick1LR-center_x1)/32767.0f,
759 /*pitch*/(float)(stick1UD-center_y1)/32767.0f,
760 /*gaz*/-(float)(stick2UD-center_x2)/32767.0f,
761 /*yaw*/(float)(stick2LR-center_y2)/32767.0f );
770 C_RESULT close_ps3pad(void)
781 static int32_t make_id(device_t* device)
783 return ( (device->vendor << 16) & 0xffff0000) | (device->product & 0xffff);
786 static C_RESULT add_device(device_t* device, const int32_t id_wanted)
788 int32_t id = make_id(device);
790 if( id_wanted == GAMEPAD_LOGICTECH_ID && id == id_wanted)
792 PRINT("Input device %s found\n", device->name);
793 strncpy(gamepad.name, device->handlers, MAX_NAME_LENGTH);
797 for(device_id = 0 ; device_id < JOYSTICK_DEVICE_MAX ; device_id++)
799 if( id_wanted == joystick_device_ids[device_id] && id == id_wanted)
801 PRINT("Input device %s found\n", device->name);
802 strncpy(joystick.name, device->handlers, MAX_NAME_LENGTH);
807 if(id_wanted == RADIO_GP_ID && id==id_wanted)
809 PRINT("Input device %s found\n", device->name);
810 strncpy(radioGP.name, device->handlers, MAX_NAME_LENGTH);
814 if(id_wanted == GAMEPAD_PLAYSTATION3_ID && id==id_wanted)
816 PRINT("PS3 : Input device %s found\n", device->name);
817 strncpy(ps3pad.name, device->handlers, MAX_NAME_LENGTH);
828 /** simple /proc/bus/input/devices generic LL(1) parser **/
830 #define KW_MAX_LEN 64
849 value_type_t value_type;
850 int32_t value_offset;
853 static int current_c;
854 static int next_c; // look ahead buffer
856 static device_t current_device;
858 static const int separators[] = { ' ', ':', '=', '\"', '\n' };
859 static const int quote = '\"';
860 static const int eol = '\n';
862 static kw_tab_entry_t kw_tab[] = {
863 [KW_BUS] = { "Bus", INT, offsetof(device_t, bus) },
864 [KW_VENDOR] = { "Vendor", INT, offsetof(device_t, vendor) },
865 [KW_PRODUCT] = { "Product", INT, offsetof(device_t, product) },
866 [KW_VERSION] = { "Version", INT, offsetof(device_t, version) },
867 [KW_NAME] = { "Name", STRING, offsetof(device_t, name) },
868 [KW_HANDLERS] = { "Handlers", STRING, offsetof(device_t, handlers) }
871 static const char* handler_names[] = {
879 static bool_t is_separator(int c)
882 bool_t found = FALSE;
884 for( i = 0; i < sizeof separators && !found; i++ )
886 found = ( c == separators[i] );
892 static bool_t is_quote(int c)
897 static bool_t is_eol(int c)
902 static C_RESULT fetch_char(FILE* f)
904 C_RESULT res = C_FAIL;
914 // PRINT("current_c = %c, next_c = %c\n", current_c, next_c );
919 static C_RESULT parse_string(FILE* f, char* str, int32_t maxlen)
922 bool_t is_quoted = is_quote(current_c);
926 while( SUCCEED(fetch_char(f)) && ! ( is_separator(current_c) && is_quote(current_c) ) ) {
933 while( SUCCEED(fetch_char(f)) && !is_separator(current_c) ) {
940 // PRINT("parse_string: %s\n", str);
942 return is_eol( current_c ) ? C_FAIL : C_OK;
945 static C_RESULT parse_int(FILE* f, int32_t* i)
952 while( !is_separator(next_c) && SUCCEED(fetch_char(f)) && res == C_OK ) {
953 value = current_c - '0';
955 if (value > 9 || value < 0)
957 value = current_c - 'a' + 10;
958 res = (value > 0xF || value < 0xa) ? C_FAIL : C_OK;
968 static C_RESULT skip_line(FILE* f)
970 while( !is_eol(next_c) && SUCCEED(fetch_char(f)) );
975 static C_RESULT match_keyword( const char* keyword, keyword_t* kw )
978 C_RESULT res = C_FAIL;
980 for( i = 0; i < KW_MAX && res != C_OK; i++ )
982 res = ( strcmp( keyword, kw_tab[i].name ) == 0 ) ? C_OK : C_FAIL;
990 static C_RESULT match_handler( void )
993 bool_t found = FALSE;
995 while( !found && handler_names[i] != 0 )
997 found = strcmp( (char*)((char*)¤t_device + kw_tab[KW_HANDLERS].value_offset), handler_names[i] ) == 0;
1004 strcpy(current_device.handlers, handler_names[i-1]);
1007 return found ? C_OK : C_FAIL;
1010 static C_RESULT parse_keyword( FILE* f, keyword_t kw )
1012 C_RESULT res = C_OK;
1014 while( is_separator(next_c) && SUCCEED(fetch_char(f)) );
1016 switch( kw_tab[kw].value_type ) {
1018 parse_int( f, (int32_t*)((char*)¤t_device + kw_tab[kw].value_offset) );
1019 //PRINT("%s = %x\n", kw_tab[kw].name, *(int32_t*)((char*)¤t_device + kw_tab[kw].value_offset) );
1023 parse_string( f, (char*)((char*)¤t_device + kw_tab[kw].value_offset), KW_MAX_LEN );
1024 //PRINT("%s = %s\n", kw_tab[kw].name, (char*)((char*)¤t_device + kw_tab[kw].value_offset) );
1035 static C_RESULT parse_I(FILE* f)
1037 char keyword[KW_MAX_LEN];
1039 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
1041 while( !is_eol(next_c) ) {
1044 parse_string( f, keyword, KW_MAX_LEN );
1045 if( SUCCEED( match_keyword( keyword, &kw ) ) )
1047 parse_keyword( f, kw );
1054 static C_RESULT parse_N(FILE* f)
1056 char keyword[KW_MAX_LEN];
1058 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
1060 while( !is_eol(next_c) ) {
1063 parse_string( f, keyword, KW_MAX_LEN );
1064 if( SUCCEED( match_keyword( keyword, &kw ) ) )
1066 parse_keyword( f, kw );
1074 static C_RESULT parse_H(FILE* f)
1076 C_RESULT res = C_FAIL;
1077 char keyword[KW_MAX_LEN];
1079 while( SUCCEED(fetch_char(f)) && is_separator(next_c) );
1081 while( !is_eol(next_c) ) {
1082 parse_string( f, keyword, KW_MAX_LEN );
1083 if( strcmp( keyword, kw_tab[KW_HANDLERS].name ) == 0 )
1085 while( FAILED(res) && SUCCEED( parse_string(f,
1086 (char*)((char*)¤t_device + kw_tab[KW_HANDLERS].value_offset),
1089 res = match_handler();
1097 static C_RESULT end_device(const int32_t id)
1099 C_RESULT res = C_FAIL;
1100 res=add_device(¤t_device, id);
1101 vp_os_memset( ¤t_device, 0, sizeof(device_t) );
1106 static C_RESULT parse_proc_input_devices(FILE* f, const int32_t id)
1108 C_RESULT res = C_FAIL;
1111 vp_os_memset( ¤t_device, 0, sizeof(device_t) );
1113 while( res != C_OK && SUCCEED( fetch_char(f) ) )
1117 case 'I': parse_I(f); break;
1118 case 'N': parse_N(f); break;
1119 case 'H': if( SUCCEED( parse_H(f) ) ) res = end_device(id); break;
1123 default: skip_line(f); break;