Improved the reconnecting and fixes some issues about the connection.

This should be pretty stable now =)
Code is not really beautiful atm, but better commit it before I break it
again!
This commit is contained in:
Maschell 2017-02-06 20:40:48 +01:00
parent 3918a71627
commit a479bb14ee
6 changed files with 138 additions and 43 deletions

View File

@ -44,6 +44,7 @@ public class GuiInputControls extends JPanel implements ActionListener {
private static final String CONNECT = "Connect";
private static final String DISCONNECT = "Disconnect";
private static final String RECONNECTING = "Reconnecting";
private JButton connectButton;
private JTextField ipTextBox;
@ -93,10 +94,15 @@ public class GuiInputControls extends JPanel implements ActionListener {
int delay = 100; //milliseconds
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(NetworkManager.getInstance().isConnected()){
if(NetworkManager.getInstance().isReconnecting()){
connectButton.setText(RECONNECTING);
connectButton.setEnabled(false);
}else if(NetworkManager.getInstance().isConnected()){
connectButton.setText(DISCONNECT);
connectButton.setEnabled(true);
}else{
connectButton.setText(CONNECT);
connectButton.setEnabled(true);
}
}
};
@ -127,10 +133,14 @@ public class GuiInputControls extends JPanel implements ActionListener {
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if(NetworkManager.getInstance().isConnected()){
NetworkManager.getInstance().disconnect();
}else{
NetworkManager.getInstance().connect(ipTextBox.getText());
if(NetworkManager.getInstance().isReconnecting()){
}else{
if(NetworkManager.getInstance().isConnected()){
NetworkManager.getInstance().disconnect();
}else{
NetworkManager.getInstance().connect(ipTextBox.getText());
}
}
}
});

View File

@ -129,4 +129,13 @@ public class ActiveControllerManager implements Runnable{
}
}
}
public void attachAllActiveControllers() {
synchronized (activeControllers) {
for(Entry<Controller, NetworkHIDDevice> entry : activeControllers.entrySet()){
NetworkHIDDevice device = entry.getValue();
device.sendAttach();
}
}
}
}

View File

