Initial commit for the SteelSeries SRW-S1 Steering Wheel

This commit is contained in:
Kristian Sloth Lauszus 2016-02-20 02:25:10 +01:00
parent 3ca6ddd8d4
commit c0f0ae4cb9
3 changed files with 279 additions and 0 deletions

View file

@ -0,0 +1,140 @@
/* Copyright (C) 2016 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#include "SRWS1.h"
enum DPADEnum {
DPAD_UP = 0x0,
DPAD_UP_RIGHT = 0x1,
DPAD_RIGHT = 0x2,
DPAD_RIGHT_DOWN = 0x3,
DPAD_DOWN = 0x4,
DPAD_DOWN_LEFT = 0x5,
DPAD_LEFT = 0x6,
DPAD_LEFT_UP = 0x7,
DPAD_OFF = 0xF,
};
void SRWS1::ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
if (HIDUniversal::VID != STEELSERIES_VID || HIDUniversal::PID != STEELSERIES_SRWS1_PID) // Make sure the right device is actually connected
return;
#if 0
if (len && buf) {
Notify(PSTR("\r\n"), 0x80);
for (uint8_t i = 0; i < len; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
}
#else
memcpy(&srws1Data, buf, min(len, sizeof(srws1Data)));
if (srws1Data.leftTrigger) {
Serial.print(F("L2: "));
Serial.println(srws1Data.leftTrigger);
}
if (srws1Data.rightTrigger) {
Serial.print(F("R2: "));
Serial.println(srws1Data.rightTrigger);
}
if (srws1Data.btn.select) {
//Serial.println("Select");
Serial.println(srws1Data.tilt);
}
if (srws1Data.btn.back) Serial.println(F("Back"));
if (srws1Data.btn.lookLeft) Serial.println(F("Look Left"));
if (srws1Data.btn.lights) Serial.println(F("Lights"));
if (srws1Data.btn.lookBack) Serial.println(F("Look Back"));
if (srws1Data.btn.rearBrakeBalance) Serial.println(F("R. Brake Balance"));
if (srws1Data.btn.frontBrakeBalance) Serial.println(F("F. Brake Balance"));
if (srws1Data.btn.requestPit) Serial.println(F("Request Pit"));
if (srws1Data.btn.leftGear) Serial.println(F("Left Gear"));
if (srws1Data.btn.camera) Serial.println(F("Camera"));
if (srws1Data.btn.lookRight) Serial.println(F("Look right"));
if (srws1Data.btn.boost) Serial.println(F("Boost"));
if (srws1Data.btn.horn) Serial.println(F("Horn"));
if (srws1Data.btn.hud) Serial.println(F("HUD"));
if (srws1Data.btn.launchControl) Serial.println(F("Launch Control"));
if (srws1Data.btn.speedLimiter) Serial.println(F("Speed Limiter"));
if (srws1Data.btn.rightGear) Serial.println(F("Right gear"));
static SRWS1DataButtons buttonClickState, oldButtonState;
if (srws1Data.btn.val != oldButtonState.val) { // Check if anything has changed
buttonClickState.val = srws1Data.btn.val & ~oldButtonState.val; // Update click state variable
oldButtonState.val = srws1Data.btn.val;
}
if (buttonClickState.lights) {
buttonClickState.lights = 0; // Clear event
static uint16_t leds = 0;
leds = leds << 1 | 1;
if (leds == 0xFFFF)
leds = 0; // Clear LEDs variable
setLeds(leds); // Note: disable the strobe light effect
}
if (srws1Data.assists) Serial.println(srws1Data.assists);
if (srws1Data.steeringSensitivity) Serial.println(srws1Data.steeringSensitivity);
if (srws1Data.assistValues) Serial.println(srws1Data.assistValues);
switch (srws1Data.btn.dpad) {
case DPAD_UP:
Serial.println(F("Up"));
break;
case DPAD_UP_RIGHT:
Serial.println(F("UP & RIGHT"));
break;
case DPAD_RIGHT:
Serial.println(F("Right"));
break;
case DPAD_RIGHT_DOWN:
Serial.println(F("Right & down"));
break;
case DPAD_DOWN:
Serial.println(F("Down"));
break;
case DPAD_DOWN_LEFT:
Serial.println(F("Down & left"));
break;
case DPAD_LEFT:
Serial.println(F("Left"));
break;
case DPAD_LEFT_UP:
Serial.println(F("Left & up"));
break;
case DPAD_OFF:
break;
default:
Serial.print(F("Unknown state: "));
D_PrintHex<uint8_t > (srws1Data.btn.dpad, 0x80);
Serial.println();
break;
}
#endif
}
// See: https://github.com/torvalds/linux/blob/master/drivers/hid/hid-steelseries.c
void SRWS1::setLeds(uint16_t leds) {
uint8_t buf[3];
buf[0] = 0x40; // Report ID
buf[1] = leds & 0xFF;
buf[2] = leds >> 8;
pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf);
}

View file

@ -0,0 +1,82 @@
/* Copyright (C) 2016 Kristian Lauszus, TKJ Electronics. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : kristianl@tkjelectronics.com
*/
#ifndef __srws1_h__
#define __srws1_h__
#include <hiduniversal.h>
#define STEELSERIES_VID 0x1038
#define STEELSERIES_SRWS1_PID 0x1410
union SRWS1DataButtons {
struct {
uint8_t dpad : 4;
uint8_t dummy : 3;
uint8_t select : 1;
uint8_t back : 1;
uint8_t lookLeft : 1;
uint8_t lights : 1;
uint8_t lookBack : 1;
uint8_t rearBrakeBalance : 1;
uint8_t frontBrakeBalance : 1;
uint8_t requestPit : 1;
uint8_t leftGear : 1;
uint8_t camera : 1;
uint8_t lookRight : 1;
uint8_t boost : 1;
uint8_t horn : 1;
uint8_t hud : 1;
uint8_t launchControl : 1;
uint8_t speedLimiter : 1;
uint8_t rightGear : 1;
} __attribute__((packed));
uint32_t val : 24;
} __attribute__((packed));
struct SRWS1Data {
int16_t tilt; // Range [-1800:1800]
uint16_t rightTrigger : 12; // Range [0:1023] i.e. only 10 bits
uint16_t leftTrigger : 12; // Range [0:1023] i.e. only 10 bits
SRWS1DataButtons btn;
uint8_t assists : 4;
uint8_t steeringSensitivity : 4;
uint8_t assistValues : 4;
} __attribute__((packed));
class SRWS1 : public HIDUniversal {
public:
SRWS1(USB *p) : HIDUniversal(p) {};
bool connected() {
return HIDUniversal::isReady() && HIDUniversal::VID == STEELSERIES_VID && HIDUniversal::PID == STEELSERIES_SRWS1_PID;
};
void setLeds(uint16_t leds);
private:
void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); // Called by the HIDUniversal library
uint8_t OnInitSuccessful() { // Called by the HIDUniversal library on success
if (HIDUniversal::VID != STEELSERIES_VID || HIDUniversal::PID != STEELSERIES_SRWS1_PID) // Make sure the right device is actually connected
return 1;
setLeds(0);
return 0;
};
SRWS1Data srws1Data;
};
#endif

