Added basic floppy drives #3.

This commit is contained in:
simon 2017-11-14 17:25:12 -05:00
parent da7d050661
commit cfb8050cee
13 changed files with 318 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package net.simon987.cubotplugin; package net.simon987.cubotplugin;
import net.simon987.server.GameServer; import net.simon987.server.GameServer;
import net.simon987.server.assembly.Memory;
import net.simon987.server.game.ControllableUnit; import net.simon987.server.game.ControllableUnit;
import net.simon987.server.game.Direction; import net.simon987.server.game.Direction;
import net.simon987.server.game.GameObject; import net.simon987.server.game.GameObject;
@ -29,6 +30,8 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
private ArrayList<Integer> keyboardBuffer = new ArrayList<>(); private ArrayList<Integer> keyboardBuffer = new ArrayList<>();
private FloppyDisk floppyDisk;
private User parent; private User parent;
private int energy; private int energy;
@ -181,4 +184,9 @@ public class Cubot extends GameObject implements Updatable, ControllableUnit {
public int getMaxEnergy() { public int getMaxEnergy() {
return maxEnergy; return maxEnergy;
} }
@Override
public Memory getFloppyData() {
return ((CubotFloppyDrive) getParent().getCpu().getHardware(CubotFloppyDrive.DEFAULT_ADDRESS)).getFloppy().getMemory();
}
} }

View File

@ -0,0 +1,105 @@
package net.simon987.cubotplugin;
import net.simon987.server.GameServer;
import net.simon987.server.assembly.CpuHardware;
import net.simon987.server.assembly.Status;
import org.json.simple.JSONObject;
public class CubotFloppyDrive extends CpuHardware {
/**
* Hardware ID (Should be unique)
*/
static final char HWID = 0x000B;
public static final int DEFAULT_ADDRESS = 0x000B;
private static final int POLL = 1;
private static final int READ_SECTOR = 2;
private static final int WRITE_SECTOR = 3;
private Cubot cubot;
private FloppyDisk floppyDisk;
public CubotFloppyDrive(Cubot cubot) {
this.cubot = cubot;
this.floppyDisk = new FloppyDisk();//todo remove
}
@Override
public void handleInterrupt(Status status) {
int a = getCpu().getRegisterSet().getRegister("A").getValue();
if (a == POLL) {
if (floppyDisk != null) {
getCpu().getRegisterSet().getRegister("B").setValue(0);
} else {
getCpu().getRegisterSet().getRegister("B").setValue(1);
}
} else if (a == READ_SECTOR) {
if (floppyDisk == null) {
getCpu().getRegisterSet().getRegister("B").setValue(0);
} else {
getCpu().getRegisterSet().getRegister("B").setValue(1);
int x = getCpu().getRegisterSet().getRegister("X").getValue();
int y = getCpu().getRegisterSet().getRegister("Y").getValue();
floppyDisk.readSector(x, cubot.getParent().getCpu().getMemory(), y);
}
} else if (a == WRITE_SECTOR) {
if (floppyDisk == null) {
getCpu().getRegisterSet().getRegister("B").setValue(0);
} else {
getCpu().getRegisterSet().getRegister("B").setValue(1);
int x = getCpu().getRegisterSet().getRegister("X").getValue();
int y = getCpu().getRegisterSet().getRegister("Y").getValue();
floppyDisk.writeSector(x, cubot.getParent().getCpu().getMemory(), y);
}
}
}
@Override
public char getId() {
return HWID;
}
@Override
public JSONObject serialise() {
JSONObject json = new JSONObject();
json.put("hwid", (int) HWID);
json.put("cubot", cubot.getObjectId());
if (floppyDisk != null) {
json.put("floppy", floppyDisk.serialise());
}
return json;
}
public static CubotFloppyDrive deserialize(JSONObject hwJSON) {
CubotFloppyDrive drive = new CubotFloppyDrive((Cubot) GameServer.INSTANCE.getGameUniverse().getObject((int) (long) hwJSON.get("cubot")));
if (hwJSON.containsKey("floppy")) {
drive.floppyDisk = FloppyDisk.deserialise((JSONObject) hwJSON.get("floppy"));
} else {
drive.floppyDisk = new FloppyDisk();
}
return drive;
}
public FloppyDisk getFloppy() {
return floppyDisk;
}
}

