Skip to content

Instantly share code, notes, and snippets.

@mp911de
Created September 1, 2014 10:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mp911de/968610d1ff9ce7db5c18 to your computer and use it in GitHub Desktop.
Save mp911de/968610d1ff9ce7db5c18 to your computer and use it in GitHub Desktop.
RaspiBoy
SUBSYSTEM=="input", ATTRS{name}=="retrogame", ENV{ID_INPUT_KEYBOARD}="1"
# Doom config file
# Format:
# variable value
# Misc settings
default_compatibility_level -1
menu_background 1
max_player_corpse 32
flashing_hom 0
demo_insurance 2
level_precache 0
demo_smoothturns 0
demo_smoothturnsfactor 6
# Files
wadfile_1 ""
wadfile_2 ""
dehfile_1 ""
dehfile_2 ""
# Game settings
default_skill 3
weapon_recoil 0
doom_weapon_toggles 1
player_bobbing 1
monsters_remember 1
monster_infighting 1
monster_backing 0
monster_avoid_hazards 1
monkeys 0
monster_friction 1
help_friends 1
allow_pushers 1
variable_friction 1
sts_always_red 1
sts_pct_always_gray 0
sts_traditional_keys 0
show_messages 1
autorun 0
# Compatibility settings
comp_zombie 0
comp_infcheat 0
comp_stairs 0
comp_telefrag 0
comp_dropoff 0
comp_falloff 0
comp_staylift 0
comp_doorstuck 0
comp_pursuit 0
comp_vile 0
comp_pain 0
comp_skull 0
comp_blazing 0
comp_doorlight 0
comp_god 0
comp_skymap 0
comp_floors 0
comp_model 0
comp_zerotags 0
comp_moveblock 0
comp_sound 0
comp_666 0
comp_soul 0
comp_maskedanim 0
# Sound settings
sound_card -1
music_card -1
pitched_sounds 0
samplerate 11025
sfx_volume 8
music_volume 8
mus_pause_opt 2
snd_channels 8
# Video settings
use_doublebuffer 1
screenblocks 0
usegamma 0
uncapped_framerate 1
filter_wall 1
filter_floor 1
filter_sprite 1
filter_z 1
filter_patch 1
filter_threshold 49152
sprite_edges 0
patch_edges 0
# Mouse settings
use_mouse 1
mouse_sensitivity_horiz 10
mouse_sensitivity_vert 10
mouseb_fire 0
mouseb_strafe 1
mouseb_forward 2
mouseb_backward -1
# Key bindings
key_right 0xae
key_left 0xac
key_up 0xad
key_down 0xaf
key_menu_right 0xae
key_menu_left 0xac
key_menu_up 0xad
key_menu_down 0xaf
key_menu_backspace 0x7f
key_menu_escape 0x1b
key_menu_enter 0xd
key_setup 0xc7
key_strafeleft 0x2c
key_straferight 0x2e
key_fire 0x20
key_use 0xb8
key_strafe 0x6e
key_speed 0x6d
key_savegame 0xbc
key_loadgame 0xbd
key_soundvolume 0xbe
key_hud 0xbf
key_quicksave 0xc0
key_endgame 0xc1
key_messages 0xc2
key_quickload 0xc3
key_quit 0xc4
key_gamma 0xd7
key_spy 0xd8
key_pause 0x9
key_autorun 0xba
key_chat 0x74
key_backspace 0x7f
key_enter 0xd
key_map 0xff
key_map_right 0xae
key_map_left 0xac
key_map_up 0xad
key_map_down 0xaf
key_map_zoomin 0x3d
key_map_zoomout 0x2d
key_map_gobig 0x30
key_map_follow 0x66
key_map_mark 0x6d
key_map_clear 0x63
key_map_grid 0x67
key_map_rotate 0x72
key_map_overlay 0x6f
key_reverse 0x2f
key_zoomin 0x3d
key_zoomout 0x2d
key_chatplayer1 0x67
key_chatplayer2 0x69
key_chatplayer3 0x62
key_chatplayer4 0x72
key_weapontoggle 0x30
key_weaponcycleup 0xb6
key_weaponcycledown 0x9d
key_weapon1 0x31
key_weapon2 0x32
key_weapon3 0x33
key_weapon4 0x34
key_weapon5 0x35
key_weapon6 0x36
key_weapon7 0x37
key_weapon8 0x38
key_weapon9 0x39
key_screenshot 0x2a
# Chat macros
chatmacro0 "No"
chatmacro1 "I'm ready to kick butt!"
chatmacro2 "I'm OK."
chatmacro3 "I'm not looking too good!"
chatmacro4 "Help!"
chatmacro5 "You suck!"
chatmacro6 "Next time, scumbag..."
chatmacro7 "Come here!"
chatmacro8 "I'll take care of it."
chatmacro9 "Yes"
# Automap settings
mapcolor_back 0xf7
mapcolor_grid 0x68
mapcolor_wall 0x17
mapcolor_fchg 0x37
mapcolor_cchg 0xd7
mapcolor_clsd 0xd0
mapcolor_rkey 0xaf
mapcolor_bkey 0xcc
mapcolor_ykey 0xe7
mapcolor_rdor 0xaf
mapcolor_bdor 0xcc
mapcolor_ydor 0xe7
mapcolor_tele 0x77
mapcolor_secr 0xfc
mapcolor_exit 0x0
mapcolor_unsn 0x68
mapcolor_flat 0x58
mapcolor_sprt 0x70
mapcolor_item 0xe7
mapcolor_hair 0xd0
mapcolor_sngl 0xd0
mapcolor_me 0x70
mapcolor_enemy 0xb1
mapcolor_frnd 0x70
map_secret_after 0
map_point_coord 0
automapmode 0x0
# Heads-up display settings
hudcolor_titl 5
hudcolor_xyco 3
hudcolor_mesg 6
hudcolor_chat 5
hudcolor_list 5
hud_msg_lines 1
hud_list_bgon 0
hud_distributed 0
health_red 25
health_yellow 50
health_green 100
armor_red 25
armor_yellow 50
armor_green 100
ammo_red 25
ammo_yellow 50
hud_active 2
hud_displayed 0
hud_nosecrets 0
# Weapon preferences
weapon_choice_1 6
weapon_choice_2 9
weapon_choice_3 4
weapon_choice_4 3
weapon_choice_5 2
weapon_choice_6 8
weapon_choice_7 5
weapon_choice_8 7
weapon_choice_9 1
# Music
mus_e1m1 "e1m1.mp3"
mus_e1m2 "e1m2.mp3"
mus_e1m3 "e1m3.mp3"
mus_e1m4 "e1m4.mp3"
mus_e1m5 "e1m5.mp3"
mus_e1m6 "e1m6.mp3"
mus_e1m7 "e1m7.mp3"
mus_e1m8 "e1m8.mp3"
mus_e1m9 "e1m9.mp3"
mus_e2m1 "e2m1.mp3"
mus_e2m2 "e2m2.mp3"
mus_e2m3 "e2m3.mp3"
mus_e2m4 "e2m4.mp3"
mus_e2m5 "e1m7.mp3"
mus_e2m6 "e2m6.mp3"
mus_e2m7 "e2m7.mp3"
mus_e2m8 "e2m8.mp3"
mus_e2m9 "e3m1.mp3"
mus_e3m1 "e3m1.mp3"
mus_e3m2 "e3m2.mp3"
mus_e3m3 "e3m3.mp3"
mus_e3m4 "e1m8.mp3"
mus_e3m5 "e1m7.mp3"
mus_e3m6 "e1m6.mp3"
mus_e3m7 "e2m7.mp3"
mus_e3m8 "e3m8.mp3"
mus_e3m9 "e1m9.mp3"
mus_inter "e2m3.mp3"
mus_intro "intro.mp3"
mus_bunny "bunny.mp3"
mus_victor "victor.mp3"
mus_introa "intro.mp3"
mus_runnin "runnin.mp3"
mus_stalks "stalks.mp3"
mus_countd "countd.mp3"
mus_betwee "betwee.mp3"
mus_doom "doom.mp3"
mus_the_da "the_da.mp3"
mus_shawn "shawn.mp3"
mus_ddtblu "ddtblu.mp3"
mus_in_cit "in_cit.mp3"
mus_dead "dead.mp3"
mus_stlks2 "stalks.mp3"
mus_theda2 "the_da.mp3"
mus_doom2 "doom.mp3"
mus_ddtbl2 "ddtblu.mp3"
mus_runni2 "runnin.mp3"
mus_dead2 "dead.mp3"
mus_stlks3 "stalks.mp3"
mus_romero "romero.mp3"
mus_shawn2 "shawn.mp3"
mus_messag "messag.mp3"
mus_count2 "countd.mp3"
mus_ddtbl3 "ddtblu.mp3"
mus_ampie "ampie.mp3"
mus_theda3 "the_da.mp3"
mus_adrian "adrian.mp3"
mus_messg2 "messag.mp3"
mus_romer2 "romero.mp3"
mus_tense "tense.mp3"
mus_shawn3 "shawn.mp3"
mus_openin "openin.mp3"
mus_evil "evil.mp3"
mus_ultima "ultima.mp3"
mus_read_m "read_m.mp3"
mus_dm2ttl "dm2ttl.mp3"
mus_dm2int "dm2int.mp3"
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
printf "My IP address is %s\n" "$_IP"
fi
/home/pi/Adafruit-Retrogame/retrogame &
exit 0
input_axis_threshold = "0.500000"
load_dummy_on_core_shutdown = "true"
fps_show = "false"
libretro_path = "/opt/retropie/emulatorcores/libretro-prboom/prboom_libretro.so"
rewind_enable = "false"
audio_sync = "true"
audio_block_frames = "0"
rewind_granularity = "1"
video_shader = "/opt/retropie/emulators/RetroArch/shader/snes_phosphor.glslp"
video_shader_enable = "false"
video_aspect_ratio = "1.330000"
video_windowed_fullscreen = "true"
autosave_interval = "0"
video_crop_overscan = "true"
video_scale_integer = "true"
video_threaded = "true"
video_shared_context = "false"
video_fullscreen = "true"
video_refresh_rate = "59.950001"
video_monitor_index = "0"
menu_driver = "rgui"
video_vsync = "true"
video_hard_sync = "false"
video_hard_sync_frames = "0"
video_black_frame_insertion = "false"
video_disable_composition = "false"
pause_nonactive = "false"
video_swap_interval = "1"
video_gpu_screenshot = "true"
video_rotation = "0"
screenshot_directory = "default"
aspect_ratio_index = "6"
audio_rate_control = "true"
audio_rate_control_delta = "0.005000"
audio_out_rate = "44100"
video_font_size = "40.000000"
video_font_enable = "true"
system_directory = "default"
audio_resampler = "sinc"
savefile_directory = "default"
savestate_directory = "default"
video_shader_dir = "default"
video_filter_dir = "default"
audio_filter_dir = "default"
content_directory = "default"
assets_directory = "default"
rgui_browser_directory = "default"
rgui_config_directory = "default"
rgui_show_start_screen = "false"
game_history_size = "100"
input_autodetect_enable = "true"
overlay_directory = "default"
input_overlay_enable = "false"
input_overlay_opacity = "0.700000"
input_overlay_scale = "1.000000"
gamma_correction = "false"
triple_buffering_enable = "false"
soft_filter_enable = "false"
flicker_filter_enable = "false"
flicker_filter_index = "0"
soft_filter_index = "0"
current_resolution_id = "0"
custom_viewport_width = "600"
custom_viewport_height = "480"
custom_viewport_x = "60"
custom_viewport_y = "0"
block_sram_overwrite = "false"
savestate_auto_index = "false"
savestate_auto_save = "false"
savestate_auto_load = "true"
fastforward_ratio = "-1.000000"
config_save_on_exit = "true"
sound_mode = "0"
state_slot = "0"
netplay_spectator_mode_enable = "false"
netplay_mode = "false"
netplay_ip_port = "0"
netplay_delay_frames = "0"
custom_bgm_enable = "false"
input_driver = "udev"
input_device_p1 = "0"
input_player1_joypad_index = "0"
input_libretro_device_p1 = "1"
input_player1_analog_dpad_mode = "0"
input_device_p2 = "0"
input_player2_joypad_index = "1"
input_libretro_device_p2 = "1"
input_player2_analog_dpad_mode = "0"
input_device_p3 = "0"
input_player3_joypad_index = "2"
input_libretro_device_p3 = "1"
input_player3_analog_dpad_mode = "0"
input_device_p4 = "0"
input_player4_joypad_index = "3"
input_libretro_device_p4 = "1"
input_player4_analog_dpad_mode = "0"
input_device_p5 = "0"
input_player5_joypad_index = "4"
input_libretro_device_p5 = "1"
input_player5_analog_dpad_mode = "0"
input_device_p6 = "0"
input_player6_joypad_index = "5"
input_libretro_device_p6 = "1"
input_player6_analog_dpad_mode = "0"
input_device_p7 = "0"
input_player7_joypad_index = "6"
input_libretro_device_p7 = "1"
input_player7_analog_dpad_mode = "0"
input_device_p8 = "0"
input_player8_joypad_index = "7"
input_libretro_device_p8 = "1"
input_player8_analog_dpad_mode = "0"
input_player1_b = "ralt"
input_player1_b_btn = "nul"
input_player1_b_axis = "nul"
input_player1_y = "pageup"
input_player1_y_btn = "nul"
input_player1_y_axis = "nul"
input_player1_select = "x"
input_player1_select_btn = "nul"
input_player1_select_axis = "nul"
input_player1_start = "enter"
input_player1_start_btn = "nul"
input_player1_start_axis = "nul"
input_player1_up = "up"
input_player1_up_btn = "nul"
input_player1_up_axis = "nul"
input_player1_down = "down"
input_player1_down_btn = "nul"
input_player1_down_axis = "nul"
input_player1_left = "left"
input_player1_left_btn = "nul"
input_player1_left_axis = "nul"
input_player1_right = "right"
input_player1_right_btn = "nul"
input_player1_right_axis = "nul"
input_player1_a = "rctrl"
input_player1_a_btn = "nul"
input_player1_a_axis = "nul"
input_player1_x = "pagedown"
input_player1_x_btn = "nul"
input_player1_x_axis = "nul"
input_player1_l = "q"
input_player1_l_btn = "nul"
input_player1_l_axis = "nul"
input_player1_r = "w"
input_player1_r_btn = "nul"
input_player1_r_axis = "nul"
input_player1_l2 = "nul"
input_player1_l2_btn = "nul"
input_player1_l2_axis = "nul"
input_player1_r2 = "nul"
input_player1_r2_btn = "nul"
input_player1_r2_axis = "nul"
input_player1_l3 = "nul"
input_player1_l3_btn = "nul"
input_player1_l3_axis = "nul"
input_player1_r3 = "nul"
input_player1_r3_btn = "nul"
input_player1_r3_axis = "nul"
input_player1_l_x_plus = "nul"
input_player1_l_x_plus_btn = "nul"
input_player1_l_x_plus_axis = "nul"
input_player1_l_x_minus = "nul"
input_player1_l_x_minus_btn = "nul"
input_player1_l_x_minus_axis = "nul"
input_player1_l_y_plus = "nul"
input_player1_l_y_plus_btn = "nul"
input_player1_l_y_plus_axis = "nul"
input_player1_l_y_minus = "nul"
input_player1_l_y_minus_btn = "nul"
input_player1_l_y_minus_axis = "nul"
input_player1_r_x_plus = "nul"
input_player1_r_x_plus_btn = "nul"
input_player1_r_x_plus_axis = "nul"
input_player1_r_x_minus = "nul"
input_player1_r_x_minus_btn = "nul"
input_player1_r_x_minus_axis = "nul"
input_player1_r_y_plus = "nul"
input_player1_r_y_plus_btn = "nul"
input_player1_r_y_plus_axis = "nul"
input_player1_r_y_minus = "nul"
input_player1_r_y_minus_btn = "nul"
input_player1_r_y_minus_axis = "nul"
input_player1_turbo = "nul"
input_player1_turbo_btn = "nul"
input_player1_turbo_axis = "nul"
input_toggle_fast_forward = "space"
input_toggle_fast_forward_btn = "nul"
input_toggle_fast_forward_axis = "nul"
input_hold_fast_forward = "l"
input_hold_fast_forward_btn = "nul"
input_hold_fast_forward_axis = "nul"
input_load_state = "f4"
input_load_state_btn = "nul"
input_load_state_axis = "nul"
input_save_state = "f2"
input_save_state_btn = "nul"
input_save_state_axis = "nul"
input_toggle_fullscreen = "f"
input_toggle_fullscreen_btn = "nul"
input_toggle_fullscreen_axis = "nul"
input_exit_emulator = "tab"
input_exit_emulator_btn = "nul"
input_exit_emulator_axis = "nul"
input_state_slot_increase = "f7"
input_state_slot_increase_btn = "nul"
input_state_slot_increase_axis = "nul"
input_state_slot_decrease = "f6"
input_state_slot_decrease_btn = "nul"
input_state_slot_decrease_axis = "nul"
input_rewind = "r"
input_rewind_btn = "nul"
input_rewind_axis = "nul"
input_movie_record_toggle = "o"
input_movie_record_toggle_btn = "nul"
input_movie_record_toggle_axis = "nul"
input_pause_toggle = "p"
input_pause_toggle_btn = "nul"
input_pause_toggle_axis = "nul"
input_frame_advance = "k"
input_frame_advance_btn = "nul"
input_frame_advance_axis = "nul"
input_reset = "h"
input_reset_btn = "nul"
input_reset_axis = "nul"
input_shader_next = "m"
input_shader_next_btn = "nul"
input_shader_next_axis = "nul"
input_shader_prev = "n"
input_shader_prev_btn = "nul"
input_shader_prev_axis = "nul"
input_cheat_index_plus = "y"
input_cheat_index_plus_btn = "nul"
input_cheat_index_plus_axis = "nul"
input_cheat_index_minus = "t"
input_cheat_index_minus_btn = "nul"
input_cheat_index_minus_axis = "nul"
input_cheat_toggle = "u"
input_cheat_toggle_btn = "nul"
input_cheat_toggle_axis = "nul"
input_screenshot = "f8"
input_screenshot_btn = "nul"
input_screenshot_axis = "nul"
input_audio_mute = "f9"
input_audio_mute_btn = "nul"
input_audio_mute_axis = "nul"
input_netplay_flip_players = "i"
input_netplay_flip_players_btn = "nul"
input_netplay_flip_players_axis = "nul"
input_slowmotion = "e"
input_slowmotion_btn = "nul"
input_slowmotion_axis = "nul"
input_enable_hotkey = "nul"
input_enable_hotkey_btn = "nul"
input_enable_hotkey_axis = "nul"
input_volume_up = "add"
input_volume_up_btn = "nul"
input_volume_up_axis = "nul"
input_volume_down = "subtract"
input_volume_down_btn = "nul"
input_volume_down_axis = "nul"
input_overlay_next = "nul"
input_overlay_next_btn = "nul"
input_overlay_next_axis = "nul"
input_disk_eject_toggle = "nul"
input_disk_eject_toggle_btn = "nul"
input_disk_eject_toggle_axis = "nul"
input_disk_next = "nul"
input_disk_next_btn = "nul"
input_disk_next_axis = "nul"
input_grab_mouse_toggle = "f11"
input_grab_mouse_toggle_btn = "nul"
input_grab_mouse_toggle_axis = "nul"
input_menu_toggle = "escape"
input_menu_toggle_btn = "nul"
input_menu_toggle_axis = "nul"
input_player2_b = "nul"
input_player2_b_btn = "nul"
input_player2_b_axis = "nul"
input_player2_y = "nul"
input_player2_y_btn = "nul"
input_player2_y_axis = "nul"
input_player2_select = "nul"
input_player2_select_btn = "nul"
input_player2_select_axis = "nul"
input_player2_start = "nul"
input_player2_start_btn = "nul"
input_player2_start_axis = "nul"
input_player2_up = "nul"
input_player2_up_btn = "nul"
input_player2_up_axis = "nul"
input_player2_down = "nul"
input_player2_down_btn = "nul"
input_player2_down_axis = "nul"
input_player2_left = "nul"
input_player2_left_btn = "nul"
input_player2_left_axis = "nul"
input_player2_right = "nul"
input_player2_right_btn = "nul"
input_player2_right_axis = "nul"
input_player2_a = "nul"
input_player2_a_btn = "nul"
input_player2_a_axis = "nul"
input_player2_x = "nul"
input_player2_x_btn = "nul"
input_player2_x_axis = "nul"
input_player2_l = "nul"
input_player2_l_btn = "nul"
input_player2_l_axis = "nul"
input_player2_r = "nul"
input_player2_r_btn = "nul"
input_player2_r_axis = "nul"
input_player2_l2 = "nul"
input_player2_l2_btn = "nul"
input_player2_l2_axis = "nul"
input_player2_r2 = "nul"
input_player2_r2_btn = "nul"
input_player2_r2_axis = "nul"
input_player2_l3 = "nul"
input_player2_l3_btn = "nul"
input_player2_l3_axis = "nul"
input_player2_r3 = "nul"
input_player2_r3_btn = "nul"
input_player2_r3_axis = "nul"
input_player2_l_x_plus = "nul"
input_player2_l_x_plus_btn = "nul"
input_player2_l_x_plus_axis = "nul"
input_player2_l_x_minus = "nul"
input_player2_l_x_minus_btn = "nul"
input_player2_l_x_minus_axis = "nul"
input_player2_l_y_plus = "nul"
input_player2_l_y_plus_btn = "nul"
input_player2_l_y_plus_axis = "nul"
input_player2_l_y_minus = "nul"
input_player2_l_y_minus_btn = "nul"
input_player2_l_y_minus_axis = "nul"
input_player2_r_x_plus = "nul"
input_player2_r_x_plus_btn = "nul"
input_player2_r_x_plus_axis = "nul"
input_player2_r_x_minus = "nul"
input_player2_r_x_minus_btn = "nul"
input_player2_r_x_minus_axis = "nul"
input_player2_r_y_plus = "nul"
input_player2_r_y_plus_btn = "nul"
input_player2_r_y_plus_axis = "nul"
input_player2_r_y_minus = "nul"
input_player2_r_y_minus_btn = "nul"
input_player2_r_y_minus_axis = "nul"
input_player2_turbo = "nul"
input_player2_turbo_btn = "nul"
input_player2_turbo_axis = "nul"
input_player3_b = "nul"
input_player3_b_btn = "nul"
input_player3_b_axis = "nul"
input_player3_y = "nul"
input_player3_y_btn = "nul"
input_player3_y_axis = "nul"
input_player3_select = "nul"
input_player3_select_btn = "nul"
input_player3_select_axis = "nul"
input_player3_start = "nul"
input_player3_start_btn = "nul"
input_player3_start_axis = "nul"
input_player3_up = "nul"
input_player3_up_btn = "nul"
input_player3_up_axis = "nul"
input_player3_down = "nul"
input_player3_down_btn = "nul"
input_player3_down_axis = "nul"
input_player3_left = "nul"
input_player3_left_btn = "nul"
input_player3_left_axis = "nul"
input_player3_right = "nul"
input_player3_right_btn = "nul"
input_player3_right_axis = "nul"
input_player3_a = "nul"
input_player3_a_btn = "nul"
input_player3_a_axis = "nul"
input_player3_x = "nul"
input_player3_x_btn = "nul"
input_player3_x_axis = "nul"
input_player3_l = "nul"
input_player3_l_btn = "nul"
input_player3_l_axis = "nul"
input_player3_r = "nul"
input_player3_r_btn = "nul"
input_player3_r_axis = "nul"
input_player3_l2 = "nul"
input_player3_l2_btn = "nul"
input_player3_l2_axis = "nul"
input_player3_r2 = "nul"
input_player3_r2_btn = "nul"
input_player3_r2_axis = "nul"
input_player3_l3 = "nul"
input_player3_l3_btn = "nul"
input_player3_l3_axis = "nul"
input_player3_r3 = "nul"
input_player3_r3_btn = "nul"
input_player3_r3_axis = "nul"
input_player3_l_x_plus = "nul"
input_player3_l_x_plus_btn = "nul"
input_player3_l_x_plus_axis = "nul"
input_player3_l_x_minus = "nul"
input_player3_l_x_minus_btn = "nul"
input_player3_l_x_minus_axis = "nul"
input_player3_l_y_plus = "nul"
input_player3_l_y_plus_btn = "nul"
input_player3_l_y_plus_axis = "nul"
input_player3_l_y_minus = "nul"
input_player3_l_y_minus_btn = "nul"
input_player3_l_y_minus_axis = "nul"
input_player3_r_x_plus = "nul"
input_player3_r_x_plus_btn = "nul"
input_player3_r_x_plus_axis = "nul"
input_player3_r_x_minus = "nul"
input_player3_r_x_minus_btn = "nul"
input_player3_r_x_minus_axis = "nul"
input_player3_r_y_plus = "nul"
input_player3_r_y_plus_btn = "nul"
input_player3_r_y_plus_axis = "nul"
input_player3_r_y_minus = "nul"
input_player3_r_y_minus_btn = "nul"
input_player3_r_y_minus_axis = "nul"
input_player3_turbo = "nul"
input_player3_turbo_btn = "nul"
input_player3_turbo_axis = "nul"
input_player4_b = "nul"
input_player4_b_btn = "nul"
input_player4_b_axis = "nul"
input_player4_y = "nul"
input_player4_y_btn = "nul"
input_player4_y_axis = "nul"
input_player4_select = "nul"
input_player4_select_btn = "nul"
input_player4_select_axis = "nul"
input_player4_start = "nul"
input_player4_start_btn = "nul"
input_player4_start_axis = "nul"
input_player4_up = "nul"
input_player4_up_btn = "nul"
input_player4_up_axis = "nul"
input_player4_down = "nul"
input_player4_down_btn = "nul"
input_player4_down_axis = "nul"
input_player4_left = "nul"
input_player4_left_btn = "nul"
input_player4_left_axis = "nul"
input_player4_right = "nul"
input_player4_right_btn = "nul"
input_player4_right_axis = "nul"
input_player4_a = "nul"
input_player4_a_btn = "nul"
input_player4_a_axis = "nul"
input_player4_x = "nul"
input_player4_x_btn = "nul"
input_player4_x_axis = "nul"
input_player4_l = "nul"
input_player4_l_btn = "nul"
input_player4_l_axis = "nul"
input_player4_r = "nul"
input_player4_r_btn = "nul"
input_player4_r_axis = "nul"
input_player4_l2 = "nul"
input_player4_l2_btn = "nul"
input_player4_l2_axis = "nul"
input_player4_r2 = "nul"
input_player4_r2_btn = "nul"
input_player4_r2_axis = "nul"
input_player4_l3 = "nul"
input_player4_l3_btn = "nul"
input_player4_l3_axis = "nul"
input_player4_r3 = "nul"
input_player4_r3_btn = "nul"
input_player4_r3_axis = "nul"
input_player4_l_x_plus = "nul"
input_player4_l_x_plus_btn = "nul"
input_player4_l_x_plus_axis = "nul"
input_player4_l_x_minus = "nul"
input_player4_l_x_minus_btn = "nul"
input_player4_l_x_minus_axis = "nul"
input_player4_l_y_plus = "nul"
input_player4_l_y_plus_btn = "nul"
input_player4_l_y_plus_axis = "nul"
input_player4_l_y_minus = "nul"
input_player4_l_y_minus_btn = "nul"
input_player4_l_y_minus_axis = "nul"
input_player4_r_x_plus = "nul"
input_player4_r_x_plus_btn = "nul"
input_player4_r_x_plus_axis = "nul"
input_player4_r_x_minus = "nul"
input_player4_r_x_minus_btn = "nul"
input_player4_r_x_minus_axis = "nul"
input_player4_r_y_plus = "nul"
input_player4_r_y_plus_btn = "nul"
input_player4_r_y_plus_axis = "nul"
input_player4_r_y_minus = "nul"
input_player4_r_y_minus_btn = "nul"
input_player4_r_y_minus_axis = "nul"
input_player4_turbo = "nul"
input_player4_turbo_btn = "nul"
input_player4_turbo_axis = "nul"
input_player5_b = "nul"
input_player5_b_btn = "nul"
input_player5_b_axis = "nul"
input_player5_y = "nul"
input_player5_y_btn = "nul"
input_player5_y_axis = "nul"
input_player5_select = "nul"
input_player5_select_btn = "nul"
input_player5_select_axis = "nul"
input_player5_start = "nul"
input_player5_start_btn = "nul"
input_player5_start_axis = "nul"
input_player5_up = "nul"
input_player5_up_btn = "nul"
input_player5_up_axis = "nul"
input_player5_down = "nul"
input_player5_down_btn = "nul"
input_player5_down_axis = "nul"
input_player5_left = "nul"
input_player5_left_btn = "nul"
input_player5_left_axis = "nul"
input_player5_right = "nul"
input_player5_right_btn = "nul"
input_player5_right_axis = "nul"
input_player5_a = "nul"
input_player5_a_btn = "nul"
input_player5_a_axis = "nul"
input_player5_x = "nul"
input_player5_x_btn = "nul"
input_player5_x_axis = "nul"
input_player5_l = "nul"
input_player5_l_btn = "nul"
input_player5_l_axis = "nul"
input_player5_r = "nul"
input_player5_r_btn = "nul"
input_player5_r_axis = "nul"
input_player5_l2 = "nul"
input_player5_l2_btn = "nul"
input_player5_l2_axis = "nul"
input_player5_r2 = "nul"
input_player5_r2_btn = "nul"
input_player5_r2_axis = "nul"
input_player5_l3 = "nul"
input_player5_l3_btn = "nul"
input_player5_l3_axis = "nul"
input_player5_r3 = "nul"
input_player5_r3_btn = "nul"
input_player5_r3_axis = "nul"
input_player5_l_x_plus = "nul"
input_player5_l_x_plus_btn = "nul"
input_player5_l_x_plus_axis = "nul"
input_player5_l_x_minus = "nul"
input_player5_l_x_minus_btn = "nul"
input_player5_l_x_minus_axis = "nul"
input_player5_l_y_plus = "nul"
input_player5_l_y_plus_btn = "nul"
input_player5_l_y_plus_axis = "nul"
input_player5_l_y_minus = "nul"
input_player5_l_y_minus_btn = "nul"
input_player5_l_y_minus_axis = "nul"
input_player5_r_x_plus = "nul"
input_player5_r_x_plus_btn = "nul"
input_player5_r_x_plus_axis = "nul"
input_player5_r_x_minus = "nul"
input_player5_r_x_minus_btn = "nul"
input_player5_r_x_minus_axis = "nul"
input_player5_r_y_plus = "nul"
input_player5_r_y_plus_btn = "nul"
input_player5_r_y_plus_axis = "nul"
input_player5_r_y_minus = "nul"
input_player5_r_y_minus_btn = "nul"
input_player5_r_y_minus_axis = "nul"
input_player5_turbo = "nul"
input_player5_turbo_btn = "nul"
input_player5_turbo_axis = "nul"
input_player6_b = "nul"
input_player6_b_btn = "nul"
input_player6_b_axis = "nul"
input_player6_y = "nul"
input_player6_y_btn = "nul"
input_player6_y_axis = "nul"
input_player6_select = "nul"
input_player6_select_btn = "nul"
input_player6_select_axis = "nul"
input_player6_start = "nul"
input_player6_start_btn = "nul"
input_player6_start_axis = "nul"
input_player6_up = "nul"
input_player6_up_btn = "nul"
input_player6_up_axis = "nul"
input_player6_down = "nul"
input_player6_down_btn = "nul"
input_player6_down_axis = "nul"
input_player6_left = "nul"
input_player6_left_btn = "nul"
input_player6_left_axis = "nul"
input_player6_right = "nul"
input_player6_right_btn = "nul"
input_player6_right_axis = "nul"
input_player6_a = "nul"
input_player6_a_btn = "nul"
input_player6_a_axis = "nul"
input_player6_x = "nul"
input_player6_x_btn = "nul"
input_player6_x_axis = "nul"
input_player6_l = "nul"
input_player6_l_btn = "nul"
input_player6_l_axis = "nul"
input_player6_r = "nul"
input_player6_r_btn = "nul"
input_player6_r_axis = "nul"
input_player6_l2 = "nul"
input_player6_l2_btn = "nul"
input_player6_l2_axis = "nul"
input_player6_r2 = "nul"
input_player6_r2_btn = "nul"
input_player6_r2_axis = "nul"
input_player6_l3 = "nul"
input_player6_l3_btn = "nul"
input_player6_l3_axis = "nul"
input_player6_r3 = "nul"
input_player6_r3_btn = "nul"
input_player6_r3_axis = "nul"
input_player6_l_x_plus = "nul"
input_player6_l_x_plus_btn = "nul"
input_player6_l_x_plus_axis = "nul"
input_player6_l_x_minus = "nul"
input_player6_l_x_minus_btn = "nul"
input_player6_l_x_minus_axis = "nul"
input_player6_l_y_plus = "nul"
input_player6_l_y_plus_btn = "nul"
input_player6_l_y_plus_axis = "nul"
input_player6_l_y_minus = "nul"
input_player6_l_y_minus_btn = "nul"
input_player6_l_y_minus_axis = "nul"
input_player6_r_x_plus = "nul"
input_player6_r_x_plus_btn = "nul"
input_player6_r_x_plus_axis = "nul"
input_player6_r_x_minus = "nul"
input_player6_r_x_minus_btn = "nul"
input_player6_r_x_minus_axis = "nul"
input_player6_r_y_plus = "nul"
input_player6_r_y_plus_btn = "nul"
input_player6_r_y_plus_axis = "nul"
input_player6_r_y_minus = "nul"
input_player6_r_y_minus_btn = "nul"
input_player6_r_y_minus_axis = "nul"
input_player6_turbo = "nul"
input_player6_turbo_btn = "nul"
input_player6_turbo_axis = "nul"
input_player7_b = "nul"
input_player7_b_btn = "nul"
input_player7_b_axis = "nul"
input_player7_y = "nul"
input_player7_y_btn = "nul"
input_player7_y_axis = "nul"
input_player7_select = "nul"
input_player7_select_btn = "nul"
input_player7_select_axis = "nul"
input_player7_start = "nul"
input_player7_start_btn = "nul"
input_player7_start_axis = "nul"
input_player7_up = "nul"
input_player7_up_btn = "nul"
input_player7_up_axis = "nul"
input_player7_down = "nul"
input_player7_down_btn = "nul"
input_player7_down_axis = "nul"
input_player7_left = "nul"
input_player7_left_btn = "nul"
input_player7_left_axis = "nul"
input_player7_right = "nul"
input_player7_right_btn = "nul"
input_player7_right_axis = "nul"
input_player7_a = "nul"
input_player7_a_btn = "nul"
input_player7_a_axis = "nul"
input_player7_x = "nul"
input_player7_x_btn = "nul"
input_player7_x_axis = "nul"
input_player7_l = "nul"
input_player7_l_btn = "nul"
input_player7_l_axis = "nul"
input_player7_r = "nul"
input_player7_r_btn = "nul"
input_player7_r_axis = "nul"
input_player7_l2 = "nul"
input_player7_l2_btn = "nul"
input_player7_l2_axis = "nul"
input_player7_r2 = "nul"
input_player7_r2_btn = "nul"
input_player7_r2_axis = "nul"
input_player7_l3 = "nul"
input_player7_l3_btn = "nul"
input_player7_l3_axis = "nul"
input_player7_r3 = "nul"
input_player7_r3_btn = "nul"
input_player7_r3_axis = "nul"
input_player7_l_x_plus = "nul"
input_player7_l_x_plus_btn = "nul"
input_player7_l_x_plus_axis = "nul"
input_player7_l_x_minus = "nul"
input_player7_l_x_minus_btn = "nul"
input_player7_l_x_minus_axis = "nul"
input_player7_l_y_plus = "nul"
input_player7_l_y_plus_btn = "nul"
input_player7_l_y_plus_axis = "nul"
input_player7_l_y_minus = "nul"
input_player7_l_y_minus_btn = "nul"
input_player7_l_y_minus_axis = "nul"
input_player7_r_x_plus = "nul"
input_player7_r_x_plus_btn = "nul"
input_player7_r_x_plus_axis = "nul"
input_player7_r_x_minus = "nul"
input_player7_r_x_minus_btn = "nul"
input_player7_r_x_minus_axis = "nul"
input_player7_r_y_plus = "nul"
input_player7_r_y_plus_btn = "nul"
input_player7_r_y_plus_axis = "nul"
input_player7_r_y_minus = "nul"
input_player7_r_y_minus_btn = "nul"
input_player7_r_y_minus_axis = "nul"
input_player7_turbo = "nul"
input_player7_turbo_btn = "nul"
input_player7_turbo_axis = "nul"
input_player8_b = "nul"
input_player8_b_btn = "nul"
input_player8_b_axis = "nul"
input_player8_y = "nul"
input_player8_y_btn = "nul"
input_player8_y_axis = "nul"
input_player8_select = "nul"
input_player8_select_btn = "nul"
input_player8_select_axis = "nul"
input_player8_start = "nul"
input_player8_start_btn = "nul"
input_player8_start_axis = "nul"
input_player8_up = "nul"
input_player8_up_btn = "nul"
input_player8_up_axis = "nul"
input_player8_down = "nul"
input_player8_down_btn = "nul"
input_player8_down_axis = "nul"
input_player8_left = "nul"
input_player8_left_btn = "nul"
input_player8_left_axis = "nul"
input_player8_right = "nul"
input_player8_right_btn = "nul"
input_player8_right_axis = "nul"
input_player8_a = "nul"
input_player8_a_btn = "nul"
input_player8_a_axis = "nul"
input_player8_x = "nul"
input_player8_x_btn = "nul"
input_player8_x_axis = "nul"
input_player8_l = "nul"
input_player8_l_btn = "nul"
input_player8_l_axis = "nul"
input_player8_r = "nul"
input_player8_r_btn = "nul"
input_player8_r_axis = "nul"
input_player8_l2 = "nul"
input_player8_l2_btn = "nul"
input_player8_l2_axis = "nul"
input_player8_r2 = "nul"
input_player8_r2_btn = "nul"
input_player8_r2_axis = "nul"
input_player8_l3 = "nul"
input_player8_l3_btn = "nul"
input_player8_l3_axis = "nul"
input_player8_r3 = "nul"
input_player8_r3_btn = "nul"
input_player8_r3_axis = "nul"
input_player8_l_x_plus = "nul"
input_player8_l_x_plus_btn = "nul"
input_player8_l_x_plus_axis = "nul"
input_player8_l_x_minus = "nul"
input_player8_l_x_minus_btn = "nul"
input_player8_l_x_minus_axis = "nul"
input_player8_l_y_plus = "nul"
input_player8_l_y_plus_btn = "nul"
input_player8_l_y_plus_axis = "nul"
input_player8_l_y_minus = "nul"
input_player8_l_y_minus_btn = "nul"
input_player8_l_y_minus_axis = "nul"
input_player8_r_x_plus = "nul"
input_player8_r_x_plus_btn = "nul"
input_player8_r_x_plus_axis = "nul"
input_player8_r_x_minus = "nul"
input_player8_r_x_minus_btn = "nul"
input_player8_r_x_minus_axis = "nul"
input_player8_r_y_plus = "nul"
input_player8_r_y_plus_btn = "nul"
input_player8_r_y_plus_axis = "nul"
input_player8_r_y_minus = "nul"
input_player8_r_y_minus_btn = "nul"
input_player8_r_y_minus_axis = "nul"
input_player8_turbo = "nul"
input_player8_turbo_btn = "nul"
input_player8_turbo_axis = "nul"
core_specific_config = "false"
libretro_log_level = "0"
log_verbosity = "false"
perfcnt_enable = "false"
audio_driver = "alsathread"
audio_latency = "64"
video_xscale = "4.000000"
video_yscale = "4.000000"
video_smooth = "false"
video_fullscreen_x = "640"
video_fullscreen_y = "480"
video_driver = "gl"
slowmotion_ratio = "3.000000"
libretro_directory = ""
libretro_info_path = ""
cheat_database_path = ""
audio_device = ""
audio_dsp_plugin = ""
extraction_directory = ""
video_filter = ""
game_history_path = ""
joypad_autoconfig_dir = ""
input_overlay = ""
netplay_nickname = ""
netplay_ip_address = ""
input_joypad_driver = ""
input_keyboard_layout = ""
/*
ADAFRUIT RETROGAME UTILITY: remaps buttons on Raspberry Pi GPIO header
to virtual USB keyboard presses. Great for classic game emulators!
Retrogame is interrupt-driven and efficient (usually under 0.3% CPU use)
and debounces inputs for glitch-free gaming.
Connect one side of button(s) to GND pin (there are several on the GPIO
header, but see later notes) and the other side to GPIO pin of interest.
Internal pullups are used; no resistors required. Avoid pins 8 and 10;
these are configured as a serial port by default on most systems (this
can be disabled but takes some doing). Pin configuration is currently
set in global table; no config file yet. See later comments.
Must be run as root, i.e. 'sudo ./retrogame &' or configure init scripts
to launch automatically at system startup.
Requires uinput kernel module. This is typically present on popular
Raspberry Pi Linux distributions but not enabled on some older varieties.
To enable, either type:
sudo modprobe uinput
Or, to make this persistent between reboots, add a line to /etc/modules:
uinput
Prior versions of this code, when being compiled for use with the Cupcade
or PiGRRL projects, required CUPCADE to be #defined. This is no longer
the case; instead a test is performed to see if a PiTFT is connected, and
one of two I/O tables is automatically selected.
Written by Phil Burgess for Adafruit Industries, distributed under BSD
License. Adafruit invests time and resources providing this open source
code, please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Copyright (c) 2013 Adafruit Industries.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <linux/uinput.h>
// START HERE ------------------------------------------------------------
// This table remaps GPIO inputs to keyboard values. In this initial
// implementation there's a 1:1 relationship (can't attach multiple keys
// to a button) and the list is fixed in code; there is no configuration
// file. Buttons physically connect between GPIO pins and ground. There
// are only a few GND pins on the GPIO header, so a breakout board is
// often needed. If you require just a couple extra ground connections
// and have unused GPIO pins, set the corresponding key value to GND to
// create a spare ground point.
#define GND -1
struct {
int pin;
int key;
} *io, // In main() this pointer is set to one of the two tables below.
ioTFT[] = {
// This pin/key table is used if an Adafruit PiTFT display
// is detected (e.g. Cupcade or PiGRRL).
// Input Output (from /usr/include/linux/input.h)
{ 2, KEY_LEFT }, // Joystick (4 pins)
{ 3, KEY_RIGHT },
{ 4, KEY_DOWN },
{ 17, KEY_UP },
{ 27, KEY_Z }, // A/Fire/jump/primary
{ 22, KEY_X }, // B/Bomb/secondary
{ 23, KEY_R }, // Credit
{ 18, KEY_Q }, // Start 1P
{ -1, -1 } }, // END OF LIST, DO NOT CHANGE
// MAME must be configured with 'z' & 'x' as buttons 1 & 2 -
// this was required for the accompanying 'menu' utility to
// work (catching crtl/alt w/ncurses gets totally NASTY).
// Credit/start are likewise moved to 'r' & 'q,' reason being
// to play nicer with certain emulators not liking numbers.
// GPIO options are 'maxed out' with PiTFT + above table.
// If additional buttons are desired, will need to disable
// serial console and/or use P5 header. Or use keyboard.
ioStandard[] = {
// This pin/key table is used when the PiTFT isn't found
// (using HDMI or composite instead), as with our original
// retro gaming guide.
// Input Output (from /usr/include/linux/input.h)
{ 6, KEY_LEFT }, // Joystick (4 pins)
{ 24, KEY_RIGHT },
{ 5, KEY_UP },
{ 25, KEY_DOWN },
{ 17, KEY_RIGHTCTRL}, // A/Fire/jump/primary
{ 27, KEY_RIGHTALT }, // B/Bomb/secondary
{ 22, KEY_ENTER }, // start
{ 23, KEY_X }, // select
{ 4, KEY_ESC },
{ 16, KEY_PAGEDOWN },
{ 19, KEY_PAGEUP },
// For credit/start/etc., use USB keyboard or add more buttons.
{ -1, -1 } }; // END OF LIST, DO NOT CHANGE
// A "Vulcan nerve pinch" (holding down a specific button combination
// for a few seconds) issues an 'esc' keypress to MAME (which brings up
// an exit menu or quits the current game). The button combo is
// configured with a bitmask corresponding to elements in the above io[]
// array. The default value here uses elements 6 and 7 (credit and start
// in the Cupcade pinout). If you change this, make certain it's a combo
// that's not likely to occur during actual gameplay (i.e. avoid using
// joystick directions or hold-for-rapid-fire buttons).
// Also key auto-repeat times are set here. This is for navigating the
// game menu using the 'gamera' utility; MAME disregards key repeat
// events (as it should).
const unsigned long vulcanMask = (1L << 6) | (1L << 7);
const int vulcanKey = KEY_ESC, // Keycode to send
vulcanTime = 1500, // Pinch time in milliseconds
repTime1 = 500, // Key hold time to begin repeat
repTime2 = 100; // Time between key repetitions
// A few globals ---------------------------------------------------------
char
*progName, // Program name (for error reporting)
sysfs_root[] = "/sys/class/gpio", // Location of Sysfs GPIO files
running = 1; // Signal handler will set to 0 (exit)
volatile unsigned int
*gpio; // GPIO register table
const int
debounceTime = 20; // 20 ms for button debouncing
// Some utility functions ------------------------------------------------
// Set one GPIO pin attribute through the Sysfs interface.
int pinConfig(int pin, char *attr, char *value) {
char filename[50];
int fd, w, len = strlen(value);
sprintf(filename, "%s/gpio%d/%s", sysfs_root, pin, attr);
if((fd = open(filename, O_WRONLY)) < 0) return -1;
w = write(fd, value, len);
close(fd);
return (w != len); // 0 = success
}
// Un-export any Sysfs pins used; don't leave filesystem cruft. Also
// restores any GND pins to inputs. Write errors are ignored as pins
// may be in a partially-initialized state.
void cleanup() {
char buf[50];
int fd, i;
sprintf(buf, "%s/unexport", sysfs_root);
if((fd = open(buf, O_WRONLY)) >= 0) {
for(i=0; io[i].pin >= 0; i++) {
// Restore GND items to inputs
if(io[i].key == GND)
pinConfig(io[i].pin, "direction", "in");
// And un-export all items regardless
sprintf(buf, "%d", io[i].pin);
write(fd, buf, strlen(buf));
}
close(fd);
}
}
// Quick-n-dirty error reporter; print message, clean up and exit.
void err(char *msg) {
printf("%s: %s. Try 'sudo %s'.\n", progName, msg, progName);
cleanup();
exit(1);
}
// Interrupt handler -- set global flag to abort main loop.
void signalHandler(int n) {
running = 0;
}
// Returns 1 if running on early Pi board, 0 otherwise.
// Relies on info in /proc/cmdline by default; if this is
// unreliable in the future, easy change to /proc/cpuinfo.
int isRevOnePi(void) {
FILE *fp;
char buf[1024], *ptr;
int n, rev = 0;
#if 1
char *filename = "/proc/cmdline",
*token = "boardrev=",
*fmt = "%x";
#else
char *filename = "/proc/cpuinfo",
*token = "Revision", // Capital R!
*fmt = " : %x";
#endif
if((fp = fopen(filename, "r"))) {
if((n = fread(buf, 1, sizeof(buf)-1, fp)) > 0) {
buf[n] = 0;
if((ptr = strstr(buf, token))) {
sscanf(&ptr[strlen(token)], fmt, &rev);
}
}
fclose(fp);
}
return ((rev == 0x02) || (rev == 0x03));
}
// Main stuff ------------------------------------------------------------
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
#define BLOCK_SIZE (4*1024)
#define GPPUD (0x94 / 4)
#define GPPUDCLK0 (0x98 / 4)
int main(int argc, char *argv[]) {
// A few arrays here are declared with 32 elements, even though
// values aren't needed for io[] members where the 'key' value is
// GND. This simplifies the code a bit -- no need for mallocs and
// tests to create these arrays -- but may waste a handful of
// bytes for any declared GNDs.
char buf[50], // For sundry filenames
c; // Pin input value ('0'/'1')
int fd, // For mmap, sysfs, uinput
i, j, // Asst. counter
bitmask, // Pullup enable bitmask
timeout = -1, // poll() timeout
intstate[32], // Last-read state
extstate[32], // Debounced state
lastKey = -1; // Last key down (for repeat)
unsigned long bitMask, bit; // For Vulcan pinch detect
volatile unsigned char shortWait; // Delay counter
struct input_event keyEv, synEv; // uinput events
struct pollfd p[32]; // GPIO file descriptors
progName = argv[0]; // For error reporting
signal(SIGINT , signalHandler); // Trap basic signals (exit cleanly)
signal(SIGKILL, signalHandler);
// Select io[] table for Cupcade (TFT) or 'normal' project.
io = (access("/etc/modprobe.d/adafruit.conf", F_OK) ||
access("/dev/fb1", F_OK)) ? ioStandard : ioTFT;
// If this is a "Revision 1" Pi board (no mounting holes),
// remap certain pin numbers in the io[] array for compatibility.
// This way the code doesn't need modification for old boards.
if(isRevOnePi()) {
for(i=0; io[i].pin >= 0; i++) {
if( io[i].pin == 2) io[i].pin = 0;
else if(io[i].pin == 3) io[i].pin = 1;
else if(io[i].pin == 27) io[i].pin = 21;
}
}
// ----------------------------------------------------------------
// Although Sysfs provides solid GPIO interrupt handling, there's
// no interface to the internal pull-up resistors (this is by
// design, being a hardware-dependent feature). It's necessary to
// grapple with the GPIO configuration registers directly to enable
// the pull-ups. Based on GPIO example code by Dom and Gert van
// Loo on elinux.org
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
err("Can't open /dev/mem");
gpio = mmap( // Memory-mapped I/O
NULL, // Any adddress will do
BLOCK_SIZE, // Mapped block length
PROT_READ|PROT_WRITE, // Enable read+write
MAP_SHARED, // Shared with other processes
fd, // File to map
GPIO_BASE ); // Offset to GPIO registers
close(fd); // Not needed after mmap()
if(gpio == MAP_FAILED) err("Can't mmap()");
// Make combined bitmap of pullup-enabled pins:
for(bitmask=i=0; io[i].pin >= 0; i++)
if(io[i].key != GND) bitmask |= (1 << io[i].pin);
gpio[GPPUD] = 2; // Enable pullup
for(shortWait=150;--shortWait;); // Min 150 cycle wait
gpio[GPPUDCLK0] = bitmask; // Set pullup mask
for(shortWait=150;--shortWait;); // Wait again
gpio[GPPUD] = 0; // Reset pullup registers
gpio[GPPUDCLK0] = 0;
(void)munmap((void *)gpio, BLOCK_SIZE); // Done with GPIO mmap()
// ----------------------------------------------------------------
// All other GPIO config is handled through the sysfs interface.
sprintf(buf, "%s/export", sysfs_root);
if((fd = open(buf, O_WRONLY)) < 0) // Open Sysfs export file
err("Can't open GPIO export file");
for(i=j=0; io[i].pin >= 0; i++) { // For each pin of interest...
sprintf(buf, "%d", io[i].pin);
write(fd, buf, strlen(buf)); // Export pin
pinConfig(io[i].pin, "active_low", "0"); // Don't invert
if(io[i].key == GND) {
// Set pin to output, value 0 (ground)
if(pinConfig(io[i].pin, "direction", "out") ||
pinConfig(io[i].pin, "value" , "0"))
err("Pin config failed (GND)");
} else {
// Set pin to input, detect rise+fall events
if(pinConfig(io[i].pin, "direction", "in") ||
pinConfig(io[i].pin, "edge" , "both"))
err("Pin config failed");
// Get initial pin value
sprintf(buf, "%s/gpio%d/value",
sysfs_root, io[i].pin);
// The p[] file descriptor array isn't necessarily
// aligned with the io[] array. GND keys in the
// latter are skipped, but p[] requires contiguous
// entries for poll(). So the pins to monitor are
// at the head of p[], and there may be unused
// elements at the end for each GND. Same applies
// to the intstate[] and extstate[] arrays.
if((p[j].fd = open(buf, O_RDONLY)) < 0)
err("Can't access pin value");
intstate[j] = 0;
if((read(p[j].fd, &c, 1) == 1) && (c == '0'))
intstate[j] = 1;
extstate[j] = intstate[j];
p[j].events = POLLPRI; // Set up poll() events
p[j].revents = 0;
j++;
}
} // 'j' is now count of non-GND items in io[] table
close(fd); // Done exporting
// ----------------------------------------------------------------
// Set up uinput
#if 1
// Retrogame normally uses /dev/uinput for generating key events.
// Cupcade requires this and it's the default. SDL2 (used by
// some newer emulators) doesn't like it, wants /dev/input/event0
// instead. Enable that code by changing to "#if 0" above.
if((fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0)
err("Can't open /dev/uinput");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
err("Can't SET_EVBIT");
for(i=0; io[i].pin >= 0; i++) {
if(io[i].key != GND) {
if(ioctl(fd, UI_SET_KEYBIT, io[i].key) < 0)
err("Can't SET_KEYBIT");
}
}
if(ioctl(fd, UI_SET_KEYBIT, vulcanKey) < 0) err("Can't SET_KEYBIT");
struct uinput_user_dev uidev;
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "retrogame");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
if(write(fd, &uidev, sizeof(uidev)) < 0)
err("write failed");
if(ioctl(fd, UI_DEV_CREATE) < 0)
err("DEV_CREATE failed");
#else // SDL2 prefers this event methodology
if((fd = open("/dev/input/event0", O_WRONLY | O_NONBLOCK)) < 0)
err("Can't open /dev/input/event0");
#endif
// Initialize input event structures
memset(&keyEv, 0, sizeof(keyEv));
keyEv.type = EV_KEY;
memset(&synEv, 0, sizeof(synEv));
synEv.type = EV_SYN;
synEv.code = SYN_REPORT;
synEv.value = 0;
// 'fd' is now open file descriptor for issuing uinput events
// ----------------------------------------------------------------
// Monitor GPIO file descriptors for button events. The poll()
// function watches for GPIO IRQs in this case; it is NOT
// continually polling the pins! Processor load is near zero.
while(running) { // Signal handler can set this to 0 to exit
// Wait for IRQ on pin (or timeout for button debounce)
if(poll(p, j, timeout) > 0) { // If IRQ...
for(i=0; i<j; i++) { // Scan non-GND pins...
if(p[i].revents) { // Event received?
// Read current pin state, store
// in internal state flag, but
// don't issue to uinput yet --
// must wait for debounce!
lseek(p[i].fd, 0, SEEK_SET);
read(p[i].fd, &c, 1);
if(c == '0') intstate[i] = 1;
else if(c == '1') intstate[i] = 0;
p[i].revents = 0; // Clear flag
}
}
timeout = debounceTime; // Set timeout for debounce
c = 0; // Don't issue SYN event
// Else timeout occurred
} else if(timeout == debounceTime) { // Button debounce timeout
// 'j' (number of non-GNDs) is re-counted as
// it's easier than maintaining an additional
// remapping table or a duplicate key[] list.
bitMask = 0L; // Mask of buttons currently pressed
bit = 1L;
for(c=i=j=0; io[i].pin >= 0; i++, bit<<=1) {
if(io[i].key != GND) {
// Compare internal state against
// previously-issued value. Send
// keystrokes only for changed states.
if(intstate[j] != extstate[j]) {
extstate[j] = intstate[j];
keyEv.code = io[i].key;
keyEv.value = intstate[j];
write(fd, &keyEv,
sizeof(keyEv));
c = 1; // Follow w/SYN event
if(intstate[j]) { // Press?
// Note pressed key
// and set initial
// repeat interval.
lastKey = i;
timeout = repTime1;
} else { // Release?
// Stop repeat and
// return to normal
// IRQ monitoring
// (no timeout).
lastKey = timeout = -1;
}
}
j++;
if(intstate[i]) bitMask |= bit;
}
}
// If the "Vulcan nerve pinch" buttons are pressed,
// set long timeout -- if this time elapses without
// a button state change, esc keypress will be sent.
if((bitMask & vulcanMask) == vulcanMask)
timeout = vulcanTime;
} else if(timeout == vulcanTime) { // Vulcan timeout occurred
// Send keycode (MAME exits or displays exit menu)
keyEv.code = vulcanKey;
for(i=1; i>= 0; i--) { // Press, release
keyEv.value = i;
write(fd, &keyEv, sizeof(keyEv));
usleep(10000); // Be slow, else MAME flakes
write(fd, &synEv, sizeof(synEv));
usleep(10000);
}
timeout = -1; // Return to normal processing
c = 0; // No add'l SYN required
} else if(lastKey >= 0) { // Else key repeat timeout
if(timeout == repTime1) timeout = repTime2;
else if(timeout > 30) timeout -= 5; // Accelerate
c = 1; // Follow w/SYN event
keyEv.code = io[lastKey].key;
keyEv.value = 2; // Key repeat event
write(fd, &keyEv, sizeof(keyEv));
}
if(c) write(fd, &synEv, sizeof(synEv));
}
// ----------------------------------------------------------------
// Clean up
ioctl(fd, UI_DEV_DESTROY); // Destroy and
close(fd); // close uinput
cleanup(); // Un-export pins
puts("Done.");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment