Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 2 #2

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
90 changes: 90 additions & 0 deletions XBOXChatpadEnums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/* Copyright (C) 2020 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").

Based on the project from here: https://github.com/Kytech/xbox360wirelesschatpad
*/

#ifndef _xbox_chatpad_enums_h_
#define _xbox_chatpad_enums_h_

enum ChatpadModiferEnum {
MODIFER_SHIFT = 0,
MODIFER_GREENBUTTON = 1,
MODIFER_ORANGEBUTTON = 2,
MODIFER_MESSENGER = 3
};

enum ChatpadLEDEnum {
CHATPADLED_CAPSLOCK = 0,
CHATPADLED_GREEN = 1,
CHATPADLED_ORANGE = 2,
CHATPADLED_MESSENGER = 3,

__NUM_CHATPAD_LED
};

/** Buttons on the chatpad
* This only accounts for the main keys and does not
* use the modifiers (orange/green)
*/
enum ChatpadButtonEnum {
XBOX_CHATPAD_D7 = 0,
XBOX_CHATPAD_D6 = 1,
XBOX_CHATPAD_D5 = 2,
XBOX_CHATPAD_D4 = 3,
XBOX_CHATPAD_D3 = 4,
XBOX_CHATPAD_D2 = 5,
XBOX_CHATPAD_D1 = 6,

XBOX_CHATPAD_U = 8,
XBOX_CHATPAD_Y = 9,
XBOX_CHATPAD_T = 10,
XBOX_CHATPAD_R = 11,
XBOX_CHATPAD_E = 12,
XBOX_CHATPAD_W = 13,
XBOX_CHATPAD_Q = 14,

XBOX_CHATPAD_J = 16,
XBOX_CHATPAD_H = 17,
XBOX_CHATPAD_G = 18,
XBOX_CHATPAD_F = 19,
XBOX_CHATPAD_D = 20,
XBOX_CHATPAD_S = 21,
XBOX_CHATPAD_A = 22,

XBOX_CHATPAD_M = 33,
XBOX_CHATPAD_N = 24,
XBOX_CHATPAD_B = 25,
XBOX_CHATPAD_V = 26,
XBOX_CHATPAD_C = 27,
XBOX_CHATPAD_X = 28,
XBOX_CHATPAD_Z = 29,

XBOX_CHATPAD_RIGHT = 32,
XBOX_CHATPAD_SPACE = 35,
XBOX_CHATPAD_LEFT = 36,

XBOX_CHATPAD_COMMA = 41,
XBOX_CHATPAD_PERIOD = 34,
XBOX_CHATPAD_ENTER = 42,
XBOX_CHATPAD_P = 43,
XBOX_CHATPAD_D0 = 44,
XBOX_CHATPAD_D9 = 45,
XBOX_CHATPAD_D8 = 46,

XBOX_CHATPAD_BACK = 48,
XBOX_CHATPAD_L = 49,
XBOX_CHATPAD_O = 52,
XBOX_CHATPAD_I = 53,
XBOX_CHATPAD_K = 54,

__XBOX_CHATPAD_ENUM_MAX
};

#endif
169 changes: 169 additions & 0 deletions XBOXRECV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ uint8_t XBOXRECV::Poll() {
checkStatus();
}

sendChatpadInitIfNeeded();

uint8_t inputPipe;
uint16_t bufferSize;
for(uint8_t i = 0; i < 4; i++) {
Expand Down Expand Up @@ -364,6 +366,11 @@ void XBOXRECV::readReport(uint8_t controller) {
controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4];
return;
}
if(readBuf[1] == 0x02) {
// Chatpad data
processChatpadData(controller, readBuf);
return;
}
if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
return;

Expand Down Expand Up @@ -407,6 +414,92 @@ void XBOXRECV::printReport(uint8_t controller __attribute__((unused)), uint8_t n
#endif
}