View File

@ -55,6 +55,8 @@ public class CubotPlugin extends ServerPlugin implements GameObjectDeserializer,
return CubotHologram.deserialize(hwJson); return CubotHologram.deserialize(hwJson);
case CubotBattery.HWID: case CubotBattery.HWID:
return CubotBattery.deserialize(hwJson); return CubotBattery.deserialize(hwJson);
case CubotFloppyDrive.HWID:
return CubotFloppyDrive.deserialize(hwJson);
} }
return null; return null;

View File

@ -0,0 +1,106 @@
package net.simon987.cubotplugin;
import net.simon987.server.assembly.Memory;
import net.simon987.server.io.JSONSerialisable;
import net.simon987.server.logging.LogManager;
import org.json.simple.JSONObject;
/**
* Represents a floppy disk that is inside a floppy drive.
* Floppies contains 80 tracks with 18 sectors per track.
* That's 1440 sectors of 512 words. (total 1,474,560 bytes / 737,280 words / 1.44Mb)
*/
public class FloppyDisk implements JSONSerialisable {
/**
* Contents of the disk
*/
private Memory memory;
/**
* Current location of the read/write head.
* Used to calculate seek time
*/
private int rwHeadTrack = 0;
public FloppyDisk() {
this.memory = new Memory(1024 * 1440);
}
/**
* Read 512 words from the specified sector to cpu memory at specified address
*
* @param sector sector to read (0-1440)
* @param cpuMemory Cpu memory to write to
* @param ramAddress address of the data to write in CPU memory
* @return Whether or not the read operation was in the same track as the last r/w
*/
public boolean readSector(int sector, Memory cpuMemory, int ramAddress) {
cpuMemory.write(ramAddress, memory.getBytes(), sector * 512, 1024);
LogManager.LOGGER.fine("Read 512 words from floppy sector:" + sector + " to memory addr:" + ramAddress);
//Calculate seek time
int deltaTrack = (sector / 80) - rwHeadTrack;
if (deltaTrack != 0) {
rwHeadTrack = (sector / 80);
return false;
} else {
return true;
}
}
/**
* Write 512 words to the specified sector from cpu memory at the specified address
*
* @param sector sector to write (0-1440)
* @param cpuMemory Cpu memory to read from
* @param ramAddress address of the data to read in CPU memory
* @return Whether or not the read operation was in the same track as the last r/w
*/
public boolean writeSector(int sector, Memory cpuMemory, int ramAddress) {
memory.write(sector * 512, cpuMemory.getBytes(), ramAddress * 2, 1024);
LogManager.LOGGER.fine("Wrote 512 words to floppy sector:" + sector + " from memory addr:" + ramAddress);
//Calculate seek time
int deltaTrack = (sector / 80) - rwHeadTrack;
if (deltaTrack != 0) {
rwHeadTrack = (sector / 80);
return false;
} else {
return true;
}
}
@Override
public JSONObject serialise() {
JSONObject json = new JSONObject();
json.put("rwHeadTrack", rwHeadTrack);
json.put("memory", memory.serialise());
return json;
}
public static FloppyDisk deserialise(JSONObject json) {
FloppyDisk floppyDisk = new FloppyDisk();
floppyDisk.rwHeadTrack = (int) (long) json.get("rwHeadTrack");
floppyDisk.memory = Memory.deserialize((JSONObject) json.get("memory"));
return floppyDisk;
}
public Memory getMemory() {
return memory;
}
}

View File

