001package jmri.jmrit.z21server; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006import java.net.InetAddress; 007import java.util.Arrays; 008 009public class Service40 { 010 private static final String moduleIdent = "[Service 40] "; 011 012 private final static Logger log = LoggerFactory.getLogger(Service40.class); 013 014 015 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 016 justification = "Messages can be of any length, null is used to indicate absence of message for caller") 017 public static byte[] handleService(byte[] data, InetAddress clientAddress) { 018 int command = data[0]; 019 switch (command){ 020 case 0x21: 021 return handleHeader21(data[1]); 022 case (byte)0xE3: 023 return handleHeaderE3(Arrays.copyOfRange(data, 1, 4), clientAddress); 024 case (byte)0xE4: 025 return handleHeaderE4(Arrays.copyOfRange(data, 1, 5), clientAddress); 026 default: 027 log.debug("{} Header {} not yet supported", moduleIdent, Integer.toHexString(command)); 028 break; 029 } 030 return null; 031 } 032 033 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 034 justification = "Messages can be of any length, null is used to indicate absence of message for caller") 035 private static byte[] handleHeader21(int db0){ 036 switch (db0){ 037 case 0x21: 038 // Get z21 version 039 break; 040 case 0x24: 041 // Get z21 status 042 byte[] answer = new byte[8]; 043 answer[0] = (byte) 0x08; 044 answer[1] = (byte) 0x00; 045 answer[2] = (byte) 0x40; 046 answer[3] = (byte) 0x00; 047 answer[4] = (byte) 0x62; 048 answer[5] = (byte) 0x22; 049 answer[6] = (byte) 0x00; 050 answer[7] = ClientManager.xor(answer); 051 return answer; 052 case 0x80: 053 log.debug("{} Set track power to off", moduleIdent); 054 break; 055 case 0x81: 056 log.debug("{} Set track power to on", moduleIdent); 057 break; 058 default: 059 break; 060 } 061 return null; 062 } 063 064 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 065 justification = "Messages can be of any length, null is used to indicate absence of message for caller") 066 private static byte[] handleHeaderE3(byte[] data, InetAddress clientAddress) { 067 int db0 = data[0]; 068 if (db0 == (byte)0xF0) { 069 // Get loco status command 070 int locomotiveAddress = (((data[1] & 0xFF) & 0x3F) << 8) + (data[2] & 0xFF); 071 log.debug("{} Get loco no {} status", moduleIdent, locomotiveAddress); 072 073 ClientManager.getInstance().registerLocoIfNeeded(clientAddress, locomotiveAddress); 074 075 return ClientManager.getInstance().getLocoStatusMessage(clientAddress, locomotiveAddress); 076 077 } else { 078 log.debug("{} Header E3 with function {} is not supported", moduleIdent, Integer.toHexString(db0)); 079 } 080 return null; 081 } 082 083 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 084 justification = "Messages can be of any length, null is used to indicate absence of message for caller") 085 private static byte[] handleHeaderE4(byte[] data, InetAddress clientAddress) { 086 if (data[0] == 0x13) { 087 int locomotiveAddress = (((data[1] & 0xFF) & 0x3F) << 8) + (data[2] & 0xFF); 088 int rawSpeedData = data[3] & 0xFF; 089 boolean bForward = ((rawSpeedData & 0x80) >> 7) == 1; 090 int actualSpeed = rawSpeedData & 0x7F; 091 log.debug("Set loco no {} direction {} with speed {}",locomotiveAddress, (bForward ? "FWD" : "RWD"), actualSpeed); 092 093 ClientManager.getInstance().setLocoSpeedAndDirection(clientAddress, locomotiveAddress, actualSpeed, bForward); 094 095 return ClientManager.getInstance().getLocoStatusMessage(clientAddress, locomotiveAddress); 096 } 097 if (data[0] == (byte)0xF8) { 098 int locomotiveAddress = (((data[1] & 0xFF) & 0x3F) << 8) + (data[2] & 0xFF); 099 boolean bOn = (((data[3] & 0xFF) & 0x40) >> 6) == 1; 100 int functionNumber = (data[3] & 0xFF) & 0x3F; 101 log.debug("Set loco no {} function no {} to {}", locomotiveAddress, functionNumber, (bOn ? "ON" : "OFF")); 102 103 ClientManager.getInstance().setLocoFunction(clientAddress, locomotiveAddress, functionNumber, bOn); 104 105 return ClientManager.getInstance().getLocoStatusMessage(clientAddress, locomotiveAddress); 106 } 107 return null; 108 } 109}