PSX controller to UART

This manual provides instructions on how to convert your PSx controller's output from the PSx connector to UART. In addition, you will learn how to receive data from the UART and how to emulate keyboard and mouse functions using Python scripting.

 
 
 
 
 
 
 

Figure 1 - Modular Design Diagram


 

 

Introduction

According to the design shown in Figure 1, the system to be designed should have various peripherals connected to the DE0-NANO, including a PSX controller and a UART module. The PSX controller is connected via an SPI data interface, and the FPGA has an HW description that decodes the controller and acquires the state of all the controller's buttons. In addition, a transmission system is required to capture the PSX controller key presses and send them via a serial protocol to a USB converter.

 

Verilog Design

In Figure 2, there are two Verilog modules, each of which serves as the hardware description for a chip that performs a specific function.

The first chip, named "psx_control.v," is responsible for SPI communication with the PSX controller to acquire the state of each button and place each value on its outputs.

 

    
Figure 2 - Verilog Modules

 

Verilog for "psx_control.v:

 

module psx_control(clk_50mhz,
	I_psRXD,
	O_psCLK,
	O_psSEL,
	O_psTXD,
	O_l1,
	O_l2,
	O_r1,
	O_r2,
	O_l3,
	O_r3,
	O_d_pad_up,
	O_d_pad_down,
	O_d_pad_left,
	O_d_pad_right,
	O_square,
	O_triangle,
	O_circle,
	O_x,
	O_select,
	O_start,
	O_analog1_left_right,
	O_analog2_left_right,
	O_analog1_up_down,
	O_analog2_up_down,
	switches
	);
	
input	clk_50mhz; //  50Mhz
input  I_psRXD;
output O_psCLK;
output O_psSEL;
output O_psTXD;
output	O_l1;
output	O_l2;
output	O_r1;
output	O_r2;
output O_l3;
output O_r3;
output	O_d_pad_up;
output	O_d_pad_down;
output	O_d_pad_left;
output	O_d_pad_right;
output	O_square;
output	O_triangle;
output	O_circle;
output	O_x;
output	O_select;
output	O_start;
output	[7:0]O_analog1_left_right;
output	[7:0]O_analog2_left_right;
output	[7:0]O_analog1_up_down;
output	[7:0]O_analog2_up_down;	
input [1:0]switches;


wire [7:0]data_to_psx1;
wire [7:0]data_to_psx2;
wire [7:0]data_to_psx3;
wire [7:0]data_to_psx4;
wire [7:0]data_to_psx5;
wire [7:0]data_to_psx6;


// BUTTONS PSX
assign O_d_pad_up=~data_to_psx1[4];
assign O_d_pad_down=~data_to_psx1[6];
assign O_d_pad_left=~data_to_psx1[5];
assign O_d_pad_right=~data_to_psx1[7];

assign O_select=~data_to_psx1[0];
assign O_start=~data_to_psx1[3];
assign O_l3=~data_to_psx1[1];
assign O_r3=~data_to_psx1[2];
assign O_l1=~data_to_psx2[2];
assign O_r1=~data_to_psx2[3];
assign O_l2=~data_to_psx2[0];
assign O_r2=~data_to_psx2[1];
assign O_triangle=~data_to_psx2[4];
assign O_square=~data_to_psx2[7];
assign O_circle=~data_to_psx2[5];
assign O_x=~data_to_psx2[6];

assign O_analog1_left_right=data_to_psx3[7:0];
assign O_analog2_left_right=data_to_psx5[7:0];
assign O_analog1_up_down=data_to_psx4[7:0];
assign O_analog2_up_down=data_to_psx6[7:0];


wire CLK_FSM_PSX;

/*DIVISOR DE FRECUENCIA PARA GENERAR CLK DE LA FSM DEL DECODIFICADOR DE PSX*/
pll	pll_inst (
	.inclk0 ( clk_50mhz ),
	.c0 ( CLK_FSM_PSX ),
	.c1 ( )
	);


