挖井人地址:点我
要是问起PJLink是啥,回答如下:
PJLINK CLASS 1是由日本向务机器和信息系统行业公会制定的一种标准协议,用来控制网络兼容的投影仪,这是他们投影仪控制协议标准工作的一部分。
更多请点击:点这儿(偷懒大法)
测试环境搭建:
没有现成的投影机提供测试,于是写了一个PJLink的测试类,首先看下协议内容(实际交互数据):
[2020.05.28 14:44:59.167] Connect TCP
[2020.05.28 14:44:59.176] RECV:PJLINK 0
[2020.05.28 14:44:59.197] SEND:%1POWR ?
[2020.05.28 14:44:59.205] RECV:%1POWR=0
[2020.05.28 14:44:59.315] SEND:%1INPT ?
[2020.05.28 14:44:59.320] RECV:%1INPT=ERR3
[2020.05.28 14:44:59.427] SEND:%1AVMT ?
[2020.05.28 14:44:59.432] RECV:%1AVMT=ERR3
[2020.05.28 14:44:59.549] SEND:%1ERST ?
[2020.05.28 14:44:59.554] RECV:%1ERST=000000
[2020.05.28 14:44:59.661] SEND:%1LAMP ?
[2020.05.28 14:44:59.668] RECV:%1LAMP=422 0
[2020.05.28 14:44:59.784] SEND:%1INST ?
[2020.05.28 14:44:59.789] RECV:%1INST=11 12 32 33 41 52
[2020.05.28 14:44:59.906] SEND:%1NAME ?
[2020.05.28 14:44:59.915] RECV:%1NAME=EBDFE9AE
[2020.05.28 14:44:59.919] 45 42 44 46 45 39 41 45
[2020.05.28 14:45:00.033] SEND:%1INFO ?
[2020.05.28 14:45:00.038] RECV:%1INFO=102.102.---
[2020.05.28 14:45:00.146] SEND:%1INF1 ?
[2020.05.28 14:45:00.152] RECV:%1INF1=EPSON
[2020.05.28 14:45:00.265] SEND:%1INF2 ?
[2020.05.28 14:45:00.269] RECV:%1INF2=EPSON L500
[2020.05.28 14:45:00.378] SEND:%1CLSS ?
[2020.05.28 14:45:00.380] RECV:%1CLSS=2
[2020.05.28 14:45:00.482] SEND:%2INPT ?
[2020.05.28 14:45:00.488] RECV:%2INPT=ERR3
[2020.05.28 14:45:00.594] SEND:%2INST ?
[2020.05.28 14:45:00.598] RECV:%2INST=11 12 32 33 41 52
[2020.05.28 14:45:00.702] SEND:%2SNUM ?
[2020.05.28 14:45:00.708] RECV:%2SNUM=X5TE89056L
[2020.05.28 14:45:00.812] SEND:%2SVER ?
[2020.05.28 14:45:00.818] RECV:%2SVER=87009470FJWV102
[2020.05.28 14:45:00.921] SEND:%2INNM ?11
[2020.05.28 14:45:00.927] RECV:%2INNM=Computer1
[2020.05.28 14:45:00.930] 43 6F 6D 70 75 74 65 72 31
[2020.05.28 14:45:01.033] SEND:%2IRES ?
[2020.05.28 14:45:01.037] RECV:%2IRES=ERR3
[2020.05.28 14:45:01.140] SEND:%2RRES ?
[2020.05.28 14:45:01.146] RECV:%2RRES=1280x800
[2020.05.28 14:45:01.249] SEND:%2FILT ?
[2020.05.28 14:45:01.251] RECV:%2FILT=0
[2020.05.28 14:45:01.360] SEND:%2RLMP ?
[2020.05.28 14:45:01.365] RECV:%2RLMP=ERR1
[2020.05.28 14:45:01.470] SEND:%2RFIL ?
[2020.05.28 14:45:01.475] RECV:%2RFIL=ELPA56
[2020.05.28 14:45:01.594] SEND:%2FREZ ?
[2020.05.28 14:45:01.599] RECV:%2FREZ=ERR3
[2020.05.28 14:45:31.592] Close TCP socket(Server).
根据这些,测试类如下:
package http;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class PJLINKServer {
public static final int PORT = 5555;
public static void main(String[] args) {
try {
new PJLINKServer();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public PJLINKServer() throws IOException {
ServerSocket ss = new ServerSocket(PORT);
InetAddress ia = InetAddress.getByName(null);
System.out.println("Server@" + ia + " start!");
try {
while (true) {
Socket s = ss.accept();// listen PORT;
try {
new ServerOne(s);
} catch (IOException e) {
s.close();
}
}
} finally {
ss.close();
System.out.println("Server stop!");
}
}
}
class ServerOne extends Thread {
private Socket s;
private BufferedReader in;
private PrintWriter out;
public ServerOne(Socket s) throws IOException {
this.s = s;
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(s.getOutputStream())), true);
start();
}
public void run() {
try {
out.println("PJLINK 0");
while (true) {
String str = in.readLine();
System.out.println("Server:" + str);
if (str == null) {
break;
}
// out.println("Echo: "+str);
if ("%1POWR ?".equals(str)) {
out.println("%1POWR=0");
} else if ("%1INPT ?".equals(str)) {
out.println("%1INPT=ERR3");
} else if ("%1AVMT ?".equals(str)) {
out.println("%1AVMT=ERR3");
} else if ("%1ERST ?".equals(str)) {
out.println("%1ERST=000000");
} else if ("%1LAMP ?".equals(str)) {
out.println("%1LAMP=422 0");
} else if ("%1INST ?".equals(str)) {
out.println("%1INST=11 12 32 33 41 52");
} else if ("%1NAME ?".equals(str)) {
out.println("%1NAME=EBDFE9AE");
} else if ("%1INFO ?".equals(str)) {
out.println("%1INFO=102.102.---");
} else if ("%1INF1 ?".equals(str)) {
out.println("%1INF1=EPSON");
} else if ("%1INF2 ?".equals(str)) {
out.println("%1INF2=EPSON L500");
} else if ("%1CLSS ?".equals(str)) {
out.println("%1CLSS=2");
} else if ("%2INPT ?".equals(str)) {
out.println("%2INPT=ERR3");
} else if ("%2INST ?".equals(str)) {
out.println("%2INST=11 12 32 33 41 52");
} else if ("%2SNUM ?".equals(str)) {
out.println("%2SNUM=X5TE80056L");
} else if ("%2SVER ?".equals(str)) {
out.println("%2SVER=87009470FJWV102");
} else if ("%2INNM ?11".equals(str)) {
out.println("%2INNM=Computer1");
} else if ("%2IRES ?".equals(str)) {
out.println("%2IRES=ERR3");
} else if ("%2RRES ?".equals(str)) {
out.println("%2RRES=1280x800");
} else if ("%2FILT ?".equals(str)) {
out.println("%2FILT=0");
} else if ("%2RLMP ?".equals(str)) {
out.println("%2RLMP=ERR1");
} else if ("%2RFIL ?".equals(str)) {
out.println("%2RFIL=ELAF56");
} else if ("%2FREZ ?".equals(str)) {
out.println("%2FREZ=ERR3");
}
}
System.out.println("closing...");
} catch (IOException e) {
} finally {
try {
s.close();
} catch (IOException e) {
}
}
}
}
到这就可以写代码了。
根据挖井人代码我略微的修改了(有小BUG)。
代码如下,首先是PJLink类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Serializable;
import java.math.BigInteger;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
public class PJLink implements Serializable{
// PJLink connection.
private int _TCPPort = 4352;
private String _ipAddress = "";
private String _pjlinkPassword = "";
private PJLinkSocket _pjlinkSocket = new PJLinkSocket();
private PJLinkQueue _pjlinkQueue = new PJLinkQueue();
private PJLinkRefreshTimer _rft = new PJLinkRefreshTimer();
private ArrayList _pjlinkListeners = new ArrayList();
// Device state.
private int _powerState = PJlinkCode.POWER_OFF;
private int _newPowerState = PJlinkCode.POWER_OFF;
private int _activeInput = PJlinkCode.INPUT_RGB_1;
private int _newActiveInput = PJlinkCode.INPUT_RGB_1;
private boolean _audioMuteActive = false;
private boolean _audioMuteStateBeforeVideoMuted = false;
private boolean _newAudioMuteActive = false;
private boolean _videoMuteActive = false;
private boolean _newVideoMuteActive = false;
private int _lampHours = 0;
boolean _connectionError = false;
int _fanError = 0;
int _lampError = 0;
int _tempError = 0;
int _coverError = 0;
int _filterError = 0;
int _otherError = 0;
private String INST = null;
private String NAME = null;
private String INFO = null;
private String INF1 = null;
private String INF2 = null;
private String CLSS = null;
private String SNUM = null;
private String SVER = null;
private String INNM = null;
private String IRES = null;
private String RRES = null;
private String FILT = null;
private String RLMP = null;
private String RFIL = null;
private String FREZ = null;
// Module settings.
boolean _printDebug = false; // Print debug statements to the console.
boolean _disablePolling = false; // Disable polling of the projector state.
/**
* Creates an uninitialized PJLink connection.
* At a minimum, the projector's IP address must be specified
* before a connection can be established.
*/
public PJLink() {
}
/**
* Creates a PJLink connection to a projector at the specified IP address.
* The default PJLink port is used.
* @param ipAddress
*/
public PJLink(String ipAddress) {
setIPAddress(ipAddress);
}
/**
* Creates a PJLink connection to a projector at the specified IP address and port.
* @param ipAddress
* @param port
*/
public PJLink(String ipAddress, int port) {
setIPAddress(ipAddress);
setPort(port);
}
/**
* Adds a <code>PJLinkListener</code> to receive changes regarding the projector's state.
* @param listener
*/
public void addListener(PJLinkListener listener) {
if (_pjlinkListeners.contains(listener) == true) return;
_pjlinkListeners.add(listener);
}
public void removeListener(PJLinkListener listener) {
_pjlinkListeners.remove(listener);
}
private void notifyListeners(PJLinkEvent event) {
Iterator i = _pjlinkListeners.iterator();
while (i.hasNext()) {
((PJLinkListener) i.next()).deviceStateChanged(this, event);
}
}
public String getIPAddress() {
return _ipAddress;
}
public int getPort() {
return _TCPPort;
}
/**
* @return Projector is on, off, warming, or cooling.
*/
public int getPowerState() {
queryPowerState();
return _powerState;
}
public boolean getConnectionError() {
return _connectionError;
}
public boolean getPrintDebug() {
return _printDebug;
}
public boolean getDisablePolling() {
return _disablePolling;
}
public void powerOn() {
_pjlinkQueue.push(new PJLinkCommand("%1POWR 1"));
if (_powerState == PJlinkCode.POWER_OFF) {
_newPowerState = (_disablePolling == false) ? PJlinkCode.POWER_WARMING : PJlinkCode.POWER_ON;
}
if (_disablePolling == false) queryPowerState();
}
public void powerOff() {
_pjlinkQueue.push(new PJLinkCommand("%1POWR 0"));
if (_powerState == PJlinkCode.POWER_ON) {
_newPowerState = (_disablePolling == false) ? PJlinkCode.POWER_COOLING : PJlinkCode.POWER_OFF;
}
if (_disablePolling == false) queryPowerState();
}
public void switchInput(int input) {
if (input < 11 || input > 59) return;
_pjlinkQueue.push(new PJLinkCommand("%1INPT " + input));
_newActiveInput = input;
}
public void muteAudio() {
if (_audioMuteActive == true) return;
_newAudioMuteActive = true;
sendAVMuteState();
}
public void unmuteAudio() {
if (_audioMuteActive == false) return;
if (_videoMuteActive == false) _newAudioMuteActive = false;
sendAVMuteState();
}
public void muteVideo() {
if (_videoMuteActive == true) return;
// Muting video also mutes audio, but the audio mute
// state must be retained when video is unmuted again.
if (_videoMuteActive == false) _audioMuteStateBeforeVideoMuted = _audioMuteActive;
_newAudioMuteActive = true;
_newVideoMuteActive = true;
sendAVMuteState();
}
public void unmuteVideo() {
if (_videoMuteActive == false) return;
_newAudioMuteActive = _audioMuteStateBeforeVideoMuted;
_newVideoMuteActive = false;
sendAVMuteState();
}
private void sendAVMuteState() {
if (_newVideoMuteActive == true) {
// Mute audio and video.
_pjlinkQueue.push(new PJLinkCommand("%1AVMT 31"));
}
else {
if (_newAudioMuteActive == true) {
// Unmute video, leave audio muted.
_pjlinkQueue.push(new PJLinkCommand("%1AVMT 10"));
_pjlinkQueue.push(new PJLinkCommand("%1AVMT 21"));
}
else {
// Unmute audio and video.
_pjlinkQueue.push(new PJLinkCommand("%1AVMT 30"));
}
}
if (_disablePolling == false) queryAVMute();
}
/**
* Queries projector error status, power state, selected input,
* A/V mute, and lamp hours. It does <i>not</i> query the input
* list.
*/
public void queryAll() {
//错误状态
queryErrorStatus();
//开关
queryPowerState();
//输入信号
queryInput();
//音道
queryAVMute();
//灯泡时数
queryLampHours();
//分辨率
queryRres();
}
public void queryOnce() {
//品牌
queryName();
//信息
queryInfo();
//信息1(品牌)
queryInf1();
//信息2(型号)
queryInf2();
//输入
//queryInput2();
//输入列表
// queryInputList2();
//编号
querySnum();
//版本
querySver();
//信道名称 参数:输入列表
// queryInnm();
//未知
queryIres();
//分辨率
// queryRres();
//未知
queryFILT();
//未知
queryRLMP();
//编号?出厂号?
queryRFIL();
//未知
queryFREZ();
}
public void queryAVMute() {
_pjlinkQueue.push(new PJLinkCommand("%1AVMT ?"));
}
public void queryErrorStatus() {
_pjlinkQueue.push(new PJLinkCommand("%1ERST ?"));
}
public void queryInput() {
_pjlinkQueue.push(new PJLinkCommand("%1INPT ?"));
}
public void queryInputList() {
_pjlinkQueue.push(new PJLinkCommand("%1INST ?"));
}
public void queryPowerState() {
_pjlinkQueue.push(new PJLinkCommand("%1POWR ?"));
}
public void queryLampHours() {
_pjlinkQueue.push(new PJLinkCommand("%1LAMP ?"));
}
//------------------queryOnce----------------
public void queryName() {
_pjlinkQueue.push(new PJLinkCommand("%1NAME ?"));
}
public void queryInfo() {
_pjlinkQueue.push(new PJLinkCommand("%1INFO ?"));
}
public void queryInf1() {
_pjlinkQueue.push(new PJLinkCommand("%1INF1 ?"));
}
public void queryInf2() {
_pjlinkQueue.push(new PJLinkCommand("%1INF2 ?"));
}
public void queryInput2() {
_pjlinkQueue.push(new PJLinkCommand("%2INPT ?"));
}
public void queryInputList2() {
_pjlinkQueue.push(new PJLinkCommand("%2INST ?"));
}
public void querySnum() {
_pjlinkQueue.push(new PJLinkCommand("%2SNUM ?"));
}
public void querySver() {
_pjlinkQueue.push(new PJLinkCommand("%2SVER ?"));
}
public void queryInnm(int input) {
_pjlinkQueue.push(new PJLinkCommand("%2INNM ?"+input));
}
public void queryIres() {
_pjlinkQueue.push(new PJLinkCommand("%2IRES ?"));
}
public void queryRres() {
_pjlinkQueue.push(new PJLinkCommand("%2RRES ?"));
}
public void queryFILT() {
_pjlinkQueue.push(new PJLinkCommand("%2FILT ?"));
}
public void queryRLMP() {
_pjlinkQueue.push(new PJLinkCommand("%2RLMP ?"));
}
public void queryRFIL() {
_pjlinkQueue.push(new PJLinkCommand("%2RFIL ?"));
}
public void queryFREZ() {
_pjlinkQueue.push(new PJLinkCommand("%2FREZ ?"));
}
//------------------queryOnce----------------
public void setPassword(String password) {
_pjlinkPassword = password;
}
public void setIPAddress(String ipAddress) {
_ipAddress = ipAddress;
if (_ipAddress.length() != 0) {
queryAll();
queryOnce();
}
}
public void setPort(int port) {
_TCPPort = port;
}
public void setPrintDebug(boolean value) {
_printDebug = value;
}
public void setDisablePolling(boolean value) {
_disablePolling = value;
}
private void updatePowerState() {
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_POWER, _powerState));
}
private void updateInputState() {
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INPUT, _activeInput));
}
private void updateAVMuteState() {
int muteState = PJlinkCode.MUTE_OFF;
if (_videoMuteActive == true && _audioMuteActive == true) {
muteState = PJlinkCode.MUTE_AUDIO_VIDEO;
}
else if (_videoMuteActive == true && _audioMuteActive == false) {
muteState = PJlinkCode.MUTE_VIDEO_ONLY;
}
else if (_videoMuteActive == false && _audioMuteActive == true) {
muteState = PJlinkCode.MUTE_AUDIO_ONLY;
}
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_AV_MUTE, muteState));
}
/**
* The refresh timer queries all of the projector's parameters
* at a regular interval. This keeps the instance variables and
* class's listeners up to date without the need to poll the class.
*/
private class PJLinkRefreshTimer {
Timer _pjlinkRefreshTimer = new Timer(true);
int x = 0;
public PJLinkRefreshTimer () {
_pjlinkRefreshTimer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (_ipAddress.length() != 0 && _disablePolling == false) queryAll();
}
}, 5000, 5000);
}
}
/**
*
*
*/
private class PJLinkQueue {
ArrayList _commandQueue = new ArrayList();
private Thread _queueThread = new Thread(new PJLinkQueueRunner());
public PJLinkQueue() {
_queueThread.start();
}
public synchronized void push(PJLinkCommand command) {
_commandQueue.add(command);
}
private synchronized PJLinkCommand pop() {
if (_commandQueue.isEmpty() == true) return null;
return (PJLinkCommand) _commandQueue.remove(0);
}
public synchronized boolean isEmpty() {
return _commandQueue.isEmpty();
}
private class PJLinkQueueRunner implements Runnable {
public void run() {
while (true) {
if (_commandQueue.isEmpty() == true) {
Thread.yield();
}
else {
PJLinkCommand command = (PJLinkCommand) pop();
if (command != null) command.execute();
}
}
}
}
}
private class PJLinkSocket {
private String _pjlinkKey = ""; // Random number generated by PJLink upon connect.
private Socket _socket = new Socket();
private BufferedReader _socketReader;
private PrintWriter _socketWriter;
private Thread _socketThread;
private SocketDataListener _socketDataListener;
private MessageDigest _md5;
private boolean _sessionUsesAuthentication = false;
// TODO: Turn this into a state machine.
private boolean _socketReadyForCommand = false; // Projector has responded after opening socket.
private boolean _socketCommandReceived = true;
private Object _socketLock = new Object();
public PJLinkSocket() {
try {
_md5 = MessageDigest.getInstance("MD5");
}
catch (NoSuchAlgorithmException e) {
System.out.println("PJLink error: MD5 encryption not supported. Disable authentication.");
}
}
/**
*
* @param command
*
* This method is already called from another thread.
*/
public void sendCommand(String command) {
synchronized (_socketLock) {
// Expires the connection if it stalls.
Timer connectionExpire = new Timer(false);
connectionExpire.schedule(new TimerTask() {
public void run() {
_connectionError = true;
if (_printDebug == true) System.out.println("PJLink connection timed out. " + _ipAddress);
disconnect();
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_CONNECTION));
this.cancel();
}
}, 4000);
boolean oldConnectionErrorState = _connectionError;
try {
connect();
_connectionError = false;
while (_socketReadyForCommand == false) Thread.yield();
if (_socketWriter != null) { // This prevents the Duet module from crashing.
if (_sessionUsesAuthentication == true) {
String pjlinkHash = _pjlinkKey + _pjlinkPassword;
String commandHash = new BigInteger(1, _md5.digest(pjlinkHash.getBytes("ASCII"))).toString(16) + command + "\r";
_socketWriter.print(commandHash);
}
else {
_socketWriter.print(command + "\r");
}
_socketWriter.flush();
while (_socketCommandReceived == false) Thread.yield();
}
}
catch (IOException ex) {
_connectionError = true;
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_CONNECTION));
if (_printDebug == true) System.out.println("PJLink connection error. " + _ipAddress);
}
catch (Exception ex) {
_connectionError = true;
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_CONNECTION));
if (_printDebug == true) System.out.println("Unknown PJLink connection error. " + _ipAddress);
}
if(oldConnectionErrorState&&!_connectionError) {//first online
queryOnce();
}else if(!oldConnectionErrorState&&_connectionError) {//first offline
}
connectionExpire.cancel();
// boolean oldConnectionErrorState = _connectionError;
//
//
// if (oldConnectionErrorState == true) notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJLink.ERROR_CONNECTION));
}
}
private void connect() throws IOException {
if (_ipAddress.length() == 0) {
// Prevent thread from yielding on error.
_socketReadyForCommand = true;
_socketCommandReceived = true;
return;
}
if (_socket != null) {
if (_socket.isClosed() == false) {
disconnect();
}
}
_socket = new Socket(_ipAddress, _TCPPort);
_socket.setTcpNoDelay(true);
_socketReader = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
_socketWriter = new PrintWriter(_socket.getOutputStream(), true);
_sessionUsesAuthentication = false;
_socketReadyForCommand = false;
_socketCommandReceived = false;
_pjlinkKey = "";
_socketDataListener = new SocketDataListener();
_socketThread = new Thread(_socketDataListener);
_socketThread.start();
}
private void disconnect() {
try {
_socket.close();
_socketReader = null;
_socketWriter = null;
_socketCommandReceived = true;
_socketReadyForCommand = true;
_socketCommandReceived = true;
}
catch (IOException ex) {
// Don't care. Socket is getting destroyed.
}
}
/***********************************************************
Socket Parser
***********************************************************/
private class SocketDataListener implements Runnable {
public void run() {
String line;
try {
while ( _socketReader != null &&
_socket != null &&
_socket.isClosed() == false &&
(line = _socketReader.readLine()) != null) {
if (_printDebug == true) {
System.out.println("PJLink received: " + line);
System.out.flush();
}
// Projector greeting, no authentication.
if (line.startsWith("PJLINK 0")) {
_pjlinkKey = "";
_sessionUsesAuthentication = false;
_socketReadyForCommand = true;
}
// Projector greeting, authentication challenge.
else if (line.startsWith("PJLINK 1 ")) {
_pjlinkKey = line.substring(9);
_sessionUsesAuthentication = true;
_socketReadyForCommand = true;
}
// PJLink data response.
else {
// Authentication error.
if (line.indexOf(" ERRA") > -1) {
System.out.println("PJLink authentication error. " + _ipAddress);
_socket.close();
}
// Undefined command.
if (line.endsWith("ERR1")){
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_UNDEFINED_COMMAND));
}
// Unavailable time.
if (line.endsWith("ERR3")){
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_UNAVAILABLE_TIME));
}
// Projector failure.
else if (line.endsWith("ERR4")) {
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, PJlinkCode.ERROR_PROJECTOR_FAILURE));
}
// Power response.
else if (line.startsWith("%1POWR=")) {
// Accepted power command.
if (line.endsWith("OK")) {
_powerState = _newPowerState;
updatePowerState();
}
// Returned power state value.
else {
int powerState = Integer.parseInt(line.substring(7));
_powerState = powerState;
updatePowerState();
}
}
// Input response.
else if (line.startsWith("%1INPT=")||line.startsWith("%2INPT=")) {
// Accepted input selection.
if (line.endsWith("OK")) {
_activeInput = _newActiveInput;
updateInputState();
}
// Nonexistent input source.
else if (line.endsWith("ERR2")) {
_newActiveInput = _activeInput; // Input switch cancelled.
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INPUT, PJlinkCode.INPUT_ERROR_NONEXISTENT_SOURCE));
}
// Returned active input value.
else {
int activeInput = Integer.parseInt(line.substring(7, 8));
if (activeInput > 0) {
_activeInput = activeInput;
}
updateInputState();
}
}
// A/V mute response.
else if (line.startsWith("%1AVMT=")) {
// Accepted mute instruction.
if (line.endsWith("OK")) {
_audioMuteActive = _newAudioMuteActive;
_videoMuteActive = _newVideoMuteActive;
updateAVMuteState();
}
else if (line.endsWith("ERR2")) {
_newAudioMuteActive = _audioMuteActive;
_newVideoMuteActive = _videoMuteActive;
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_AV_MUTE, PJlinkCode.MUTE_ERROR_CANNOT_MUTE));
}
else {
int avmt = Integer.parseInt(line.substring(7,9));
switch (avmt) {
case PJlinkCode.MUTE_VIDEO_ONLY:
_videoMuteActive = true;
_audioMuteActive = false;
break;
case PJlinkCode.MUTE_AUDIO_ONLY:
_videoMuteActive = false;
_audioMuteActive = true;
break;
case PJlinkCode.MUTE_AUDIO_VIDEO:
_videoMuteActive = true;
_audioMuteActive = true;
break;
case PJlinkCode.MUTE_OFF:
_videoMuteActive = false;
_audioMuteActive = false;
break;
default: break;
}
updateAVMuteState();
}
}
// Error status response.
else if (line.startsWith("%1ERST=")) {
if (line.length() == 13) {
_fanError = Integer.parseInt(line.substring(7, 8));
_lampError = Integer.parseInt(line.substring(8, 9));
_tempError = Integer.parseInt(line.substring(9, 10));
_coverError = Integer.parseInt(line.substring(10, 11));
_filterError = Integer.parseInt(line.substring(11, 12));
_otherError = Integer.parseInt(line.substring(12, 13));
// TODO: Refactor error status bit packing.
// This method will just confuse people who are unfamiliar with binary operations.
// Make it easy and well-named.
// Packed bits:
// | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// |Fail|Unav|Undf| | Other | Filter| Cover | Temp | Lamp | Fan |
// Bit 15: Projector Failure
// Bit 14: In Unavailable Time
// Bit 13: Undefined Command
int packedData = _fanError << 0 +
_lampError << 2 +
_tempError << 4 +
_coverError << 6 +
_filterError << 8 +
_otherError << 10;
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_ERROR, packedData));
}
}
// Lamp status response.
else if (line.startsWith("%1LAMP=")) {
int hoursEndPos = line.indexOf(' ', 7);
if (hoursEndPos > -1) {
_lampHours = Integer.parseInt(line.substring(7, hoursEndPos));
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_LAMP, _lampHours));
}
}
// Input list response.
else if (line.startsWith("%1INST=")||line.startsWith("%2INST=")) {
// TODO: Implement list enumeration response.
INST = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INST, 0,INST));
}
else if (line.startsWith("%1NAME=")) {
NAME = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_NAME, 0,NAME));
}
else if (line.startsWith("%1INFO=")) {
INFO = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INFO, 0,INFO));
}
else if (line.startsWith("%1INF1=")) {
INF1 = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INF1, 0,INF1));
}
else if (line.startsWith("%1INF2=")) {
INF2 = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INF2, 0,INF2));
}
else if (line.startsWith("%1CLSS=")) {
CLSS = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_CLSS, 0,CLSS));
}
else if (line.startsWith("%2SNUM=")) {
SNUM = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_SNUM, 0,SNUM));
}
else if (line.startsWith("%2SVER=")) {
SVER = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_SVER, 0,SVER));
}
else if (line.startsWith("%2INNM=")) {
INNM = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_INNM, 0,INNM));
}
else if (line.startsWith("%2IRES=")) {
IRES = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_IRES, 0,IRES));
}
else if (line.startsWith("%2FILT=")) {
FILT = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_FILT, 0,FILT));
}
else if (line.startsWith("%2RLMP=")) {
RLMP = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_RLMP, 0,RLMP));
}
else if (line.startsWith("%2RFIL=")) {
RFIL = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_RFIL, 0,RFIL));
}
else if (line.startsWith("%2FREZ=")) {
FREZ = line.substring(7);
notifyListeners(new PJLinkEvent(PJLinkEvent.EVENT_FREZ, 0,FREZ));
}
_socketCommandReceived = true;
}
}
if (_socket != null) disconnect();
}
catch (IOException ex) {
}
}
}
}
private class PJLinkCommand {
private String _command = "";
public PJLinkCommand() {
}
public PJLinkCommand(String command) {
_command = command;
}
public void execute() {
if (_command.length() == 0) return;
if (_ipAddress.length() == 0) return;
if (_printDebug == true) {
System.out.println("Executing command: " + _command);
System.out.flush();
}
_pjlinkSocket.sendCommand(_command);
}
}
}
常量码PJlinkCode:
public class PJlinkCode {
// Packed error bits:
// | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// |Fail|Unav|Undf|Conn| Other | Filter| Cover | Temp | Lamp | Fan |
// Projector errors.
// See SocketDataListener private class for bit map.
public static final int ERROR_FAN_WARNING = 0x0001;
public static final int ERROR_FAN_ERROR = 0x0002;
public static final int ERROR_LAMP_WARNING = 0x0004;
public static final int ERROR_LAMP_ERROR = 0x0008;
public static final int ERROR_TEMP_WARNING = 0x0010;
public static final int ERROR_TEMP_ERROR = 0x0020;
public static final int ERROR_COVER_WARNING = 0x0040;
public static final int ERROR_COVER_ERROR = 0x0080;
public static final int ERROR_FILTER_WARNING = 0x0100;
public static final int ERROR_FILTER_ERROR = 0x0200;
public static final int ERROR_OTHER_WARNING = 0x0400;
public static final int ERROR_OTHER_ERROR = 0x0800;
public static final int ERROR_CONNECTION = 0x1000;
public static final int ERROR_UNDEFINED_COMMAND = 0x2000;
public static final int ERROR_UNAVAILABLE_TIME = 0x4000;
public static final int ERROR_PROJECTOR_FAILURE = 0x8000;
// Power codes taken from PJLink spec.
public static final int POWER_OFF = 0;
public static final int POWER_ON = 1;
public static final int POWER_COOLING = 2;
public static final int POWER_WARMING = 3;
// Input codes taken from PJLink spec.
public static final int INPUT_ERROR_NONEXISTENT_SOURCE = 2;
public static final int INPUT_RGB_1 = 11;
public static final int INPUT_RGB_2 = 12;
public static final int INPUT_RGB_3 = 13;
public static final int INPUT_RGB_4 = 14;
public static final int INPUT_RGB_5 = 15;
public static final int INPUT_RGB_6 = 16;
public static final int INPUT_RGB_7 = 17;
public static final int INPUT_RGB_8 = 18;
public static final int INPUT_RGB_9 = 19;
public static final int INPUT_VIDEO_1 = 21;
public static final int INPUT_VIDEO_2 = 22;
public static final int INPUT_VIDEO_3 = 23;
public static final int INPUT_VIDEO_4 = 24;
public static final int INPUT_VIDEO_5 = 25;
public static final int INPUT_VIDEO_6 = 26;
public static final int INPUT_VIDEO_7 = 27;
public static final int INPUT_VIDEO_8 = 28;
public static final int INPUT_VIDEO_9 = 29;
public static final int INPUT_DIGITAL_1 = 31;
public static final int INPUT_DIGITAL_2 = 32;
public static final int INPUT_DIGITAL_3 = 33;
public static final int INPUT_DIGITAL_4 = 34;
public static final int INPUT_DIGITAL_5 = 35;
public static final int INPUT_DIGITAL_6 = 36;
public static final int INPUT_DIGITAL_7 = 37;
public static final int INPUT_DIGITAL_8 = 38;
public static final int INPUT_DIGITAL_9 = 39;
public static final int INPUT_STORAGE_1 = 41;
public static final int INPUT_STORAGE_2 = 42;
public static final int INPUT_STORAGE_3 = 43;
public static final int INPUT_STORAGE_4 = 44;
public static final int INPUT_STORAGE_5 = 45;
public static final int INPUT_STORAGE_6 = 46;
public static final int INPUT_STORAGE_7 = 47;
public static final int INPUT_STORAGE_8 = 48;
public static final int INPUT_STORAGE_9 = 49;
public static final int INPUT_NETWORK_1 = 51;
public static final int INPUT_NETWORK_2 = 52;
public static final int INPUT_NETWORK_3 = 53;
public static final int INPUT_NETWORK_4 = 54;
public static final int INPUT_NETWORK_5 = 55;
public static final int INPUT_NETWORK_6 = 56;
public static final int INPUT_NETWORK_7 = 57;
public static final int INPUT_NETWORK_8 = 58;
public static final int INPUT_NETWORK_9 = 59;
// A/V Mute codes taken from PJLink spec.
public static final int MUTE_ERROR_CANNOT_MUTE = 2;
public static final int MUTE_VIDEO_ONLY = 11;
public static final int MUTE_AUDIO_ONLY = 21;
public static final int MUTE_AUDIO_VIDEO = 31;
public static final int MUTE_OFF = 30;
}
然后是事件监听类PJLinkListener:
public interface PJLinkListener {
public void deviceStateChanged(PJLink source, PJLinkEvent e);
}
事件类:
package com.castle.ream.pjlink.util.pjlink;
public class PJLinkEvent {
// public static final int EVENT_CON_ERR = -1;
// public static final int EVENT_CON_ON = -2;
// public static final int EVENT_CON_PFF = -3;
// public static final int EVENT_DEV_ERR = -4;
public static final int EVENT_ERROR = 0;
public static final int EVENT_POWER = 1;
public static final int EVENT_INPUT = 2;
public static final int EVENT_AV_MUTE = 3;
public static final int EVENT_LAMP = 4;
public static final int EVENT_INST = 5;
public static final int EVENT_NAME = 6;
public static final int EVENT_INFO = 7;
public static final int EVENT_INF1 = 8;
public static final int EVENT_INF2 = 9;
public static final int EVENT_CLSS = 10;
public static final int EVENT_SNUM = 11;
public static final int EVENT_SVER = 12;
public static final int EVENT_INNM = 13;
public static final int EVENT_IRES = 14;
public static final int EVENT_FILT = 15;
public static final int EVENT_RLMP = 16;
public static final int EVENT_RFIL = 17;
public static final int EVENT_FREZ = 18;
private int _eventType;
private int _data;
private String _message = "";
public PJLinkEvent(int eventType, int data) {
_eventType = eventType;
_data = data;
}
public PJLinkEvent(int eventType, int data, String message) {
_eventType = eventType;
_data = data;
_message = message;
}
public int getEventType() {
return _eventType;
}
public int getEventData() {
return _data;
}
public String getEventMessage() {
return _message;
}
}
测试:
public class Test {
public static void main(String[] args) {
PJLink p = new PJLink("192.168.1.3",5555);
p.setPrintDebug(true);
PJLinkListener listener = new PJLinkListener() {
@Override
public void deviceStateChanged(PJLink p, PJLinkEvent e) {
// if(arg1 != null && PJLinkEvent.EVENT_ERROR==arg1.getEventType()&& PJLink.ERROR_CONNECTION == arg1.getEventData()) {
// System.out.println("in...");
// p.setConnectionError(true);
// }
int eventCode = e.getEventType();
switch (eventCode) {
case PJLinkEvent.EVENT_ERROR:
int data = e.getEventData();
switch (data) {
case PJlinkCode.ERROR_CONNECTION:
break;
case PJlinkCode.ERROR_UNDEFINED_COMMAND:
break;
case PJlinkCode.ERROR_UNAVAILABLE_TIME:
break;
case PJlinkCode.ERROR_PROJECTOR_FAILURE:
break;
default:
break;
}
break;
case PJLinkEvent.EVENT_POWER:
break;
case PJLinkEvent.EVENT_INPUT:
break;
case PJLinkEvent.EVENT_AV_MUTE:
break;
case PJLinkEvent.EVENT_LAMP:
break;
case PJLinkEvent.EVENT_INST:
break;
case PJLinkEvent.EVENT_NAME:
break;
case PJLinkEvent.EVENT_INFO:
break;
case PJLinkEvent.EVENT_INF1:
break;
case PJLinkEvent.EVENT_INF2:
break;
case PJLinkEvent.EVENT_CLSS:
break;
case PJLinkEvent.EVENT_SNUM:
break;
case PJLinkEvent.EVENT_SVER:
break;
case PJLinkEvent.EVENT_INNM:
break;
case PJLinkEvent.EVENT_IRES:
break;
case PJLinkEvent.EVENT_FILT:
break;
case PJLinkEvent.EVENT_RLMP:
break;
case PJLinkEvent.EVENT_RFIL:
break;
case PJLinkEvent.EVENT_FREZ:
break;
default:
break;
}
}
};
p.addListener(listener);
while(true){
// System.out.println(p.getConnectionError());
System.out.println(RamUsageEstimator.sizeOf(p));
try {
Thread.sleep(3000);
} catch (Exception e) {
// TODO: handle exception
}
}
}
}
添加监听,根据不同的事件类型做出相关的操作,如库操作。
RamUsageEstimator.sizeOf(p)是查看内存对象大小的方法,具体见:点我
启动测试类(PJLINKServer和Test)
告辞!