@ -37,6 +37,8 @@ public class CpuInitialisationListener implements GameEventListener {
emoteHw.setCpu(cpu); emoteHw.setCpu(cpu);
CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit()); CubotBattery batteryHw = new CubotBattery((Cubot) user.getControlledUnit());
batteryHw.setCpu(cpu); batteryHw.setCpu(cpu);
CubotFloppyDrive floppyHw = new CubotFloppyDrive((Cubot) user.getControlledUnit());
floppyHw.setCpu(cpu);
cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS); cpu.attachHardware(legHw, CubotLeg.DEFAULT_ADDRESS);
cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS); cpu.attachHardware(laserHw, CubotLaser.DEFAULT_ADDRESS);
@ -47,5 +49,6 @@ public class CpuInitialisationListener implements GameEventListener {
cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS); cpu.attachHardware(invHw, CubotInventory.DEFAULT_ADDRESS);
cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS); cpu.attachHardware(emoteHw, CubotHologram.DEFAULT_ADDRESS);
cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS); cpu.attachHardware(batteryHw, CubotBattery.DEFAULT_ADDRESS);
cpu.attachHardware(floppyHw, CubotFloppyDrive.DEFAULT_ADDRESS);
} }
} }

View File

@ -55,7 +55,7 @@ public class Memory implements Target, JSONSerialisable {
/** /**
* Write x words from an array at an offset * Write x words from an array at an offset
*/ */
public boolean write(int offset, byte[] bytes, int count) { public boolean write(int offset, byte[] bytes, int srcOffset, int count) {
offset = (char)offset * 2; offset = (char)offset * 2;
@ -64,7 +64,7 @@ public class Memory implements Target, JSONSerialisable {
return false; return false;
} }
System.arraycopy(bytes, 0, this.bytes, offset, count); System.arraycopy(bytes, srcOffset, this.bytes, offset, count);
return true; return true;
} }
@ -122,18 +122,6 @@ public class Memory implements Target, JSONSerialisable {
e.printStackTrace(); e.printStackTrace();
} }
//To deflate
/*
ByteArrayOutputStream stream2 = new ByteArrayOutputStream();
Inflater decompresser = new Inflater(true);
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(stream2, decompresser);
inflaterOutputStream.write(output);
inflaterOutputStream.close();
byte[] output2 = stream2.toByteArray();
*/
return json; return json;
} }
@ -157,4 +145,8 @@ public class Memory implements Target, JSONSerialisable {
return memory; return memory;
} }
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
} }

View File

@ -1,5 +1,6 @@
package net.simon987.server.game; package net.simon987.server.game;
import net.simon987.server.assembly.Memory;
import net.simon987.server.user.User; import net.simon987.server.user.User;
import java.util.ArrayList; import java.util.ArrayList;
@ -14,4 +15,6 @@ public interface ControllableUnit {
ArrayList<Integer> getKeyboardBuffer(); ArrayList<Integer> getKeyboardBuffer();
Memory getFloppyData();
} }

View File