void XBOXRECV::processChatpadData(uint8_t controller, uint8_t* dataPacket) {
// This function is called anytime received data is identified as chatpad data
// It will parse the data, and depending on the value, send a keyboard command,
// adjust a modifier for later use, flag initialization, or note the LED status.
if (dataPacket[24] == 0xF0) {
if (dataPacket[25] == 0x03) {
// This data represents handshake request, flag keep-alive to send
// chatpad initialization data.
chatpadInitNeeded[controller] = true;
}
else if (dataPacket[25] == 0x04) {
// This data represents the LED status. Not used because unsure of workings
//chatpadLED["Green"] = (dataPacket[26] & 0x08) > 0;
//chatpadLED["Orange"] = (dataPacket[26] & 0x10) > 0;
//chatpadLED["Messenger"] = (dataPacket[26] & 0x01) > 0;
//chatpadLED["Capslock"] = (dataPacket[26] & 0x20) > 0;
//Backlight = (dataPacket[26] & 0x80) > 0;
}
else {
// TODO: How to deal with invalid data?
return;
}
}
else if (dataPacket[24] == 0x00) {
// This data represents a key-press event
// Check if anything has changed since the last dataPacket
bool dataChanged = false;
if (!firstChatpadRun) {
if (chatpadDataPacketLast[controller][0] != dataPacket[25]) {
dataChanged = true;
}
else if (chatpadDataPacketLast[controller][1] != dataPacket[26]) {
dataChanged = true;
}
else if (chatpadDataPacketLast[controller][2] != dataPacket[27]) {
dataChanged = true;
}
}
else {
firstChatpadRun = false;
dataChanged = true;
}

// Store bits 25-27 of the data packet for later comparison
chatpadDataPacketLast[controller][0] = dataPacket[25];
chatpadDataPacketLast[controller][1] = dataPacket[26];
chatpadDataPacketLast[controller][2] = dataPacket[27];

if (dataChanged)
{
// Record the Modifier Statuses
chatpadModState[controller] = dataPacket[25];

// Process the two different possible keys that could be held down
ProcessChatpadKeypress(controller, dataPacket[26]);
ProcessChatpadKeypress(controller, dataPacket[27]);

if(chatpadClickState[controller] != chatpadClickStateOld[controller]) {
chatpadStateChanged[controller] = true;
chatpadClickStateOld[controller] = chatpadClickState[controller];
}

if(chatpadModState[controller] != chatpadModStateOld[controller]) {
// Update click state variable
chatpadModClickState[controller] = (chatpadModState[controller]) & ((~chatpadModStateOld[controller]));
chatpadModStateOld[controller] = chatpadModState[controller];
}
}
}
else {
// TODO: Handle invalid data
}
}

void XBOXRECV::ProcessChatpadKeypress(uint8_t controller, uint8_t value) {
value = (((value & 0xF0) - 0x10) >> 1) | ((value & 0x0F) - 1);

if (value > __XBOX_CHATPAD_ENUM_MAX) {
// Invalid button
return;
}

chatpadClickState[controller] |= (((uint64_t)1) << ((uint64_t)value));
}

