Help with Arduino communicating with PSP via USB

I'm using an Arduino nano 33 IOT and attempting to communicate with a custom plugin i have compiled and running on the PSP.

I'm attempting to replicate what has been achieved in this article (it is in Russian but Google translate works well)

Specifically the RPi script to communicate with the PSP (bottom of the page). I have ran the PSP plugin and RPi script and they work so i'm confident this issue is on my Arduino side rather than the PSP's.

I will attach the RPi script at the bottom of the post to save you trawling through the post.

Iv'e ran the USB_desc example sketch from the USBHost library downloaded as part of the Boards Manager package for the Arduino nano 33 iot and it returns a shed load of data about the PSP (the fact i refer to it as shed load should probably hint my lack of USB protocol knowledge)

After finding the device address based on product and vendor id's i figured i would try and send data in the same fashion the RPi script does (it uses libusb) however i get a error code back.

uint32_t res = usb.outTransfer(*addr, 0, sizeof(PS), (unsigned char *)&PS);

My response is 219 however i have no idea what that means. I assume that's a standard error code for something but im struggling to find out what that something is.

I know the USB protocol is complex with multiple messages to instigate data transfer but i assumed that was handled within the USBHost lib.

Below i have added my entire Arduino script and the script from the linked post for the RPi im trying to port to the Arduino.

I know this is an odd one, but hopefully a fun challenge and any help anyone can offer will be greatly appretiated.