@ -29,7 +29,7 @@ public class GameUniverse implements JSONSerialisable{
private int nextObjectId = 0; private int nextObjectId = 0;
private int maxWidth = 3; //0xFFFF private int maxWidth = 0xFFFF;
public GameUniverse(ServerConfiguration config) { public GameUniverse(ServerConfiguration config) {
@ -113,9 +113,11 @@ public class GameUniverse implements JSONSerialisable{
user.getCpu().getMemory().clear(); user.getCpu().getMemory().clear();
//Write assembled code to mem //Write assembled code to mem
user.getCpu().getMemory().write((short) ar.origin, ar.bytes, ar.bytes.length); user.getCpu().getMemory().write((short) ar.origin, ar.bytes, 0, ar.bytes.length);
user.getCpu().setCodeSegmentOffset(ar.origin); user.getCpu().setCodeSegmentOffset(ar.origin);
//Init
} else { } else {
user = new User(null); user = new User(null);
} }

View File

@ -28,7 +28,7 @@ public class CodeUploadHandler implements MessageHandler {
user.getUser().getCpu().getMemory().clear(); user.getUser().getCpu().getMemory().clear();
//Write assembled code to mem //Write assembled code to mem
user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, ar.bytes.length); user.getUser().getCpu().getMemory().write((char) ar.origin, ar.bytes, 0, ar.bytes.length);
user.getUser().getCpu().setCodeSegmentOffset(ar.origin); user.getUser().getCpu().setCodeSegmentOffset(ar.origin);
JSONObject response = new JSONObject(); JSONObject response = new JSONObject();

View File

@ -0,0 +1,36 @@
package net.simon987.server.webserver;
import net.simon987.server.GameServer;
import net.simon987.server.logging.LogManager;
import org.json.simple.JSONObject;
public class FloppyHandler implements MessageHandler {
SocketServerDatabase db = new SocketServerDatabase(GameServer.INSTANCE.getConfig());
@Override
public void handle(OnlineUser user, JSONObject json) {
if (json.get("t").equals("floppyDown")) {
LogManager.LOGGER.info("(WS) Floppy download request from " + user.getUser().getUsername());
//floppy
byte[] bytes = user.getUser().getControlledUnit().getFloppyData().getBytes();
user.getWebSocket().send(bytes);
} else if (json.get("t").equals("floppyUp")) {
LogManager.LOGGER.info("(WS) Floppy upload request from " + user.getUser().getUsername());
//Check newly uploaded file on the database
byte[] bytes = db.getFloppy(user.getUser().getUsername());
if (bytes != null) {
user.getUser().getControlledUnit().getFloppyData().setBytes(bytes);
}
}
}
}

View File

@ -68,6 +68,7 @@ public class SocketServer extends WebSocketServer {
messageEventDispatcher.addHandler(new CodeUploadHandler()); messageEventDispatcher.addHandler(new CodeUploadHandler());
messageEventDispatcher.addHandler(new CodeRequestHandler()); messageEventDispatcher.addHandler(new CodeRequestHandler());
messageEventDispatcher.addHandler(new KeypressHandler()); messageEventDispatcher.addHandler(new KeypressHandler());
messageEventDispatcher.addHandler(new FloppyHandler());
} }

View File

@ -4,10 +4,7 @@ import net.simon987.server.ServerConfiguration;
import net.simon987.server.io.DatabaseManager; import net.simon987.server.io.DatabaseManager;
import net.simon987.server.logging.LogManager; import net.simon987.server.logging.LogManager;
import java.sql.Connection; import java.sql.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
class SocketServerDatabase extends DatabaseManager { class SocketServerDatabase extends DatabaseManager {
@ -48,4 +45,39 @@ class SocketServerDatabase extends DatabaseManager {
return null; return null;
} }
byte[] getFloppy(String username) {
Connection connection = null;
try {
connection = getConnection();
PreparedStatement p = connection.prepareStatement("SELECT floppyData FROM mar_user WHERE username=?");
p.setString(1, username);
ResultSet rs = p.executeQuery();
if (rs.next()) {
Blob blob = rs.getBlob("floppyData");
if (blob != null) {
return blob.getBytes(1, (int) blob.length() - 1);
}
}
} catch (SQLException e) {
LogManager.LOGGER.severe("MySQL Error " + e.getErrorCode() + ": " + e.getMessage());
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
} }

View File

@ -36,14 +36,14 @@ public class MemoryTest {
Memory memory = new Memory(memorySize); Memory memory = new Memory(memorySize);
assertTrue(memory.write(0, new byte[memorySize], memorySize)); assertTrue(memory.write(0, new byte[memorySize], 0, memorySize));
assertFalse(memory.write(0, new byte[memorySize], memorySize + 1)); assertFalse(memory.write(0, new byte[memorySize], 0, memorySize + 1));
assertFalse(memory.write(0, new byte[memorySize], -1)); assertFalse(memory.write(0, new byte[memorySize], 0, -1));
assertFalse(memory.write(-1, new byte[memorySize], 10)); assertFalse(memory.write(-1, new byte[memorySize], 0, 10));
assertFalse(memory.write(memorySize / 2, new byte[15], 1)); assertFalse(memory.write(memorySize / 2, new byte[15], 0, 1));
assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 11)); assertFalse(memory.write((memorySize / 2) - 5, new byte[11], 0, 11));
assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 10)); assertTrue(memory.write((memorySize / 2) - 5, new byte[11], 0, 10));
} }