uint8_t XBOXRECV::getButtonPress(ButtonEnum b, uint8_t controller) {
if(b == L2) // These are analog buttons
return (uint8_t)(ButtonState[controller] >> 8);
Expand Down Expand Up @@ -445,6 +538,30 @@ bool XBOXRECV::buttonChanged(uint8_t controller) {
return state;
}

bool XBOXRECV::getChatpadModifierPress(ChatpadModiferEnum b, uint8_t controller) {
return (bool)(chatpadModState[controller] & (1 << b));
}

bool XBOXRECV::getChatpadModifierClick(ChatpadModiferEnum b, uint8_t controller) {
uint8_t mask = (1 << b);
bool click = (chatpadModClickState[controller] & mask);
chatpadModClickState[controller] &= ~mask; // clear "click" event
return click;
}

bool XBOXRECV::chatpadChanged(uint8_t controller) {
bool state = chatpadStateChanged[controller];
chatpadStateChanged[controller] = false;
return state;
}

bool XBOXRECV::getChatpadClick(ChatpadButtonEnum b, uint8_t controller) {
uint64_t mask = ((uint64_t)1) << ((uint64_t)b);
bool click = (chatpadClickState[controller] & mask);
chatpadClickState[controller] &= ~mask; // clear "click" event
return click;
}

/*
ControllerStatus Breakdown
ControllerStatus[controller] & 0x0001 // 0
Expand Down Expand Up @@ -524,6 +641,22 @@ void XBOXRECV::setLedBlink(LEDEnum led, uint8_t controller) {
setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]), controller);
}


void XBOXRECV::setChatpadLed(ChatpadLEDEnum ledNumber, bool value, uint8_t controller) {
uint8_t ledOnByte[4] = {0x08, 0x09, 0x0A, 0x0B};
uint8_t ledOffByte[4] = {0x00, 0x01, 0x02, 0x03};
writeBuf[0] = 0x00;
writeBuf[1] = 0x00;
writeBuf[2] = 0x0C;

if (value) {
writeBuf[3] = 0x08 + ledNumber;
} else {
writeBuf[3] = ledNumber;
}
XboxCommand(controller, writeBuf, 4);
}

void XBOXRECV::setLedMode(LEDModeEnum ledMode, uint8_t controller) { // This function is used to do some speciel LED stuff the controller supports
setLedRaw((uint8_t)ledMode, controller);
}
Expand Down Expand Up @@ -552,6 +685,42 @@ void XBOXRECV::checkStatus() {
if(Xbox360Connected[i])
XboxCommand(i, writeBuf, 4);
}

// Keep Alive 1
writeBuf[0] = 0x00;
writeBuf[1] = 0x00;
writeBuf[2] = 0x0C;
writeBuf[3] = 0x1F;
for(uint8_t i = 0; i < 4; i++) {
if(Xbox360Connected[i])
XboxCommand(i, writeBuf, 4);
}
// Keep Alive 2
writeBuf[0] = 0x00;
writeBuf[1] = 0x00;
writeBuf[2] = 0x0C;
writeBuf[3] = 0x1F;
for(uint8_t i = 0; i < 4; i++) {
if(Xbox360Connected[i])
XboxCommand(i, writeBuf, 4);
}
}

void XBOXRECV::sendChatpadInitIfNeeded() {
// ChatpadInit
writeBuf[0] = 0x00;
writeBuf[1] = 0x00;
writeBuf[2] = 0x0C;
writeBuf[3] = 0x1B;
for(uint8_t i = 0; i < 4; i++) {
if(chatpadInitNeeded[i]) {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nSending Chatpad Init to controller"), 0x80);
#endif
XboxCommand(i, writeBuf, 4);
chatpadInitNeeded[i] = false;
}
}
}

void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) {
Expand Down
33 changes: 33 additions & 0 deletions XBOXRECV.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "Usb.h"
#include "xboxEnums.h"
#include "XBOXChatpadEnums.h"

/* Data Xbox 360 taken from descriptors */
#define EP_MAXPKTSIZE 32 // max size for data via USB
Expand Down Expand Up @@ -223,6 +224,17 @@ class XBOXRECV : public USBDeviceConfig {
void attachOnInit(void (*funcOnInit)(void)) {
pFuncOnInit = funcOnInit;
};

bool getChatpadModifier(ChatpadModiferEnum b, uint8_t controller = 0);
bool getChatpadClick(ChatpadButtonEnum b, uint8_t controller = 0);
bool chatpadChanged(uint8_t controller = 0);

/**
* Set the chatpad LEDs on or off
* @param ledNumber Capslock = 0, Green = 1, Orange = 2, Messanger = 3
* @param controller The controller to read from. Default to 0.
*/
void setChatpadLed(ChatpadLEDEnum led, bool value, uint8_t controller = 0);
/**@}*/

/** True if a wireless receiver is connected. */
Expand Down Expand Up @@ -272,5 +284,26 @@ class XBOXRECV : public USBDeviceConfig {
/* Private commands */
void XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes);
void checkStatus();

/* Chatpad Commands */
void sendChatpadInitIfNeeded();
void processChatpadData(uint8_t controller, uint8_t* epBuffer);
void ProcessChatpadKeypress(uint8_t controller, uint8_t value);

/* Chatpad State */
bool firstChatpadRun = true;
bool chatpadInitNeeded[4] = { true };
uint8_t chatpadModRaw[4] = {0};
uint8_t chatpadModState[4] = {0};
uint8_t chatpadModRawOld[4] = {0};
uint8_t chatpadModClickState[4] = {0};
uint8_t chatpadDataPacketLast[4][3];
bool flagUpperCase = false;

/* Variables to store chatpad buttons */
uint64_t chatpadClickState[4];
uint64_t chatpadClickStateOld[4];
bool chatpadStateChanged[4]; // True if a button has changed
};
#endif