@ -65,7 +65,10 @@ public class ControllerManager{
connectedDevices.putAll(detectWindowsControllers());
}
//TODO: Enable HID4Java again
/*TODO: Enable HID4Java again. Currently it's disabled because
* We can either use the WiiU directly OR have XInput anyway.
* Adding an option menu for enabling it?
*/
//connectedDevices.putAll(detectHIDDevices());
//Remove detached devices
@ -100,9 +103,15 @@ public class ControllerManager{
//e.printStackTrace();
}
break;
/*
* TODO:
* Currently the XInput will be set active automatically.
* But this should move to something for the settings?
*/
case XINPUT14:
try {
c = new XInput14Controller(deviceIdentifier);
c.setActive(true);
} catch (ControllerInitializationFailedException e) {
//e.printStackTrace();
}
@ -110,6 +119,7 @@ public class ControllerManager{
case XINPUT13:
try {
c = new XInput13Controller(deviceIdentifier);
c.setActive(true);
} catch (ControllerInitializationFailedException e) {
//e.printStackTrace();
}

View File

@ -44,6 +44,9 @@ public class NetworkManager implements Runnable{
private UDPClient udpClient = null;
private static NetworkManager instance = null;
private List<DeviceCommand> ownCommands = new ArrayList<>();
private NetworkManager() {
}
@ -80,8 +83,8 @@ public class NetworkManager implements Runnable{
int i = 0;
while(true){
proccessCommands();
Utilities.sleep(10);
if(i++ > 1000/10){
Utilities.sleep(10);//TODO: move magic value to Settings
if(i++ > 1000/10){//TODO: move magic value to Settings
ping();
i = 0;
}
@ -89,11 +92,13 @@ public class NetworkManager implements Runnable{
}
private void ping() {
if(isConnected())sendingCommand(new PingCommand());
if(isConnected() || tcpClient.isShouldRetry())sendingCommand(new PingCommand());
}
public void proccessCommands(){
List<DeviceCommand> commands = new ArrayList<>();
commands.addAll(ownCommands); //TODO: Does this need a synchronized block? It _should_ be only access from this thread. Need to think about it
ownCommands.clear();
synchronized (toRemove) {
synchronized (devices) {
for(NetworkHIDDevice device : getDevices()){
@ -135,15 +140,30 @@ public class NetworkManager implements Runnable{
}
private void sendingCommand(DeviceCommand command) {
if(command instanceof AttachCommand){
sendAttach((AttachCommand) command);
}else if(command instanceof DetachCommand){
sendDetach((DetachCommand) command);
}else if(command instanceof PingCommand){
sendPing((PingCommand) command);
boolean result = false;
if(isConnected() || tcpClient.isShouldRetry()){
if(command instanceof AttachCommand){
result = sendAttach((AttachCommand) command);
}else if(command instanceof DetachCommand){
result = sendDetach((DetachCommand) command);
}else if(command instanceof PingCommand){
sendPing((PingCommand) command);
result = true;
}else{
log.info("UNKNOWN COMMAND!");
result = true;
}
}else{
Utilities.sleep(500); //TODO: move magic value to Settings
}
//Add the command again on errors
if(!result){
addCommand(command);
}
}
//TODO: PONG from WiiU? Hey Quark ;)
private void sendPing(PingCommand command) {
if(sendTCP(Protocol.getRawPingDataToSend(command))){
log.info("PING");
@ -152,27 +172,32 @@ public class NetworkManager implements Runnable{
}
}
private void sendDetach(DetachCommand command) {
private boolean sendDetach(DetachCommand command) {
byte[] sendData;
try {
sendData = Protocol.getRawDetachDataToSend(command);
if(!sendTCP(sendData)){
if(sendTCP(sendData)){
log.info("Success detach command for device (" + command.getSender() + ") sent!");
}else{
log.info("Sending the detach command for device (" + command.getSender() + ") failed. sendTCP failed");
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
private void sendAttach(AttachCommand command) {
//TODO: Maybe move it into the Protocol class?
private boolean sendAttach(AttachCommand command) {
//Send the TCP command
byte[] sendData = null;
try {
sendData = Protocol.getRawAttachDataToSend(command);
}catch (IOException e) {
log.info("Building the attach command for device (" + command.getSender() + ") failed." + e.getMessage());
return;
return false;
}
if(sendTCP(sendData)){
byte configFound = 0;
@ -182,13 +207,14 @@ public class NetworkManager implements Runnable{
e1.printStackTrace();
}
if(configFound == Protocol.TCP_CMD_ATTACH_CONFIG_FOUND){
log.info("Config on the console found!");
//log.info("Config on the console found!");
}else if(configFound == Protocol.TCP_CMD_ATTACH_CONFIG_NOT_FOUND){
log.info("NO CONFIG FOUND.");
return;
return false;
}else if (configFound == 0){
log.info("Failed to get byte.");
disconnect();
return false;
}
byte userDataOkay = 0;
@ -198,13 +224,14 @@ public class NetworkManager implements Runnable{
e1.printStackTrace();
}
if(userDataOkay == Protocol.TCP_CMD_ATTACH_USERDATA_OKAY){
log.info("userdata okay!");
//log.info("userdata okay!");
}else if(userDataOkay == Protocol.TCP_CMD_ATTACH_USERDATA_BAD){
log.info("USERDATA BAD.");
return;
return false;
}else if (userDataOkay == 0){
log.info("Failed to get byte.");
disconnect();
return false;
}
//We receive our device slot and pad slot
@ -215,11 +242,13 @@ public class NetworkManager implements Runnable{
padslot = recvTCPByte();
} catch (IOException e) {
log.info("Recieving data after sending a attach failed for device (" + command.getSender() + ") failed." + e.getMessage());
return false;
}
if(deviceslot < 0 || padslot < 0){
log.info("Recieving data after sending a attach failed for device (" + command.getSender() + ") failed. We need to disconnect =(");
disconnect();
return false;
}
//Let's save them for later.
@ -229,10 +258,13 @@ public class NetworkManager implements Runnable{
sender.setPadslot(padslot);
}else{
log.info("Something really went wrong. Got an attach event with out an " + NetworkHIDDevice.class.getSimpleName());
return false;
}
log.info("Attaching done!");
return true;
}else{
log.info("Sending the attach command for device (" + command.getSender() + ") failed. sendTCP failed");
return false;
}
}
@ -268,7 +300,6 @@ public class NetworkManager implements Runnable{
tcpClient.send(rawCommand);
result = true;
} catch (Exception e) {
//
result = false;
}
}
@ -276,7 +307,7 @@ public class NetworkManager implements Runnable{
}
public void disconnect() {
ControllerManager.deactivateAllAttachedControllers();
//ControllerManager.deactivateAllAttachedControllers();
tcpClient.abort();
}
@ -287,7 +318,6 @@ public class NetworkManager implements Runnable{
private byte recvTCPByte() throws IOException {
return tcpClient.recvByte();
}
public boolean isConnected() {
return (tcpClient != null && tcpClient.isConnected());
@ -308,4 +338,12 @@ public class NetworkManager implements Runnable{
}
return result;
}
public void addCommand(DeviceCommand command) {
this.ownCommands.add(command);
}
public boolean isReconnecting() {
return !tcpClient.isConnected() && tcpClient.isShouldRetry();
}
}

View File

@ -29,51 +29,69 @@ import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.SynchronousQueue;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;
import net.ash.HIDToVPADNetworkClient.manager.ActiveControllerManager;
import net.ash.HIDToVPADNetworkClient.network.Protocol.HandshakeReturnCode;
import net.ash.HIDToVPADNetworkClient.util.HandleFoundry;
import net.ash.HIDToVPADNetworkClient.util.Settings;
@Log
public class TCPClient {
private Socket sock;
private DataInputStream in;
private DataOutputStream out;
@Getter private int clientID = HandleFoundry.next();
@Getter @Setter(AccessLevel.PRIVATE)
private int shouldRetry = Settings.MAXIMUM_TRIES_FOR_RECONNECTING;
private String ip;
public TCPClient() {
}
public synchronized void connect(String ip) throws Exception {
this.ip = ip;
sock = new Socket();
sock.connect(new InetSocketAddress(ip, Protocol.TCP_PORT), 30000);
sock.connect(new InetSocketAddress(ip, Protocol.TCP_PORT), 2000);
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
if(doHandshake() == HandshakeReturnCode.BAD_HANDSHAKE){
throw new Exception();
}
HandshakeReturnCode resultHandshake = doHandshake();
if(resultHandshake == HandshakeReturnCode.BAD_HANDSHAKE){
log.info("[TCP] Handshaking failed");
throw new Exception();
}else{
if(resultHandshake == HandshakeReturnCode.NEW_CLIENT && this.ip != null){
//We check the IP to be sure it's the first time we connect to a WiiU. //TODO: Sending a ID from the WiiU which will be compared?
//we are new to the client.
ActiveControllerManager.getInstance().attachAllActiveControllers();
}else if(resultHandshake == HandshakeReturnCode.SAME_CLIENT){
}
this.ip = ip;
shouldRetry = 0;
}
}
private synchronized HandshakeReturnCode doHandshake() throws Exception {
if (recvByte() != Protocol.TCP_HANDSHAKE) return HandshakeReturnCode.BAD_HANDSHAKE;
if (recvByte() != Protocol.TCP_HANDSHAKE) return HandshakeReturnCode.BAD_HANDSHAKE;
send(clientID);
System.out.println("clientID:" + clientID);
System.out.println("[TCP] Handshaking...");
log.info("[TCP] Handshaking...");
HandshakeReturnCode test = (recvByte() == Protocol.TCP_NEW_CLIENT) ? HandshakeReturnCode.NEW_CLIENT : HandshakeReturnCode.SAME_CLIENT;
System.out.println(test);
return test;
}
public synchronized boolean abort(){
try {
shouldRetry = Settings.MAXIMUM_TRIES_FOR_RECONNECTING;
sock.close();
clientID = HandleFoundry.next();
} catch (IOException e) {
System.out.println(e.getMessage());
System.out.println(e.getMessage()); //TODO: handle
return false;
}
return true;
@ -85,10 +103,15 @@ public class TCPClient {
out.flush();
}catch(IOException e){
try {
connect(ip); //TODO: this is for reconnecting when the WiiU switches the application. But this breaks disconnecting, woops.
if(shouldRetry++ < Settings.MAXIMUM_TRIES_FOR_RECONNECTING){
System.out.println("Trying again to connect! Attempt number " + shouldRetry);
connect(ip); //TODO: this is for reconnecting when the WiiU switches the application. But this breaks disconnecting, woops.
}else{
abort();
}
} catch (Exception e1) {
e1.printStackTrace();
}
//e1.printStackTrace();
}
throw e;
}
}
@ -118,4 +141,8 @@ public class TCPClient {
public synchronized boolean isConnected(){
return (sock != null && sock.isConnected() && !sock.isClosed());
}
public boolean isShouldRetry() {
return this.shouldRetry < Settings.MAXIMUM_TRIES_FOR_RECONNECTING;
}
}

View File

@ -24,6 +24,7 @@ package net.ash.HIDToVPADNetworkClient.util;
public class Settings {
public static final int DETECT_CONTROLLER_INTERVAL = 1000;
public static final int HANDLE_INPUTS_INTERVAL = 15;
public static final int MAXIMUM_TRIES_FOR_RECONNECTING = 10;
private Settings(){}