View file

@ -0,0 +1,57 @@
/*
Example sketch for the SteelSeries SRW-S1 Steering Wheel - developed by Kristian Lauszus
For more information visit my blog: http://blog.tkjelectronics.dk/ or
send me an e-mail: kristianl@tkjelectronics.com
*/
#include <SPI.h>
#include "SRWS1.h"
USB Usb;
SRWS1 srw1(&Usb);
void setup() {
Serial.begin(115200);
#if !defined(__MIPSEL__)
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
if (Usb.Init() == -1) {
Serial.print(F("\r\nOSC did not start"));
while (1); // Halt
}
Serial.println(F("\r\nSteelSeries SRW-S1 Steering Wheel example started"));
}
void loop() {
Usb.Task();
if (srw1.connected()) {
#if 1 // Set to 1 in order to show a crazy strobe light effect
static uint32_t timer;
if (millis() - timer > 12) {
timer = millis(); // Reset timer
static uint16_t leds = 0;
/*D_PrintHex<uint16_t > (leds, 0x80);
Serial.println();*/
srw1.setLeds(leds); // Update LEDs
static bool dirUp = true;
if (dirUp) {
leds <<= 1;
if (leds == 0x8000) // All are actually turned off, as there is only 15 LEDs
dirUp = false; // If we have reached the end i.e. all LEDs are off, then change direction
if (!(leds & 0x8000)) // If last bit is not set set the lowest bit
leds |= 1; // Set lowest bit
} else {
leds >>= 1;
if (leds == 0) // Check if all LEDs are off
dirUp = true; // If all LEDs are off, then repeat the sequence
if (!(leds & 0x1)) // If last bit is not set set the lowest bit
leds |= 1 << 15; // Set top bit
}
}
#endif
}
}