public void run() { // start a new thread // this thread has one task. It repeatedly reads from the input pipe // and writes modified data to the output pipe. This is the heart // of the command station simulation. if (log.isDebugEnabled()) { log.debug("Simulator Thread Started"); } Random rgen = new Random(); ConnectionStatus.instance() .setConnectionState(this.getCurrentPortName(), ConnectionStatus.CONNECTION_UP); for (; ; ) { DCCppMessage m = readMessage(); if (log.isDebugEnabled()) { log.debug("Simulator Thread received message " + m.toString()); } DCCppReply r = generateReply(m); // If generateReply() returns null, do nothing. No reply to send. if (r != null) { writeReply(r); if (log.isDebugEnabled()) { log.debug("Simulator Thread sent Reply" + r.toString()); } } // Once every SENSOR_MSG_RATE loops, generate a random Sensor message. int rand = rgen.nextInt(SENSOR_MSG_RATE); if (rand == 1) { generateRandomSensorReply(); } } }
private void writeReply(DCCppReply r) { int i; int len = r.getLength(); // opCode+Nbytes+ECC // If r == null, there is no reply to be sent. try { outpipe.writeByte((byte) '<'); for (i = 0; i < len; i++) { outpipe.writeByte((byte) r.getElement(i)); } outpipe.writeByte((byte) '>'); } catch (java.io.IOException ex) { ConnectionStatus.instance() .setConnectionState(this.getCurrentPortName(), ConnectionStatus.CONNECTION_DOWN); } }
private void generateRandomSensorReply() { // Pick a random sensor number between 0 and 10; Random sNumGenerator = new Random(); int sensorNum = sNumGenerator.nextInt(10); // Generate a random sensor number between 0 and 9 Random valueGenerator = new Random(); int value = valueGenerator.nextInt(2); // Generate state value betweeon 0 and 1 String reply = new String((value == 1 ? "Q " : "q ") + Integer.toString(sensorNum)); DCCppReply r = DCCppReply.parseDCCppReply(reply); writeReply(r); if (log.isDebugEnabled()) { log.debug("Simulator Thread sent Reply" + r.toString()); } }
private void generateReadCSStatusReply() { /* String s = new String("<p" + (TrackPowerState ? "1" : "0") + ">"); DCCppReply r = new DCCppReply(s); writeReply(r); if (log.isDebugEnabled()) { log.debug("Simulator Thread sent Reply" + r.toString()); } */ DCCppReply r = DCCppReply.parseDCCppReply( "iDCC++ BASE STATION FOR ARDUINO MEGA / ARDUINO MOTOR SHIELD: BUILD 05 Nov 2015 00:09:57"); writeReply(r); if (log.isDebugEnabled()) { log.debug("Simulator Thread sent Reply" + r.toString()); } // Generate the other messages too... }
// generateReply is the heart of the simulation. It translates an // incoming DCCppMessage into an outgoing DCCppReply. @SuppressWarnings("fallthrough") private DCCppReply generateReply(DCCppMessage msg) { String s, r; Pattern p; Matcher m; DCCppReply reply = null; log.debug("Generate Reply to message type {} string = {}", msg.getElement(0), msg.toString()); switch (msg.getElement(0)) { case DCCppConstants.THROTTLE_CMD: log.debug("THROTTLE_CMD detected"); s = msg.toString(); try { p = Pattern.compile(DCCppConstants.THROTTLE_CMD_REGEX); m = p.matcher(s); if (!m.matches()) { log.error("Malformed Throttle Command: {}", s); return (null); } r = "T " + m.group(1) + " " + m.group(3) + " " + m.group(4); reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); } catch (PatternSyntaxException e) { log.error("Malformed pattern syntax! "); return (null); } catch (IllegalStateException e) { log.error("Group called before match operation executed string= " + s); return (null); } catch (IndexOutOfBoundsException e) { log.error("Index out of bounds string= " + s); return (null); } break; case DCCppConstants.TURNOUT_CMD: if (msg.isTurnoutAddMessage()) { log.debug("Add Turnout Message"); r = "O"; } else if (msg.isTurnoutDeleteMessage()) { log.debug("Delete Turnout Message"); r = "O"; } else if (msg.isListTurnoutsMessage()) { log.debug("List Turnouts Message"); r = "H 1 27 3 1"; } else { log.debug("TURNOUT_CMD detected"); r = "H" + msg.getTOIDString() + " " + msg.getTOStateString(); } reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); break; case DCCppConstants.SENSOR_CMD: if (msg.isSensorAddMessage()) { log.debug("SENSOR_CMD Add detected"); s = msg.toString(); r = "O"; // TODO: Randomize? } else if (msg.isSensorDeleteMessage()) { log.debug("SENSOR_CMD Delete detected"); s = msg.toString(); r = "O"; // TODO: Randomize? } else if (msg.isListSensorsMessage()) { r = "Q 1 4 1"; // TODO: DO this for real. } else { log.debug("Invalid SENSOR_CMD detected"); r = "X"; } reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); break; case DCCppConstants.PROG_WRITE_CV_BYTE: log.debug("PROG_WRITE_CV_BYTE detected"); s = msg.toString(); try { p = Pattern.compile(DCCppConstants.PROG_WRITE_BYTE_REGEX); m = p.matcher(s); if (!m.matches()) { log.error("Malformed ProgWriteCVByte Command: {}", s); return (null); } r = "r " + m.group(3) + " " + m.group(4) + " " + m.group(2); CVs[Integer.parseInt(m.group(1))] = Integer.parseInt(m.group(2)); reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); } catch (PatternSyntaxException e) { log.error("Malformed pattern syntax! "); return (null); } catch (IllegalStateException e) { log.error("Group called before match operation executed string= " + s); return (null); } catch (IndexOutOfBoundsException e) { log.error("Index out of bounds string= " + s); return (null); } break; case DCCppConstants.PROG_WRITE_CV_BIT: log.debug("PROG_WRITE_CV_BIT detected"); s = msg.toString(); try { p = Pattern.compile(DCCppConstants.PROG_WRITE_BIT_REGEX); m = p.matcher(s); if (!m.matches()) { log.error("Malformed ProgWriteCVBit Command: {}", s); return (null); } r = "r " + m.group(4) + " " + m.group(5) + " " + m.group(3); int idx = Integer.parseInt(m.group(1)); int bit = Integer.parseInt(m.group(2)); int v = Integer.parseInt(m.group(3)); if (v == 1) CVs[idx] = CVs[idx] | (0x0001 << bit); else CVs[idx] = CVs[idx] & ~(0x0001 << bit); reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); } catch (PatternSyntaxException e) { log.error("Malformed pattern syntax! "); return (null); } catch (IllegalStateException e) { log.error("Group called before match operation executed string= " + s); return (null); } catch (IndexOutOfBoundsException e) { log.error("Index out of bounds string= " + s); return (null); } break; case DCCppConstants.PROG_READ_CV: log.debug("PROG_READ_CV detected"); s = msg.toString(); try { p = Pattern.compile(DCCppConstants.PROG_READ_REGEX); m = p.matcher(s); if (!m.matches()) { log.error("Malformed PROG_READ_CV Command: {}", s); return (null); } // TODO: Work Magic Here to retrieve stored value. int cv = CVs[Integer.parseInt(m.group(1))]; r = "r " + m.group(2) + " " + m.group(3) + " " + Integer.toString(cv); reply = DCCppReply.parseDCCppReply(r); log.debug("Reply generated = {}", reply.toString()); } catch (PatternSyntaxException e) { log.error("Malformed pattern syntax! "); return (null); } catch (IllegalStateException e) { log.error("Group called before match operation executed string= " + s); return (null); } catch (IndexOutOfBoundsException e) { log.error("Index out of bounds string= " + s); return (null); } break; case DCCppConstants.TRACK_POWER_ON: log.debug("TRACK_POWER_ON detected"); TrackPowerState = true; reply = DCCppReply.parseDCCppReply("p1"); log.debug("Reply generated = {}", reply.toString()); break; case DCCppConstants.TRACK_POWER_OFF: log.debug("TRACK_POWER_OFF detected"); TrackPowerState = false; reply = DCCppReply.parseDCCppReply("p0"); log.debug("Reply generated = {}", reply.toString()); break; case DCCppConstants.READ_TRACK_CURRENT: log.debug("READ_TRACK_CURRENT detected"); int randint = 480 + rgen.nextInt(64); reply = DCCppReply.parseDCCppReply("a " + (TrackPowerState ? Integer.toString(randint) : "0")); log.debug("Reply generated = {}", reply.toString()); break; case DCCppConstants.READ_CS_STATUS: log.debug("READ_CS_STATUS detected"); generateReadCSStatusReply(); // Handle this special. break; /* case DCCppConstants.QUERY_SENSOR_STATE: // Obsolete ?? log.debug("QUERY_SENSOR_STATUS detected"); s = msg.toString(); try { p = Pattern.compile(DCCppConstants.QUERY_SENSOR_REGEX); m = p.matcher(s); if (!m.matches()) { log.error("Malformed Sensor Query Command: {}", s); return(null); } r = "Q " + m.group(1) + " "; // Fake reply: Odd sensors always active, even always inactive. r += ((Integer.parseInt(m.group(1)) % 2) == 1 ? "1" : "0"); reply = new DCCppReply(r); log.debug("Reply generated = {}", reply.toString()); } catch (PatternSyntaxException e) { log.error("Malformed pattern syntax! "); return(null); } catch (IllegalStateException e) { log.error("Group called before match operation executed string= " + s); return(null); } catch (IndexOutOfBoundsException e) { log.error("Index out of bounds string= " + s); return(null); } break; */ case DCCppConstants.FUNCTION_CMD: case DCCppConstants.ACCESSORY_CMD: case DCCppConstants.OPS_WRITE_CV_BYTE: case DCCppConstants.OPS_WRITE_CV_BIT: case DCCppConstants.WRITE_DCC_PACKET_MAIN: case DCCppConstants.WRITE_DCC_PACKET_PROG: log.debug("non-reply message detected"); // Send no reply. return (null); default: return (null); } return (reply); }