Steel Battalion Controller LED issues

Status
Not open for further replies.

HackNFly

Member
I'm using a Teensy 4.1 to connect to a Steel Battalion Controller:
320px-Steel_Battalion_controllers.jpg

I have experience with this controller and have already written a driver for it. I was actually able to get it working as a normal joystick fairly easily using the teensy to read the info over usb and emulate a joystick.

My problem comes from writing out commands to control the LEDs using the joystick's only out endpoint.
I reduced my program to the bare minimum needed to run. Currently it turns on LEDs on and off a few times and then stops responding. I'm sending the exact same 32 byte packet in my Windows C# program and it controls the LEDs just fine.

SBCLight.ino
Code:
#include <USBHost_t36.h>
#include "SBCController.h"

USBHost myusb;
USBHub hub1(myusb);
SBCController SBC(myusb); 

long changeTime  = 100;//milliseconds
long currentMillis;
long lastMillis;
bool flipLight = false;

void setup()
{
  Serial1.begin(2000000);
  while (!Serial) ; // wait for Arduino Serial Monitor
 
  myusb.begin();
}

void loop()
{
  currentMillis = millis();
  if(currentMillis - lastMillis > changeTime)
  {
    if(flipLight)
    {
      SBC.txbuf_[5] = 255;
      flipLight = false;
    }
    else
    {
      SBC.txbuf_[5] = 0;
      flipLight = true;      
    }
     SBC.sendLightDataPacket();
     lastMillis = currentMillis;
  }
  myusb.Task();
  
  delay(50);
}

SBCController.cpp
Code:
#include "SBCController.h"

void SBCController::init()
{
	driver_ready_for_device(this);
}

// Again this class is solely to display as much information about a device as we can...
// This all comes from the information passed to it through the claim method.
bool SBCController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len) {
  uint32_t txep = 1;
  uint8_t tx_interval = 4;
  tx_size_ = 32;
 
  txpipe_ = new_Pipe(dev, 3, txep, 0, tx_size_, tx_interval);
  if (!txpipe_) {
    return false;
  }
  txpipe_->callback_function = tx_callback;

 return true;
}

void SBCController::tx_callback(const Transfer_t *transfer)
{
  if (!transfer->driver) return;
  ((SBCController *)(transfer->driver))->tx_data(transfer);
  
}

void SBCController::sendLightDataPacket()
{
  Serial.println("trying to send light");
  queue_Data_Transfer(txpipe_, txbuf_, tx_size_, this);
}

void SBCController::tx_data(const Transfer_t *transfer)
{
   Serial.println("Light Sent");
}

SBController.h
Code:
#ifndef __SBCController_h_
#define __SBCController_h_
#include <Arduino.h>
#include <USBHost_t36.h>


class SBCController : public USBDriver {
public:
	SBCController(USBHost &host) { init();}

 Device_t *currentDevice;

void sendLightDataPacket();

bool firstSent = false;

uint8_t     txbuf_[64];   // buffer to use to send commands to joystick 


void (*data_received)(const Transfer_t *);


protected:
	virtual bool claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len);
	virtual void disconnect() {};
	void init();
  
  uint16_t    tx_size_ = 0;
  Pipe_t      *txpipe_;
  
  static void tx_callback(const Transfer_t *transfer);
  void tx_data(const Transfer_t *transfer);
  Device_t *mydevice = NULL;
};
#endif

Here is an example of the current output with USB Debugging enabled:
Code:
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20003000
periodictable = 20003000
port change: 10001803
    connect
trying to send light
  begin reset
trying to send light
port change: 10001005
  port enabled
  end recovery
new_Device: 12 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 10 01 00 00 00 08 7B 0A 00 D0 00 01 00 00 00 01 
    VendorID = 0A7B, ProductID = D000, Version = 0100
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
Config data length = 32
enumeration:
Configuration Descriptor:
  09 02 20 00 01 01 00 80 FA 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 02 58 42 00 00 
    Interface = 0
    Number of endpoints = 2
    Class/Subclass/Protocol = 88 / 66 / 0
  07 05 82 03 20 00 04 
    Endpoint = 2 IN
    Type = Interrupt
    Max Size = 32
    Polling Interval = 4
  07 05 01 03 20 00 04 
    Endpoint = 1 OUT
    Type = Interrupt
    Max Size = 32
    Polling Interval = 4
enumeration:
USBHub memory usage = 960
USBHub claim_device this=20001E80
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 5, at offset = 0, shift= 0
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
Light Sent
trying to send light
trying to send light
trying to send light
trying to send light

Is there anything obvious I'm missing. I've tried playing around with the tx_size variable. The values for tx_size, tx_interval and txep were determined using the Joystick example by parsing the descriptor. I removed that section of code to make things more concise.
 
Adding some extra information:

This website provides very specific information on the Steel Battalion and Xbox 1 controllers in general.

I thought that may be I needed to use queue_Control_Transfer instead of queue_data_transfer

/*
* from https://xboxdevwiki.net/Xbox_Input_Devices#bType_.3D_128:_Steel_Battalion
*
SET_REPORT
bmRequestType: 0x21
bRequest: 9
wValue: 0x0200
wIndex: Interface number
wLength: <length of report; typically 6>

Code:
mk_setup(setup, 0x21, 9, 0x200, 0, tx_size_); // hopefully this sets leds
  queue_Control_Transfer(device, &setup, txbuf_, this);

But I couldn't get this to work. Everything locked up when I tried that. I also tried setting byte 1 of the packet array to 22 as specified on the website to indicate the packet length, but this didn't work either.

One last thing, the whole code won't work if I don't have the USBHub part of the code enabled. I wonder if adding an intermediate hub might somehow help.
 
Last edited:
Happy to say I resolved it. I saw another user mentioning something that they had to use a usb hub in between the controller and their project in order for it to work. Mine was I was not getting enough power connecting through my usb hub to the computer. I tried plugging the hub in between the controller and the device and it didn't work at all. The hub has lights on it and no lights came on. Maybe I need a simpler hub or something else, I don't know. I connected the Teensy4.1 directly to the computer and it worked at any speed. I did learn from this issue that I've been using too big a packet. Apparently it's only supposed to be 22 bytes long and not 32. Also the second byte is supposed to be 0x16 to indicate the packet length, but the device doesn't seem to care.
 
Status
Not open for further replies.
Back
Top