For reference/context i created a PSP Consolizer now attempting to do the same but via usb and custom PSP code to mean i can do the same without opening a PSP (and run on all model PSP's)

My Script



#include "Arduino.h"
#include <usbhub.h>
#include "pgmstrings.h"

#define SONY_VENDOR_ID	 0x054C
#define PSP_B_PRODUCT_ID 0x01C9

USBHost usb;

struct
{
    unsigned int Pattern;
    unsigned int Btn;
    unsigned int X;
    unsigned int Y;
} PS = {0x1234ABFE, 0, 127, 127};

#define UP			0x00000010
#define DOWN			0x00000040
#define LEFT			0x00000080
#define RIGHT			0x00000020
#define B_X			0x00004000
#define B_O			0x00002000
#define B_KVADRAT	0x00008000
#define B_TREUGOLNIK	0x00001000
#define B_L			0x00000100
#define B_R			0x00000200
#define B_SELECT	0x00000001
#define B_START			0x00000008
#define B_NOTE			0x00800000

uint32_t *addr = NULL;

void setup()
{
  pinMode(5, INPUT_PULLUP);

  SERIAL_PORT_HARDWARE.begin( 9600 );
  while (!SERIAL_PORT_HARDWARE); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
  SERIAL_PORT_HARDWARE.println("Start USB Desc");

  if (usb.Init() == -1)
      SERIAL_PORT_HARDWARE.println("OSC did not start.");

  delay( 20 );
}

void findPSPAddress(UsbDeviceDefinition *pdev)
{
  USB_DEVICE_DESCRIPTOR buf;
  byte rcode = usb.getDevDescr( pdev->address.devAddress, 0, 0x12, ( uint8_t *)&buf );

  if (rcode) {
    SERIAL_PORT_HARDWARE.print("\n\nERROR: getting usb dev descr");
    SERIAL_PORT_HARDWARE.println(rcode);
    return;
  }

  if (buf.idVendor == SONY_VENDOR_ID && buf.idProduct == PSP_B_PRODUCT_ID) {
    SERIAL_PORT_HARDWARE.println("\n\nITS A PSP!\n\n");

    addr = &pdev->address.devAddress;
  }
}

void loop()
{
  usb.Task();

  if( usb.getUsbTaskState() == USB_STATE_RUNNING )
  {
    if (!addr) {
      usb.ForEachUsbDevice(&findPSPAddress);
    } else {
      bool pressed = digitalRead(5);

      int t = 0;

      if (pressed == LOW) {
        SERIAL_PORT_HARDWARE.println("\n\nButton PRessed");
        PS.Btn |= RIGHT; 
        t = 1;
      }

      if (t == 1) {
        SERIAL_PORT_HARDWARE.println("\n\nTransfering");

        uint32_t res = usb.outTransfer(*addr, 2, sizeof(PS), (unsigned char *)&PS);

        SERIAL_PORT_HARDWARE.print("\n\RES: ");
        SERIAL_PORT_HARDWARE.println(res);
      }
    }
    
    delay(5);
  }
}

RPi Script attempting to port

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libusb-1.0/libusb.h>

#define SONY_VENDOR_ID	 0x054C
#define PSP_B_PRODUCT_ID 0x01C9

#define UP			0x00000010
#define DOWN			0x00000040
#define LEFT			0x00000080
#define RIGHT			0x00000020
#define B_X			0x00004000
#define B_O			0x00002000
#define B_KVADRAT	0x00008000
#define B_TREUGOLNIK	0x00001000
#define B_L			0x00000100
#define B_R			0x00000200
#define B_SELECT	0x00000001
#define B_START			0x00000008
#define B_NOTE			0x00800000

struct
{
    unsigned int Pattern;
    unsigned int Btn;
    unsigned int X;
    unsigned int Y;
} PS = {0x1234ABFE, 0, 127, 127};

struct js_event
{
    unsigned int time;
    short value;
    unsigned char type;
    unsigned char number;
};

int is_usbdevblock(libusb_device *dev)
{
	struct libusb_device_descriptor desc;
	int r = libusb_get_device_descriptor(dev, &desc);
	if((desc.idVendor == SONY_VENDOR_ID) && (desc.idProduct == PSP_B_PRODUCT_ID))
	{
		return 1;
	}

	return 0;
}

int main(int argc, char** argv)
{
	unsigned int real_x = 0, real_y = 0;
	int x, y;

	int fd = 0;

	while(1)
	{
		libusb_device **list;
		libusb_device *found = NULL;
		libusb_context *ctx = NULL;
		int attached = 0;

		libusb_init(&ctx);
		libusb_set_debug(ctx, 3); 
	
		ssize_t cnt = libusb_get_device_list(ctx, &list);
		ssize_t i = 0;
		int err = 0;
		if(cnt < 0)
		{
			return -1;
		}

		for(i = 0; i < cnt; i++)
		{
			libusb_device *device = list[i];
			if(is_usbdevblock(device))
			{
				found = device;
				break;
			}
		}

		if(found)
		{
			libusb_device_handle *handle;	
			err = libusb_open(found, &handle);
			if (err)
			{
				return -1;
			}

			if (libusb_kernel_driver_active(handle, 0))
			{ 
				libusb_detach_kernel_driver(handle, 0); 
				attached = 1;
			}

			err = libusb_claim_interface(handle, 0);
			if (err)
			{
				return -1;
			}
			
			if(fd == 0)
			{
				fd = open("/dev/input/js0", O_RDONLY);
			}

			if(fd < 0)
			{
				goto clean;
			}
			
			int nEndpoint = 0x01;
			int nTimeout = 500; //in milliseconds
			int BytesWritten = 0;
			int ret;

			struct js_event e;
			int t;

			while(1)
			{
				read(fd, &e, sizeof(struct js_event));
				
				e.type &= ~0x80;
				
				t = 0; //transfer = 0;
				
				if(e.type == 1)
				{
					if(e.value == 1)
					{
						if(e.number == 0) {PS.Btn |= B_X; t = 1;}
						if(e.number == 1) {PS.Btn |= B_O; t = 1;}
						if(e.number == 2) {PS.Btn |= B_KVADRAT; t = 1;}
						if(e.number == 3) {PS.Btn |= B_TREUGOLNIK; t = 1;}
						if(e.number == 4) {PS.Btn |= B_L; t = 1;}
						if(e.number == 5) {PS.Btn |= B_R; t = 1;}
						if(e.number == 6) {PS.Btn |= B_SELECT; t = 1;}
						if(e.number == 7) {PS.Btn |= B_START; t = 1;}
						if(e.number == 8) {PS.Btn |= B_NOTE; t = 1;}//XBOX_HOME
						//if(e.number == 9) PS.Btn |= ;//L_STICK_PRESS
						//if(e.number == 10)PS.Btn |= ;//R_STICK_PRESS
					}
					
					if(e.value == 0)
					{
						if(e.number == 0) {PS.Btn &= ~B_X; t = 1;}
						if(e.number == 1) {PS.Btn &= ~B_O; t = 1;}
						if(e.number == 2) {PS.Btn &= ~B_KVADRAT; t = 1;}
						if(e.number == 3) {PS.Btn &= ~B_TREUGOLNIK; t = 1;}
						if(e.number == 4) {PS.Btn &= ~B_L; t = 1;}
						if(e.number == 5) {PS.Btn &= ~B_R; t = 1;}
						if(e.number == 6) {PS.Btn &= ~B_SELECT; t = 1;}
						if(e.number == 7) {PS.Btn &= ~B_START; t = 1;}
						if(e.number == 8) {PS.Btn &= ~B_NOTE; t = 1;}
					}
				}
				
				if(e.type == 2)
				{
					if(e.number == 6)
					{
						if(e.value == -32767) {PS.Btn |= LEFT; t = 1;}
						if(e.value ==  32767) {PS.Btn |= RIGHT; t = 1;}
						if(e.value ==	0) {PS.Btn &= ~(LEFT | RIGHT); t = 1;}
					}
					if(e.number == 7)
					{
						if(e.value == -32767) {PS.Btn |= UP; t = 1;}
						if(e.value ==  32767) {PS.Btn |= DOWN; t = 1;}
						if(e.value ==	0) {PS.Btn &= ~(UP | DOWN); t = 1;}
					}
					if(e.number == 0)
					{
						if(real_x != ((e.value + 32767) / 256)) {real_x = ((e.value + 32767) / 256); t = 1;}
					}
					if(e.number == 1)
					{
						if(real_y != ((e.value + 32767) / 256)) {real_y = ((e.value + 32767) / 256); t = 1;}
					}
				}
				
				if(t == 1)
				{
					#define KOEF 1.4
					//[-128..0..127]
					x = real_x - 128;
					y = real_y - 128;
					x = x * (1. + ((abs(x) * (KOEF-1.))/(127./KOEF))); if(x > 127) x = 127; if(x < -128) x = -128;
					y = y * (1. + ((abs(y) * (KOEF-1.))/(127./KOEF))); if(y > 127) y = 127; if(y < -128) y = -128;
					PS.X = 128 + x;
					PS.Y = 128 + y;
					
					ret = libusb_bulk_transfer(handle, nEndpoint, (unsigned char *)&PS, sizeof(PS), &BytesWritten, nTimeout);
					if(ret < 0) 
					{
						break;
					}
				}
			}
			
			clean:	
			
			if(fd)
			{
				close(fd);
				fd = 0;
			}

			if(attached == 1)
			{
				libusb_attach_kernel_driver(handle, 0);
			}
			
			libusb_close(handle);
		}

		libusb_free_device_list(list, 1);
		libusb_exit(ctx);
		
		sleep(1);
	}

	return 0;
}

On the face of it the RPi script is not doing anything extensively complex. Communicating with the controller i already have working in my existing Consolizer project. I'm just struggling to find the equivalent libusb methods in USBHost.

Well i found a list of error codes defined in USBCore.h.

Not got time yet to investigate and see if any of them are my code but thats this afternoons jobs.

#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED   0xD1
#define USB_DEV_CONFIG_ERROR_DEVICE_INIT_INCOMPLETE  0xD2
#define USB_ERROR_UNABLE_TO_REGISTER_DEVICE_CLASS      0xD3
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL		0xD4
#define USB_ERROR_HUB_ADDRESS_OVERFLOW			        0xD5
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL		0xD6
#define USB_ERROR_EPINFO_IS_NULL			                        0xD7
#define USB_ERROR_INVALID_ARGUMENT			                0xD8
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE		0xD9
#define USB_ERROR_INVALID_MAX_PKT_SIZE			        0xDA
#define USB_ERROR_EP_NOT_FOUND_IN_TBL			        0xDB
#define USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET   0xE0
#define USB_ERROR_FailGetDevDescr                                            0xE1
#define USB_ERROR_FailSetDevTblEntry                                        0xE2
#define USB_ERROR_FailGetConfDescr                                          0xE3
#define USB_ERROR_TRANSFER_TIMEOUT			               0xFF

Forgive the formatting, tried to present it nicely but it refuses.

OK so the error I'm getting is USB_ERROR_EP_NOT_FOUND_IN_TBL

Logging all the endpoints available for this address and i get a single endpoint 0.

However the RPi script im trying to port writes to endpoint 1.

So one step forwards, two back.

I think I'm going to move to a different platform.

The Raspberry pi pico seems to have a better documented and more widely used USB libraries.

I understand my project is probably too bespoke a thing compared to the more general projects seen on the forums which is why there has been no response.

However if anyone does have any input/advise id still love to hear it.

Worst comes to worst ill just get my hands on a RPi zero and run the script in my OP directly!

Thanks

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.