psPAD_top psPAD_top_inst
(
	.I_CLK250K(CLK_FSM_PSX) ,	// input  I_CLK250K_sig
	.I_RSTn(1'b1) ,	// input  I_RSTn_sig
	.O_psCLK(O_psCLK) ,	// output  O_psCLK_sig
	.O_psSEL(O_psSEL) ,	// output  O_psSEL_sig
	.O_psTXD(O_psTXD) ,	// output  O_psTXD_sig
	.I_psRXD(I_psRXD) ,	// input  I_psRXD_sig
	.O_RXD_1(data_to_psx1) ,	// output [7:0] O_RXD_1_sig
	.O_RXD_2(data_to_psx2) ,	// output [7:0] O_RXD_2_sig
	.O_RXD_3(data_to_psx3) ,	// output [7:0] O_RXD_3_sig
	.O_RXD_4(data_to_psx4) ,	// output [7:0] O_RXD_4_sig
	.O_RXD_5(data_to_psx5) ,	// output [7:0] O_RXD_5_sig
	.O_RXD_6(data_to_psx6) ,	// output [7:0] O_RXD_6_sig
	.I_CONF_SW(1'b1) ,	// input  I_CONF_SW_sig
	.I_MODE_SW(1'b1) ,	// input  I_MODE_SW_sig
	.I_MODE_EN(1'b1) ,	// input  I_MODE_EN_sig
	.I_VIB_SW(switches) ,	// input [1:0] I_VIB_SW_sig
	.I_VIB_DAT(8'hff) 	// input [7:0] I_VIB_DAT_sig
);



endmodule

The Verilog for the PSX controller "psPAD_top.v" can be downloaded: psPAD_top.v

 

The second chip, "tx_control_to_pc.v," is responsible for receiving the state of each button from the first chip and packaging them into bytes for transmission via another internal chip called "UART_FullDuplex.v." To achieve this, a state machine is used, as shown below:

 

 

You can see the FSM Verilog code(tx_control_to_pc.v), and the Uart module is described on Uart Full Duplex.


module tx_control_to_pc(clk,
	l1,
	l2,
	r1,
	r2,
	l3,
	r3,
	d_pad_up,
	d_pad_down,
	d_pad_left,
	d_pad_right,
	square,
	triangle,
	circle,
	x,
	select,
	start,
	left_analog_up_down,
	left_analog_right_left,
	right_analog_up_down,
	right_analog_right_left,
	Tx_to_pc);

	
input	clk; // 50Mhz
input	l1;
input	l2;
input	r1;
input	r2;
input l3;
input r3;
input	d_pad_up;
input	d_pad_down;
input	d_pad_left;
input	d_pad_right;
input	square;
input	triangle;
input	circle;
input	x;
input	select;
input	start;
input	[7:0]left_analog_up_down;
input	[7:0]left_analog_right_left;
input	[7:0]right_analog_up_down;
input	[7:0]right_analog_right_left;
output Tx_to_pc;

parameter SIZE_PKG1=3'd4;
parameter SIZE_PKG2=3'd6;

//							load_data, count_pack, reset_count, toggle_pack, send_data__ state
parameter IDLE= 	   {1'b0,		1'b0,		1'b1,			1'b0, 			1'b0, 	3'b000};
parameter SECOND=		{1'b1,		1'b0,		1'b0,			1'b0, 			1'b0, 	3'b001};
parameter THIRD=		{1'b0,		1'b0,		1'b0,			1'b0, 			1'b1, 	3'b010};
parameter FOURTH=		{1'b0,		1'b1,		1'b0,			1'b0, 			1'b0, 	3'b011};
parameter FIFTH=		{1'b0,		1'b0,		1'b0,			1'b1, 			1'b0, 	3'b100};


reg [7:0]STATE=IDLE;

wire load_data=STATE[7];
wire next_count=STATE[6];
wire reset_count=STATE[5];
wire toggle=STATE[4];
wire send_byte=STATE[3];


wire busy_tx;

// Paquete de datos # 1
wire [7:0]packets1[4:0];
wire [7:0]checksum1 =(packets1[0][7:0]+packets1[1][7:0]+packets1[2][7:0]+packets1[3][7:0]);

// Paquete de datos # 2
wire [7:0]packets2[6:0];
wire [7:0]checksum2 =(packets2[0][7:0]+packets2[1][7:0]+packets2[2][7:0]+packets2[3][7:0]+packets2[4][7:0]+packets2[5][7:0]);

// Paquete de datos # 1 - codificacion
assign packets1[0][7:0]=8'd17;// ID
assign packets1[1][7:0]={1'b1,2'd0,l3,r3,2'd0,checksum1[7]}; // HEAD
assign packets1[2][7:0]={1'b1,l1,l2,r1,r2,select,start,x}; // DATA1
assign packets1[3][7:0]={1'b1,d_pad_up,d_pad_down,d_pad_left,d_pad_right,square,triangle,circle}; // DATA2
assign packets1[4][7:0]={1'b1,(checksum1[6:0])}; // CHECKSUM

// Paquete de datos # 2 - codificacion
assign packets2[0][7:0]=8'd27;// ID
assign packets2[1][7:0]={1'b1,2'd0,right_analog_right_left[7],right_analog_up_down[7],left_analog_right_left[7],left_analog_up_down[7],checksum2[7]}; // HEAD
assign packets2[2][7:0]={1'b1,left_analog_up_down[6:0]}; // DATA1
assign packets2[3][7:0]={1'b1,left_analog_right_left[6:0]}; // DATA2
assign packets2[4][7:0]={1'b1,right_analog_up_down[6:0]}; // DATA3
assign packets2[5][7:0]={1'b1,right_analog_right_left[6:0]}; // DATA4
assign packets2[6][7:0]={1'b1,(checksum2[6:0])}; // CHECKSUM

// Selector de paquetes
reg toggle_reg=1'b0;
reg [2:0]count_packet=3'd0;
reg [7:0]data_to_send_buffer1[4:0];
reg [7:0]data_to_send_buffer2[6:0];

wire [2:0]count_up=toggle_reg ? SIZE_PKG1: SIZE_PKG2;
wire [7:0]data_to_send= toggle_reg ? data_to_send_buffer1[count_packet][7:0]: data_to_send_buffer2[count_packet][7:0];

always@(posedge toggle)
begin
	toggle_reg<=~toggle_reg;
end

always@(posedge next_count, posedge reset_count)
begin
	if(reset_count) count_packet<=3'd0;
	else count_packet<=count_packet+1'b1;
end

always@(posedge load_data)
begin
	if(toggle_reg)
	begin
		data_to_send_buffer1[0][7:0]<=packets1[0][7:0];
		data_to_send_buffer1[1][7:0]<=packets1[1][7:0];
		data_to_send_buffer1[2][7:0]<=packets1[2][7:0];
		data_to_send_buffer1[3][7:0]<=packets1[3][7:0];
		data_to_send_buffer1[4][7:0]<=packets1[4][7:0];
	end
end


always@(posedge load_data)
begin
	if(!toggle_reg)
	begin
		data_to_send_buffer2[0][7:0]<=packets2[0][7:0];
		data_to_send_buffer2[1][7:0]<=packets2[1][7:0];
		data_to_send_buffer2[2][7:0]<=packets2[2][7:0];
		data_to_send_buffer2[3][7:0]<=packets2[3][7:0];
		data_to_send_buffer2[4][7:0]<=packets2[4][7:0];
		data_to_send_buffer2[5][7:0]<=packets2[5][7:0];
		data_to_send_buffer2[6][7:0]<=packets2[6][7:0];
	end
end

always@(posedge clk)
begin
	case(STATE)
	// STAND BY
	IDLE: if(busy_tx) STATE<=IDLE;
			else STATE<=SECOND;
	//LOAD_DATA_IN BUFFER 1 or 2
	SECOND:
			 STATE<=THIRD;
	// SEND BYTE		 
	THIRD:if(busy_tx) STATE<=THIRD;
			else STATE<=FOURTH;
	// Cuente uno en el paquete	
	FOURTH:if(busy_tx) STATE<=FOURTH;
			 else if(count_packet<=count_up) STATE<=SECOND;
			 else STATE<=FIFTH;
	// ir al inicio	
	FIFTH: STATE<=IDLE;
	
	default: STATE<=IDLE;
	
	endcase
end



UART_FullDuplex UART_FullDuplex_inst 
(
	.clk(clk) ,	// input  clk_sig
	.Tx_Start(send_byte) ,	// input  Tx_Start_sig
	.Tx_Data(data_to_send) ,	// input [7:0] Tx_Data_sig
	.Tx(Tx_to_pc) ,	// output  Tx_sig
	.TxD_Busy(busy_tx) ,	// output  TxD_Busy_sig
	.Rx() ,	// input  Rx_sig
	.Rx_Data() ,	// output [7:0] Rx_Data_sig
	.RxD_Ready() 	// output  RxD_Ready_sig
);


endmodule

 

If you want to transform your psx controller to uart using your DE0-NANO, download the next sources and binaries(precompiled solution for the DE0-NANO):
  • Solution(.*sof): Download, GPIO[1] is Tx(UART 9600 bps).
  • Sources for Quartus: Download
 
Download Sources for Quartus II: Plantilla para la DE0-NANO
Binary (*.sof): Descargar

 

When you program your DE0-nano you should see as the following video shows, you do not need the UART to see the results on the LEDS




Python Script for UART RX, and Keyboard and Mouse Emulation(Decode_tx_psx.py)

This transmission is received by a Python script that will decode these message and convert them on Scan Codes, mimicking the keyboard and Mouse. To test this script along with the FPGA, you do need to have the UART-USB converted connected working at (UART 9600 bps).

 The python script is the following:

# Wrote by Holguer A Becerra
# Semillero ADT-UPB
# Pontificia Bolivariana University
# PSX to serial converter, Keyboard Emulador
# Platform: DE0-NANO


import threading
import serial, math,time
import time,win32api,win32con

#keyboard virtual and scan codes
KEYBOARD_HOLD = 0x1
KEYBOARD_UP_EVEN = 0x2
VK_LBUTTON = 0x1
VK_RBUTTON = 0x2
VK_CTRLBREAK = 0x3
VK_MBUTTON = 0x4
VK_BACKSPACE = 0x8
VK_TAB = 0x9
VK_ENTER = 0xD
VK_SHIFT = 0x10
VK_CONTROL = 0x11
VK_ALT = 0x12
VK_PAUSE = 0x13
VK_CAPSLOCK = 0x14
VK_ESCAPE = 0x1B
VK_SPACE = 0x20
VK_PAGEUP = 0x21
VK_PAGEDOWN = 0x22
VK_END = 0x23
VK_HOME = 0x24
VK_LEFT = 0x25
VK_UP = 0x26
VK_RIGHT = 0x27
VK_DOWN = 0x28
VK_PRINTSCREEN = 0x2C
VK_INSERT = 0x2D
VK_DELETE = 0x2E
VK_0 = 0x30
VK_1 = 0x31
VK_2 = 0x32
VK_3 = 0x33
VK_4 = 0x34
VK_5 = 0x35
VK_6 = 0x36
VK_7 = 0x37
VK_8 = 0x38
VK_9 = 0x39
VK_A = 0x41
VK_B = 0x42
VK_C = 0x43
VK_D = 0x44
VK_E = 0x45
VK_F = 0x46
VK_G = 0x47
VK_H = 0x48
VK_I = 0x49
VK_J = 0x4A
VK_K = 0x4B
VK_L = 0x4C
VK_M = 0x4D
VK_N = 0x4E
VK_O = 0x4F
VK_P = 0x50
VK_Q = 0x51
VK_R = 0x52
VK_S = 0x53
VK_T = 0x54
VK_U = 0x55
VK_V = 0x56
VK_W = 0x57
VK_X = 0x58
VK_Y = 0x59
VK_Z = 0x5A
VK_LWINDOWS = 0x5B
VK_RWINDOWS = 0x5C
VK_APPSPOPUP = 0x5D
VK_NUMPAD_0 = 0x60
VK_NUMPAD_1 = 0x61
VK_NUMPAD_2 = 0x62
VK_NUMPAD_3 = 0x63
VK_NUMPAD_4 = 0x64
VK_NUMPAD_5 = 0x65
VK_NUMPAD_6 = 0x66
VK_NUMPAD_7 = 0x67
VK_NUMPAD_8 = 0x68
VK_NUMPAD_9 = 0x69
VK_NUMPAD_MULTIPLY = 0x6A
VK_NUMPAD_ADD = 0x6B
VK_NUMPAD_PLUS = 0x6B
VK_NUMPAD_SUBTRACT = 0x6D
VK_NUMPAD_MINUS = 0x6D
VK_NUMPAD_MOINS = 0x6D
VK_NUMPAD_DECIMAL = 0x6E
VK_NUMPAD_POINT = 0x6E
VK_NUMPAD_DIVIDE = 0x6F
VK_F1 = 0x70
VK_F2 = 0x71
VK_F3 = 0x72
VK_F4 = 0x73
VK_F5 = 0x74
VK_F6 = 0x75
VK_F7 = 0x76
VK_F8 = 0x77
VK_F9 = 0x78
VK_F10 = 0x79
VK_F11 = 0x7A
VK_F12 = 0x7B
VK_NUMLOCK = 0x90
VK_SCROLL = 0x91
VK_LSHIFT = 0xA0
VK_RSHIFT = 0xA1
VK_LCONTROL = 0xA2
VK_RCONTROL = 0xA3
VK_LALT = 0xA4
VK_RALT = 0xA5
VK_POINTVIRGULE = 0xBA
VK_ADD = 0xBB
VK_PLUS = 0xBB
VK_EQUAL = 0xBB
VK_VIRGULE = 0xBC
VK_SUBTRACT = 0xBD
VK_MINUS = 0xBD
VK_MOINS = 0xBD
VK_UNDERLINE = 0xBD
VK_POINT = 0xBE
VK_SLASH = 0xBF
VK_TILDE = 0xC0
VK_LEFTBRACKET = 0xDB
VK_BACKSLASH = 0xDC
VK_RIGHTBRACKET = 0xDD
VK_QUOTE = 0xDE
VK_APOSTROPHE = 0xDE
VS_Q = 16
VS_W = 17
VS_E = 18
VS_R = 19
VS_T = 20
VS_Y = 21
VS_U = 22
VS_I = 23
VS_0 = 24
VS_P = 25
VS_A = 30
VS_S = 31
VS_D = 32
VS_F = 33
VS_G = 34
VS_H = 35
VS_J = 36
VS_K = 37
VS_L = 38
VS_Z = 44
VS_X = 45
VS_C = 46
VS_V = 47
VS_B = 48
VS_N = 49
VS_M = 50
VS_UP = 200
VS_DOWN = 208
VS_LEFT = 203
VS_RIGHT = 205
VS_PAUSE = 197
VS_SPACE = 57
VS_ENTER = 28
VS_ESCAPE = 1
VS_00 = 11
VS_1 = 2
VS_2 = 3
VS_3 = 4
VS_4 = 5
VS_5 = 6
VS_6 = 7
VS_7 = 8
VS_8 = 9
VS_9 = 10

#mouse events
CLICK_LEFTDOWN = 0x2
CLICK_LEFTUP = 0x4
CLICK_MIDDLEDOWN = 0x20
CLICK_MIDDLEUP = 0x40
CLICK_RIGHTDOWN = 0x8
CLICK_RIGHTUP = 0x10
MOUSEEVENTF_MOVE = 0x1

# buttons code
BUTTON_X=128
BUTTON_O=64
BUTTON_TRIANGLE=32
BUTTON_SQUARE=16
BUTTON_L1=8
BUTTON_L2=4
BUTTON_R1=2
BUTTON_R2=1
BUTTON_UP=128 | 512
BUTTON_DOWN=64 | 512
BUTTON_RIGHT=32 | 512
BUTTON_LEFT=16 | 512
BUTTON_L3=8 | 512
BUTTON_R3=4 | 512
BUTTON_SELECT=2 | 512
BUTTON_START=1 | 512
AN_L_UD= 1 | 512
AN_L_LR= 2 | 512
AN_R_UD= 3 | 512
AN_R_LR= 4 | 512

#buttons received
analog_axis_l_lr_med=0#analogic axis left, left right movement
analog_axis_l_ud_med=0#analogic axis left, up down movement
analog_axis_r_lr_med=0#analogic axis right, left right movement
analog_axis_r_ud_med=0#analogic axis right, up down movement

analog_axis_l_lr=0#analogic axis left, left right movement
analog_axis_l_ud=0#analogic axis left, up down movement
analog_axis_r_lr=0#analogic axis right, left right movement
analog_axis_r_ud=0#analogic axis right, up down movement
x_c_tri_sq_l1_l2_r1_r2=0 #buttons[X,O,/\,[],L1,L2,R1,R2]
u_d_r_l_l3_r3_sel_st=0#buttons[UP,DOWN,RIGHT,LEFT,L3,R3,SELECT,START]

#vars

packet1=[0,0,0,0]
packet2=[0,0,0,0,0,0]
contador=0
key=0;
checksum1=0
checksum1_to_compare=0
checksum2=0
checksum2_to_compare=0

#Class for emule key
class emule_key(threading.Thread):
    def __init__(self,vk,vs,key_p,delay):
        self.last = 0
        self.vk = vk
        self.vs = vs
        self.key_p=key_p
        self.delay=delay
        threading.Thread.__init__(self)

    def stop(self):
        self._Thread__stop()
        
    def run(self):
        while True:
            if(self.key_p & 512):             
                if(u_d_r_l_l3_r3_sel_st & ((self.key_p & 255))):
                    win32api.keybd_event(self.vk, self.vs, 0, 0)
                    self.last = 1
                #time.sleep(self.delay)                
                if((u_d_r_l_l3_r3_sel_st & ((self.key_p & 255)))==0):
                    if(self.last ==1):
                        win32api.keybd_event(self.vk, self.vs, 0x2, 0)
                        self.last = 0
            else:
                if(x_c_tri_sq_l1_l2_r1_r2 & ((self.key_p & 255))):
                    win32api.keybd_event(self.vk, self.vs, 0, 0)
                    self.last=1
                #time.sleep(self.delay)                
                if((x_c_tri_sq_l1_l2_r1_r2 & ((self.key_p & 255)))==0):
                    if(self.last ==1):
                        win32api.keybd_event(self.vk, self.vs, 0x2, 0)
                        self.last = 0
            time.sleep(self.delay)

class emule_mouse(threading.Thread):
    def __init__(self,vk,key_p,sens,delay):
        self.last = 0
        self.vk = vk
        self.key_p=key_p
        self.delay=delay
        self.sens=sens
        threading.Thread.__init__(self)

    def stop(self):
        self._Thread__stop()
        
    def run(self):
        while True:
            if(self.vk==MOUSEEVENTF_MOVE):
                if(self.key_p==AN_L_UD):                    
                    win32api.mouse_event(self.vk, 0, analog_axis_l_ud/self.sens-analog_axis_l_ud_med/self.sens, 0, 0)
                elif(self.key_p==AN_R_UD):
                    win32api.mouse_event(self.vk, 0, analog_axis_r_ud/self.sens-analog_axis_r_ud_med/self.sens, 0, 0)
                elif(self.key_p==AN_L_LR):
                    win32api.mouse_event(self.vk,  analog_axis_l_lr/self.sens-analog_axis_l_lr_med/self.sens, 0, 0, 0)
                elif(self.key_p==AN_R_LR):
                    win32api.mouse_event(self.vk, analog_axis_r_lr/self.sens-analog_axis_r_lr_med/self.sens, 0, 0, 0)
                
            elif(self.key_p & 512):             
                if(u_d_r_l_l3_r3_sel_st & ((self.key_p & 255))):
                    win32api.mouse_event(self.vk, 0, 0, 0, 0)
                    self.last = 1
                #time.sleep(self.delay)                
                if((u_d_r_l_l3_r3_sel_st & ((self.key_p & 255)))==0):
                    if(self.last == 1):
                        win32api.mouse_event(self.vk*2, 0, 0, 0,0)
                        self.last = 0
            else:
                if(x_c_tri_sq_l1_l2_r1_r2 & ((self.key_p & 255))):
                    win32api.mouse_event(self.vk, 0, 0, 0,0)
                    self.last = 1
                #time.sleep(self.delay)                
                if((x_c_tri_sq_l1_l2_r1_r2 & ((self.key_p & 255)))==0):
                    if(self.last == 1):
                        win32api.mouse_event(self.vk*2, 0, 0, 0,0)
                        self.last = 0
            time.sleep(self.delay)



ser = serial.Serial('COM9', 9600)
#ser.parity=serial.PARITY_EVEN


#PADDLE
key1_1 = emule_key(VK_W,VS_W,BUTTON_UP,0.08)
key1_2 = emule_key(VK_D,VS_D,BUTTON_RIGHT,0.08)
key1_3 = emule_key(VK_S,VS_S,BUTTON_DOWN,0.08)
key1_4 = emule_key(VK_A,VS_A,BUTTON_LEFT,0.08)
#BUTTONS
key2_1 = emule_key(VK_J,VS_J,BUTTON_O,0.08)
#key2_2 = emule_key(VK_K,VS_K,BUTTON_X,0.08)
key2_2 = emule_mouse(CLICK_LEFTDOWN,BUTTON_X,0,0.05)
key2_3 = emule_key(VK_L,VS_L,BUTTON_SQUARE,0.08)
key2_4 = emule_key(VK_I,VS_I,BUTTON_TRIANGLE,0.08)
#TOP BUTTONS
key3_1 = emule_key(VK_R,VS_R,BUTTON_L1,0.08)
key3_2 = emule_key(VK_T,VS_T,BUTTON_L2,0.08)
key3_3 = emule_key(VK_Y,VS_Y,BUTTON_R1,0.08)
key3_4 = emule_key(VK_U,VS_U,BUTTON_R2,0.08)
#MIDDLE BUTTONS
key4_1 = emule_key(VK_M,VS_M,BUTTON_L3,0.1)
key4_2 = emule_key(VK_C,VS_C,BUTTON_R3,0.1)
key4_3 = emule_key(VK_B,VS_B,BUTTON_SELECT,0.1)
key4_4 = emule_key(VK_N,VS_N,BUTTON_START,0.1)
#emule mouse
mouse1_x_axis= emule_mouse(MOUSEEVENTF_MOVE,AN_R_LR,10,0.01)
mouse1_y_axis= emule_mouse(MOUSEEVENTF_MOVE,AN_R_UD,10,0.01)


#AJUSTAR AXIS DE LOS ANALOGICOS
print "Ajustando Axis porfavor no mueva ningun analogico"
calibre=7
while(calibre>0):
    key=ord(ser.readline(1))
    if(key==27):
        packet2[0]=ord(ser.readline(1))
        packet2[1]=ord(ser.readline(1))
        packet2[2]=ord(ser.readline(1))
        packet2[3]=ord(ser.readline(1))
        packet2[4]=ord(ser.readline(1))
        packet2[5]=ord(ser.readline(1))
        checksum2=(key+packet2[0]+packet2[1]+packet2[2]+packet2[3]+packet2[4]) & 255
        checksum2_to_compare=(packet2[5]&127)+((packet2[0] & 1)<<7)
        if(checksum2==checksum2_to_compare):
            analog_axis_l_ud_med= (packet2[1] & 127) | (((packet2[0]>>1)&1)<<7)
            
            analog_axis_l_lr_med= (packet2[2] & 127) | (((packet2[0]>>2)&1)<<7)
            
            analog_axis_r_ud_med= (packet2[3] & 127) | (((packet2[0]>>3)&1)<<7)
            
            analog_axis_r_lr_med= (packet2[4] & 127) | (((packet2[0]>>4)&1)<<7)
            
        calibre=calibre-1
        ser.flushInput()

print analog_axis_r_lr_med
print analog_axis_l_lr_med
print analog_axis_l_ud_med
print analog_axis_r_ud_med
print "Termino Ajuste de Axis, Empezando en 5 seg.. emulacion"
time.sleep(5)


#START THREADS
key1_1.start()
key1_2.start()
key1_3.start()
key1_4.start()
key2_1.start()
key2_2.start()
key2_3.start()
key2_4.start()
key3_1.start()
key3_2.start()
key3_3.start()
key3_4.start()
key4_1.start()
key4_2.start()
key4_3.start()
key4_4.start()
mouse1_x_axis.start()
mouse1_y_axis.start()


#FREE 
ser.flushInput()


while (key1_1.isAlive()):# & begin2.isAlive()):
    try:
        key=ord(ser.readline(1))
        if(key==17):
            packet1[0]=ord(ser.readline(1))
            packet1[1]=ord(ser.readline(1))
            packet1[2]=ord(ser.readline(1))
            packet1[3]=ord(ser.readline(1))
            checksum1=(key+packet1[0]+packet1[1]+packet1[2]) & 255
            checksum1_to_compare=(packet1[3]&127)+((packet1[0] & 1)<<7)
            #print str(checksum1)+ ", " +str(checksum1_to_compare)
            if(checksum1==checksum1_to_compare):
                x_c_tri_sq_l1_l2_r1_r2=((packet1[1]>>3)& 15) | ((packet1[1] & 1)<<7) | ((packet1[2] & 7)<<4)
                u_d_r_l_l3_r3_sel_st=(((packet1[2]>>3)&15)<<4)  | (((packet1[0]>>3)&3)<<2) | ((packet1[1]>>1)&3)
                #if(x_c_tri_sq_l1_l2_r1_r2 & 128):
                   #print "Se esta oprimiendo: x"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 64):
                   #print "Se esta oprimiendo: circle"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 32):
                   #print "Se esta oprimiendo: triangle"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 16):
                   #print "Se esta oprimiendo: square"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 8):
                   #print "Se esta oprimiendo: L1"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 4):
                   #print "Se esta oprimiendo: L2"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 2):
                   #print "Se esta oprimiendo: R1"
                #if(x_c_tri_sq_l1_l2_r1_r2 & 1):
                   #print "Se esta oprimiendo: R2"
                #if(u_d_r_l_l3_r3_sel_st & 128):
                   #print "Se esta oprimiendo: UP"
                #if(u_d_r_l_l3_r3_sel_st & 64):
                   #print "Se esta oprimiendo: DOWN"
                #if(u_d_r_l_l3_r3_sel_st & 32):
                   #print "Se esta oprimiendo: RIGHT"
                #if(u_d_r_l_l3_r3_sel_st & 16):
                   #print "Se esta oprimiendo: LEFT"
                #if(u_d_r_l_l3_r3_sel_st & 8):
                   #print "Se esta oprimiendo: L3"
                #if(u_d_r_l_l3_r3_sel_st & 4):
                   #print "Se esta oprimiendo: R3"
                #if(u_d_r_l_l3_r3_sel_st & 2):
                   #print "Se esta oprimiendo: SELECT"
                #if(u_d_r_l_l3_r3_sel_st & 1):
                   #print "Se esta oprimiendo: START"
                #print "buen dato 1\n"
            #print("eating..." + str(contador) + " " +  str(key))
            #print(packet2[3])
        elif(key==27):
            packet2[0]=ord(ser.readline(1))
            packet2[1]=ord(ser.readline(1))
            packet2[2]=ord(ser.readline(1))
            packet2[3]=ord(ser.readline(1))
            packet2[4]=ord(ser.readline(1))
            packet2[5]=ord(ser.readline(1))
            checksum2=(key+packet2[0]+packet2[1]+packet2[2]+packet2[3]+packet2[4]) & 255
            checksum2_to_compare=(packet2[5]&127)+((packet2[0] & 1)<<7)
            if(checksum2==checksum2_to_compare):
                analog_axis_l_ud= (packet2[1] & 127) | (((packet2[0]>>1)&1)<<7)            
                analog_axis_l_lr= (packet2[2] & 127) | (((packet2[0]>>2)&1)<<7)
                analog_axis_r_ud= (packet2[3] & 127) | (((packet2[0]>>3)&1)<<7)
                analog_axis_r_lr= (packet2[4] & 127) | (((packet2[0]>>4)&1)<<7)
                #if(u_d_r_l_l3_r3_sel_st & 16):# if left print the value of analog left up down
                    #print "anal_l_ud:"+bin(analog_axis_l_ud)
                #if(u_d_r_l_l3_r3_sel_st & 32):# if right print the value of analog left right left
                    #print "anal_l_ud:"+bin(analog_axis_l_lr)
                #if(u_d_r_l_l3_r3_sel_st & 128):# if up print the value of analog right up down
                    #print "anal_l_ud:"+bin(analog_axis_r_ud)
                #if(u_d_r_l_l3_r3_sel_st & 64):# if down print the value of analog right right left
                    #print "anal_l_ud:"+bin(analog_axis_r_lr)
                
                #print "buen dato 2\n"
            #print((packet2[5]))

        #descarto N paquetes en un tiempo.
        if(contador==100):
            ser.flushInput()
            contador=0
        ##print("eating..." + str(contador) + " " +  str(key))
        contador+=1
    except KeyboardInterrupt:
            print "Ctrl-c received! kill threads..."
            key1_1.stop()
            key1_2.stop()
            key1_3.stop()
            key1_4.stop()
            key2_1.stop()
            key2_2.stop()
            key2_3.stop()
            key2_4.stop()
            key3_1.stop()
            key3_2.stop()
            key3_3.stop()
            key3_4.stop()
            key4_1.stop()
            key4_2.stop()
            key4_3.stop()
            key4_4.stop()
            mouse1_x_axis.stop()
            mouse1_y_axis.stop()
            pass

            
if ser.isOpen():
    ser.close()

 
 
Python Script for Keyboard/Mouse emulator: 
    


Modify this lines in the python script for emulating any key of your keyboard or mouse.
  • emulate_key(Virtual_Key, Scan_Code,  PSX_BUTTON, Sensitivity)
  • emulate_mouse(Mouse_Button/Move, PSX_BUTTON, Sensitivity)
  • You can changue the communication port in the line 316 "ser = serial.Serial('COM9', 9600)"

 
 
 
 
References(PSX Controller Module Decoder):