001/* 002 * $URL: svn://fred.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/eiscp/Eiscp.java $ 003 * $Author: tgutwin $ 004 * $Revision: 1308 $ 005 * $Date: 2020-02-02 10:41:39 -0800 (Sun, 02 Feb 2020) $ 006 */ 007/* 008 * 009 * Written by Tom Gutwin - WebARTS Design. 010 * Copyright (C) 2012-2014 WebARTS Design, North Vancouver Canada 011 * http://www.webarts.bc.ca 012 * 013 * This program is free software; you can redistribute it and/or modify 014 * it under the terms of the GNU General Public License as published by 015 * the Free Software Foundation; either version 2 of the License, or 016 * (at your option) any later version. 017 * 018 * This program is distributed in the hope that it will be useful, 019 * but WITHOUT ANY WARRANTY; without_ even the implied warranty of 020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 021 * GNU General Public License for more details. 022 * 023 * You should have received a copy of the GNU General Public License 024 * along with this program; if not, write to the Free Software 025 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 026 */ 027 028package ca.bc.webarts.tools.eiscp; 029 030import java.io.*; 031import java.net.*; 032import java.util.HashMap; 033import java.util.TreeSet; 034import java.util.Iterator; 035import java.util.Vector; 036 037/** 038 * A class that wraps the comunication to Onkyo/Integra devices using the 039 * ethernet Integra Serial Control Protocal (eISCP). This class uses class 040 * constants and commandMaps to help handling of the many iscp Commands. 041 * <br /> 042 * The Message packet looks like:<br /> 043 * <img src="http://tom.webarts.ca/_/rsrc/1320209141605/Blog/new-blog-items/javaeiscp-integraserialcontrolprotocol/eISCP-Packet.png" border="1"/> 044 * <br /> See also <a href="http://tom.webarts.ca/Blog/new-blog-items/javaeiscp-integraserialcontrolprotocol" > tom.webarts.ca</a> writeup. 045 * 046 * @author Tom Gutwin P.Eng 047 */ 048public class Eiscp 049{ 050 /** A holder for this clients System File Separator. */ 051 public final static String SYSTEM_FILE_SEPERATOR = File.separator; 052 053 /** A holder for this clients System line termination separator. */ 054 public final static String SYSTEM_LINE_SEPERATOR = 055 System.getProperty("line.separator"); 056 057 /** The VM classpath (used in some methods).. */ 058 public static String CLASSPATH = System.getProperty("class.path"); 059 060 /** The users home ditrectory. */ 061 public static String USERHOME = System.getProperty("user.home"); 062 063 /** The users pwd ditrectory. */ 064 public static String USERDIR = System.getProperty("user.dir"); 065 066 /** A holder This classes name (used when logging). */ 067 private static String CLASSNAME = "ca.bc.webarts.tools.eiscp.Eiscp"; 068 069 /** Class flag signifying if the initUtil method has been called */ 070 private static boolean classInit = false; 071 072 /** Class flag signifying if debugging_ messages are ptinted */ 073 private static boolean debugging_ = true; 074 075 /** default receiver IP Address. **/ 076 private static final String DEFAULT_EISCP_IP = "10.0.0.203"; 077 /** Instantiated class IP for the receiver to communicate with. **/ 078 private String receiverIP_ = DEFAULT_EISCP_IP; 079 080 /** default eISCP port. **/ 081 private static final int DEFAULT_EISCP_PORT = 60128; 082 /** Instantiated class Port for the receiver to communicate with. **/ 083 private int receiverPort_ = DEFAULT_EISCP_PORT; 084 085 /** the socket for communication - the protocol spec says to use one socket connection AND HOLD ONTO IT for re-use. 086 Note: The communication between server and client should hold one connection continuously. Unless it has connected continuously, the notice of status cannot be performed from a client. 087 Note: The number of the connections who can connect with a client is one. 088 Note: The Interval Time Receiving the message needs to take more than 50msec. 089 **/ 090 private static Socket eiscpSocket_ = null; 091 /** the timeout in ms for socket reads. **/ 092 private static int socketTimeOut_ = 800; 093 private static ObjectOutputStream out_ = null; 094 private static DataInputStream in_ = null; 095 private static boolean connected_ = false; 096 097 private static IscpCommands iscp_ = IscpCommands.getInstance(); 098 099 /** Maps the class contant vars to the eiscp command string. **/ 100 private static HashMap<Integer, String> commandMap_ = null; 101 102 /** Maps a Readable string to a corresponding class var. **/ 103 private static HashMap<String, Integer> commandNameMap_ = null; 104 105 /** Var to hold the volume level to or from a message. **/ 106 private static int volume_ = 32; 107 108 private static StringBuffer helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR); 109 110 /** Simple class Constructor (using deafult IP and port) that gets all the class command constants set-up along with their command lookup maps (commandNameMap_ and commandMap_) . **/ 111 public Eiscp() 112 { 113 //initCommandMap(); 114 } 115 116 117 /** Constructor that takes your receivers ip and default port, gets all the class command 118 * constants set-up along with their command lookup maps (commandNameMap_ and commandMap_) . 119 **/ 120 public Eiscp(String ip) 121 { 122 //initCommandMap(); 123 if (ip==null || ip.equals("")) 124 receiverIP_=DEFAULT_EISCP_IP; 125 else 126 receiverIP_=ip; 127 receiverPort_=DEFAULT_EISCP_PORT; 128 } 129 130 131 /** Constructor that takes your receivers ip and port, gets all the class command 132 * constants set-up along with their command lookup maps (commandNameMap_ and commandMap_) . 133 **/ 134 public Eiscp(String ip, int eiscpPort) 135 { 136 //initCommandMap(); 137 if (ip==null || ip.equals("")) 138 receiverIP_=DEFAULT_EISCP_IP; 139 else 140 receiverIP_=ip; 141 if (eiscpPort<1 ) 142 receiverPort_=DEFAULT_EISCP_PORT; 143 else 144 receiverPort_=eiscpPort; 145 } 146 147 /** Makes Chocolate glazed doughnuts. **/ 148 public void setReceiverIP( String ip) { receiverIP_ = ip;} 149 /** Makes Sprinkle doughnuts. **/ 150 public String getReceiverIP() {return receiverIP_;} 151 /** Makes mini doughnuts. **/ 152 public void setReceiverPort( int port) { receiverPort_ = port;} 153 /** Makes glazed doughnuts. **/ 154 public int getReceiverPort() {return receiverPort_;} 155 156 /** 157 * Connects to the receiver by opening a socket connection through the DEFaULT IP and DEFAULT eISCP port. 158 **/ 159 public boolean connectSocket() { return connectSocket(null, -1);} 160 161 162 /** 163 * Connects to the receiver by opening a socket connection through the DEFAULT eISCP port. 164 **/ 165 public boolean connectSocket(String ip) { return connectSocket(ip,-1);} 166 167 168 /** 169 * Connects to the receiver by opening a socket connection through the eISCP port. 170 **/ 171 public boolean connectSocket(String ip, int eiscpPort) 172 { 173 if (ip==null || ip.equals("")) ip=receiverIP_; 174 if (eiscpPort<1 ) eiscpPort=receiverPort_; 175 176 if (eiscpSocket_==null || !connected_ || !eiscpSocket_.isConnected()) 177 try 178 { 179 //1. creating a socket to connect to the server 180 eiscpSocket_ = new Socket(ip, eiscpPort); 181 System.out.println("Connected to "+ip+" on port "+eiscpPort); 182 //2. get Input and Output streams 183 out_ = new ObjectOutputStream(eiscpSocket_.getOutputStream()); 184 in_ = new DataInputStream(eiscpSocket_.getInputStream()); 185 186 //System.out.println("out_Init"); 187 out_.flush(); 188 // System.out.println("inInit"); 189 connected_ = true; 190 } 191 catch(UnknownHostException unknownHost) 192 { 193 System.err.println("You are trying to connect to an unknown host!"); 194 } 195 catch(IOException ioException) 196 { 197 System.err.println("Can't Connect: "+ioException.getMessage()); 198 } 199 return connected_; 200 } 201 202 203 public boolean isConnected() 204 { 205 boolean retVal = true; 206 if (eiscpSocket_==null || !connected_ || !eiscpSocket_.isConnected()) 207 retVal = false; 208 return retVal; 209 } 210 211 212 /** 213 * Tests the Connection to the receiver by opening a socket connection through the DEFaULT IP and DEFAULT eISCP port. 214 * @return true if already connected or can connect, and false if can't connect 215 **/ 216 public boolean testConnection() { return testConnection(DEFAULT_EISCP_IP,DEFAULT_EISCP_PORT);} 217 218 219 /** 220 * Tests the Connection to the receiver by opening a socket connection through the specified IP and DEFAULT eISCP port. 221 * @param ip is the ip address (as a String) of the AV receiver to connect 222 * @return true if already connected or can connect, and false if can't connect 223 **/ 224 public boolean testConnection(String ip) { return testConnection(DEFAULT_EISCP_IP,DEFAULT_EISCP_PORT);} 225 226 227 /** 228 * test the connection to the receiver by opening a socket connection through the eISCP port AND THEN CLOSES it if it was not already open. 229 * this method can be used when you need to specificly specify the IP and PORT. If the default port is used then you could also use the 230 * {@link #testConnection(String) testConnection} method (that used the default port) or the {@link #testConnection() testConnection} 231 * method (that used the default IP and port). 232 * 233 * @param ip is the ip address (as a String) of the AV receiver to connect 234 * @param eiscpPort is the IP Port of the AV receiver to connect with (Onkyo's default is 60128) 235 * @return true if already connected or can connect, and false if can't connect 236 **/ 237 public boolean testConnection(String ip, int eiscpPort) 238 { 239 boolean retVal = false; 240 if (ip==null || ip.equals("")) ip=DEFAULT_EISCP_IP; 241 if (eiscpPort==0 ) eiscpPort=DEFAULT_EISCP_PORT; 242 243 if (connected_) 244 { 245 // test existing connection 246 if (eiscpSocket_.isConnected()) retVal = true; 247 } 248 else 249 { 250 // test a new connection 251 try 252 { 253 //1. creating a socket to connect to the server 254 eiscpSocket_ = new Socket(ip, eiscpPort); 255 if (eiscpSocket_!=null) eiscpSocket_.close(); 256 retVal = true; 257 } 258 catch(UnknownHostException unknownHost) 259 { 260 System.err.println("You are trying to connect to an unknown host!"); 261 } 262 catch(IOException ioException) 263 { 264 System.err.println("Can't Connect: "+ioException.getMessage()); 265 } 266 } 267 return retVal; 268 } 269 270 271 /** 272 * Closes the socket connection. 273 * @return true if the closed succesfully 274 **/ 275 public boolean closeSocket() 276 { 277 //4: Closing connection 278 try 279 { 280 boolean acted = false; 281 if (in_!=null) {in_.close();in_=null;acted = true;} 282 if (out_!=null) {out_.close();out_=null;acted = true;} 283 if (eiscpSocket_!=null) {eiscpSocket_.close();eiscpSocket_=null;acted = true;} 284 if (acted) System.out.println("closed connections"); 285 connected_ = false; 286 } 287 catch(IOException ioException) 288 { 289 ioException.printStackTrace(); 290 } 291 return connected_; 292 } 293 294 295 public static String convertAsciiToBase10(String str) {return convertAsciiToBase10( str, false);} 296 public static String convertAsciiToBase10(String str, boolean dumpOut) 297 { 298 char[] chars = str.toCharArray(); 299 StringBuffer base10 = new StringBuffer(); 300 if (dumpOut) System.out.print(" Base10: "); 301 for(int i = 0; i < chars.length; i++) 302 { 303 base10.append( (int)chars[i]); 304 if(i+1<chars.length) base10.append( ";" ); 305 if (dumpOut) System.out.print(" "+((""+(int)chars[i]).length()==1?"0":"")+(int)chars[i] + " "); 306 } 307 if (dumpOut) System.out.println(""); 308 return base10.toString(); 309 } 310 311 312 /** Converts an ascii decimal String to a hex String. 313 * @param str holding the string to convert to HEX 314 * @return a string holding the HEX representation of the passed in decimal str. 315 **/ 316 public static String convertStringToHex(String str) 317 { 318 return convertStringToHex( str, false); 319 } 320 321 322 /** Converts an ascii decimal String to a hex String. 323 * @param str holding the string to convert to HEX 324 * @param dumpOut flag to turn some debug output on/off 325 * @return a string holding the HEX representation of the passed in str. 326 **/ 327 public static String convertStringToHex(String str, boolean dumpOut) 328 { 329 char[] chars = str.toCharArray(); 330 String out_put = ""; 331 332 if (dumpOut) System.out.println(" Ascii: "+str); 333 if (dumpOut) System.out.print(" Hex: "); 334 StringBuffer hex = new StringBuffer(); 335 for(int i = 0; i < chars.length; i++) 336 { 337 out_put = Integer.toHexString((int)chars[i]); 338 if (out_put.length()==1) hex.append("0"); 339 hex.append(out_put); 340 if (dumpOut) System.out.print("0x"+(out_put.length()==1?"0":"")+ out_put+" "); 341 } 342 if (dumpOut) System.out.println(""); 343 if (dumpOut) convertAsciiToBase10(str,dumpOut); 344 /* 345 if (dumpOut) System.out.print(" Base10: "); 346 for(int i = 0; i < chars.length; i++) 347 { 348 System.out.print(" "+convertHexNumberStringToDecimal(chars[i])); 349 } 350 if (dumpOut) System.out.println(""); 351 */ 352 353 return hex.toString(); 354 } 355 356 357 /** Converts an HEX number String to its decimal equivalent. 358 * @param str holding the Hex Number string to convert to decimal 359 * @return an int holding the decimal equivalent of the passed in HEX numberStr. 360 **/ 361 public static int convertHexNumberStringToDecimal(String str) 362 { 363 return convertHexNumberStringToDecimal(str, false); 364 } 365 366 367 /** Converts an HEX number String to its decimal equivalent. 368 * @param str holding the Hex Number string to convert to decimal 369 * @param dumpOut boolean flag to turn some debug output on/off 370 * @return an int holding the decimal equivalent of the passed in HEX numberStr. 371 **/ 372 public static int convertHexNumberStringToDecimal(String str, boolean dumpOut) 373 { 374 char[] chars = str.toCharArray(); 375 String out_put = ""; 376 377 if (dumpOut) System.out.println("\n AsciiHex: 0x"+str); 378 if (dumpOut) System.out.print( " Decimal: "); 379 380 StringBuffer hex = new StringBuffer(); 381 String hexInt = new String(); 382 for(int i = 0; i < chars.length; i++) 383 { 384 out_put = Integer.toHexString((int)chars[i]); 385 if (out_put.length()==1) hex.append("0"); 386 hex.append(out_put); 387 if (dumpOut) System.out.print((out_put.length()==1?"0":"")+ out_put); 388 } 389 hexInt = ""+(Integer.parseInt( hex.toString(), 16)); 390 if (dumpOut) System.out.println(""); 391 if (dumpOut) System.out.println( " Decimal: "+hexInt.toString()); 392 393 return Integer.parseInt(hexInt.toString()); 394 395 //return Integer.decode("0x"+str); 396 } 397 398 399 /** Converts a hex byte to an ascii String. 400 * @param hex byte holding the HEX string to convert back to decimal 401 * @return a string holding the HEX representation of the passed in str. 402 **/ 403 public static String convertHexToString(byte hex) 404 { 405 byte [] bytes = {hex}; 406 return convertHexToString( new String(bytes), false); 407 } 408 409 410 /** Converts a hex String to an ascii String. 411 * @param hex the HEX string to convert back to decimal 412 * @return a string holding the HEX representation of the passed in str. 413 **/ 414 public static String convertHexToString(String hex) 415 { 416 return convertHexToString( hex, false); 417 } 418 419 420 /** Converts a hex String to an ascii String. 421 * @param hex the HEX string to convert backk to decimal 422 * @param dumpOut boolean flag to turn some debug output on/off 423 * @return a string holding the HEX representation of the passed in str. 424 **/ 425 public static String convertHexToString(String hex, boolean dumpOut) 426 { 427 428 StringBuilder sb = new StringBuilder(); 429 StringBuilder temp = new StringBuilder(); 430 String out_put = ""; 431 432 if (dumpOut) System.out.print(" Hex: "); 433 //49204c6f7665204a617661 split into two characters 49, 20, 4c... 434 for( int i=0; i<hex.length()-1; i+=2 ){ 435 436 //grab the hex in pairs 437 out_put = hex.substring(i, (i + 2)); 438 if (dumpOut) System.out.print("0x"+out_put+" "); 439 //convert hex to decimal 440 int decimal = Integer.parseInt(out_put, 16); 441 //convert the decimal to character 442 sb.append((char)decimal); 443 444 temp.append(decimal); 445 } 446 if (dumpOut) System.out.println(" Decimal : " + temp.toString()); 447 448 return sb.toString(); 449 } 450 451 452 /** 453 * Wraps a command in a eiscp data message (data characters). 454 * 455 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 456 * @return StringBuffer holing the full iscp message packet , empty if not a valid command or parameter 457 **/ 458 public StringBuilder getEiscpMessage(int command){ return getEiscpMessage(command, null);} 459 public StringBuilder getEiscpMessage(int command, String param) 460 { 461 StringBuilder sb = new StringBuilder(""); 462 String cmdStr = ""; 463 464 if(command==iscp_.VOLUME_SET || command==iscp_.TUNING_FREQ) 465 { 466 if(param==null || param.trim().equals("")) 467 { 468 param = ""; // NOT Valid so leave sb empty so it does NOT get sent 469 } 470 else 471 if(param.trim().length() == 2 || param.trim().length() == 5) 472 { 473 try 474 { 475 // test if valid 476 int p = Integer.parseInt(param.trim()); 477 478 //if no Exception, then good to go... stitch it together 479 if (command==iscp_.VOLUME_SET) cmdStr = getVolumeCmdStr(p); 480 else if (command==iscp_.TUNING_FREQ) cmdStr = getTuneFreqCmdStr(param.trim()); 481 } 482 catch(java.lang.NumberFormatException nfEx) 483 { 484 param = ""; 485 // NOT Valid so leave sb empty so it does NOT get sent 486 } 487 } 488 else 489 param = "";// NOT Valid so leave sb empty so it does NOT get sent 490 } 491 else 492 cmdStr = iscp_.getCommandStr(command); 493 494 if(!cmdStr.equals("")) 495 { 496 int eiscpDataSize = iscp_.getCommandStr(command).length() + 2 ; // this is the eISCP data size 497 int eiscpMsgSize = eiscpDataSize + 1 + 16 ; // this is the eISCP data size 498 499 /* This is where I construct the entire message 500 character by character. Each char is represented by a 2 disgit hex value */ 501 sb.append("ISCP"); 502 // the following are all in HEX representing one char 503 504 // 4 char Big Endian Header 505 sb.append((char)Integer.parseInt("00", 16)); 506 sb.append((char)Integer.parseInt("00", 16)); 507 sb.append((char)Integer.parseInt("00", 16)); 508 sb.append((char)Integer.parseInt("10", 16)); 509 510 // 4 char Big Endian data size 511 sb.append((char)Integer.parseInt("00", 16)); 512 sb.append((char)Integer.parseInt("00", 16)); 513 sb.append((char)Integer.parseInt("00", 16)); 514 // the official ISCP docs say this is supposed to be just the data size (eiscpDataSize) 515 // ** BUT ** 516 // It only works if you send the size of the entire Message size (eiscpMsgSize) 517 sb.append((char)Integer.parseInt(Integer.toHexString(eiscpMsgSize), 16)); 518 519 // eiscp_version = "01"; 520 sb.append((char)Integer.parseInt("01", 16)); 521 522 // 3 chars reserved = "00"+"00"+"00"; 523 sb.append((char)Integer.parseInt("00", 16)); 524 sb.append((char)Integer.parseInt("00", 16)); 525 sb.append((char)Integer.parseInt("00", 16)); 526 527 // eISCP data 528 // Start Character 529 sb.append("!"); 530 531 // eISCP data - unittype char '1' is receiver 532 sb.append("1"); 533 534 // eISCP data - 3 char command and param ie PWR01 535 sb.append(cmdStr); 536 537 // msg end - EOF 538 sb.append((char)Integer.parseInt("0D", 16)); 539 540 //System.out.println(" eISCP data size: "+eiscpDataSize +"(0x"+Integer.toHexString(eiscpDataSize) +") chars"); 541 //System.out.println(" eISCP msg size: "+sb.length() +"(0x"+Integer.toHexString(sb.length()) +") chars"); 542 } 543 544 return sb; 545 } //getEiscpMessage 546 547 548 /** dumps all the commands to System.out along with its associated eIscp message string in BASE10 numbers. 549 * For example:< br />LISTEN_MODE_THEATER_DIMENSIONAL: 550 **/ 551 public void dumpBinaryMessages() 552 { 553 StringBuilder sb = null; 554 Iterator<String> it =iscp_.getIterator(); 555 String currCommandName = null; 556 while( it.hasNext()) 557 { 558 currCommandName = it.next(); 559 sb = getEiscpMessage(iscp_.getCommand(currCommandName)); 560 System.out.println(currCommandName+": "+convertAsciiToBase10(sb.toString())); 561 } 562 } 563 564 565 /** 566 * Sends to command ultiple times sequentially to the receiver and WAITS until each is completed. 567 * 568 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 569 * @param numRepeats how many doughnuts to buy. 570 * @param closeSocketWhenDone do we hold the door open for the next doughnut customer , after we leave 571 **/ 572 public void sendCommandMultipleTimes(int command, int numRepeats, boolean closeSocketWhenDone) 573 { 574 for(int i=0;i<numRepeats;i++) 575 { 576 sendQueryCommand(command, false); 577 sleep(50); // EISCP specifies a delay 578 } 579 if (closeSocketWhenDone) closeSocket(); 580 } 581 582 583 /** 584 * Sends to command ultiple times sequentially to the receiver and WAITS until each is completed and 585 * hold the door open for the next doughnut customer , after we leave. 586 * 587 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 588 * @param numRepeats how many doughnuts to buy. 589 **/ 590 public void sendCommandMultipleTimes(int command, int numRepeats) 591 { 592 sendCommandMultipleTimes( command, numRepeats, false); 593 } 594 595 596 /** 597 * Sends to command to the receiver and does not wait for a reply. 598 * 599 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 600 **/ 601 public void sendCommand(int command) 602 { 603 sendCommand(command, "", false); 604 } 605 606 607 /** 608 * Sends to command to the receiver and does not wait for a reply. 609 * 610 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 611 **/ 612 public void sendCommand(int command, String param) 613 { 614 sendCommand(command, param, false); 615 } 616 617 618 /** 619 * Sends to command to the receiver and does not wait for a reply. 620 * 621 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 622 * @param param paramater to customize a command Str for VOLUME_SET ?? or TUNING_FREQ ????? 623 * @param closeSocket flag to close the connection when done or leave it open. 624 **/ 625 public void sendCommand(int command, String param, boolean closeSocket) 626 { 627 StringBuilder sb = new StringBuilder(""); 628 629 if(command==iscp_.VOLUME_SET || command==iscp_.TUNING_FREQ) 630 { 631 if(param==null || param.trim().equals("")) 632 { 633 param = ""; // NOT Valid so leave sb empty so it does NOT get sent 634 } 635 else 636 if(param.trim().length() == 2 || param.trim().length() == 5) 637 { 638 try 639 { 640 // test if valid 641 int p = Integer.parseInt(param.trim()); 642 643 //if no Exception, then good to go... stitch it together 644 sb = getEiscpMessage(command, param.trim()); 645 //sb.append(param.trim()); 646 } 647 catch(java.lang.NumberFormatException nfEx) 648 { 649 param = ""; 650 // NOT Valid so leave sb empty so it does NOT get sent 651 } 652 } 653 else 654 param = "";// NOT Valid so leave sb empty so it does NOT get sent 655 } 656 else 657 sb = getEiscpMessage(command); 658 659 if(sb.toString().trim().length()>0 && connectSocket()) 660 { 661 try 662 { 663 System.out.println(" sending "+sb.length() +" chars: "); 664 convertStringToHex(sb.toString(), true); 665 //out_.writeObject(sb.toString()); 666 //out_.writeChars(sb.toString()); 667 out_.writeBytes(sb.toString()); // <--- This is the one that works 668 //out_.writeBytes(convertStringToHex(sb.toString(), false)); 669 //out_.writeChars(convertStringToHex(sb.toString(), false)); 670 out_.flush(); 671 System.out.println("sent!" ); 672 } 673 catch(java.net.SocketException socketException) 674 { 675 System.out.println(" Socket Was Disconnected... Reconnecting and Resending"); 676 connectSocket(); 677 try 678 { 679 out_.writeBytes(sb.toString()); 680 out_.flush(); 681 System.out.println("sent!" ); 682 } 683 catch(IOException ioEx) 684 { 685 ioEx.printStackTrace(); 686 } 687 } 688 catch(IOException ioException) 689 { 690 ioException.printStackTrace(); 691 } 692 } 693 if (closeSocket) closeSocket(); 694 } 695 696 697 /** 698 * Sends to command to the receiver and then waits for the response(s) <br />and returns only the response packetMessages related to the command requested<br />and closes the socket. 699 * if you want to see ALL the responses use the sendQueryCommand(int command, boolean closeSocket, boolean returnAll) method. 700 * 701 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 702 * @return the response to the command 703 **/ 704 public String sendQueryCommand(int command) 705 { 706 return sendQueryCommand( command, false); 707 } 708 709 710 /** 711 * Sends to command to the receiver and then waits for the response(s) <br />and returns only the response packetMessages related to the command requested. 712 * if you want to see ALL the responses use the sendQueryCommand(int command, boolean closeSocket, boolean returnAll) method. 713 * 714 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 715 * @param closeSocket flag to close the connection when done or leave it open. 716 * @return the response to the command 717 **/ 718 public String sendQueryCommand(int command, boolean closeSocket) 719 { 720 return sendQueryCommand( command, closeSocket, false); 721 } 722 723 724 /** 725 * Sends to command to the receiver and then waits for the response(s). The responses often have nothing to do with the command sent 726 * so this method can filter them to return only the responses related to the command sent. 727 * 728 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 729 * @param closeSocket flag to close the connection when done or leave it open. 730 * @param returnAll flags if all response packetMessages are returned, if no then ONLY the ones related to the command requested 731 * @return the response to the command 732 **/ 733 public String sendQueryCommand(int command, boolean closeSocket, boolean returnAll) 734 { 735 String retVal = ""; 736 737 /* Send The Command and then... */ 738 System.out.println(" sendQueryCommand ("+command+", "+closeSocket+", "+returnAll+")"); 739 System.out.println(" command="+iscp_.getCommandStr(command)); 740 sendCommand(command,null,false); 741 sleep(50); // docs say so 742 743 /* now listen for the response. */ 744 Vector <String> rv = null; 745 if(returnAll) 746 rv = readQueryResponses(); 747 else 748 rv = readQueryResponses(command); 749 String currResponse = ""; 750 for (int i=0; i < rv.size(); i++) 751 { 752 currResponse = (String) rv.elementAt(i); 753 /* Send ALL responses OR just the one related to the commad sent??? */ 754 if (returnAll || currResponse.startsWith(iscp_.getCommandStr(command).substring(0,3))) 755 retVal+= currResponse+"\n"; 756 } 757 758 if (closeSocket) closeSocket(); 759 760 return retVal ; 761 } 762 763 764 /** 765 * This method reads ALL responses (possibly more than one) after a query command. 766 * @return an array of the data portion of the response messages only - There might be more than one response message received. 767 **/ 768 public Vector <String> readQueryResponses() { return readQueryResponses(-1);} 769 /** 770 * This method reads responses (possibly more than one) after a query command. It can end 771 * early when it finds the respose you are waitng for by passing in the command you called. 772 * @param command is used to end the response processing early when it finds the command - if you want all responses processed pass in -1 773 * @return an array of the data portion of the response messages only - There might be more than one response message received. 774 **/ 775 public Vector <String> readQueryResponses(int command) 776 { 777 //boolean debugging = debugging_; 778 boolean foundCommand = false; 779 Vector <String> retVal = new Vector <String> (); 780 byte [] responseBytes = new byte[32] ; 781 String currResponse = ""; 782 int numBytesReceived = 0; 783 int totBytesReceived = 0; 784 int i=0; 785 String dataMsgStr = ""; 786 int packetCounter=0; 787 int headerSizeDecimal = 0; 788 int dataSizeDecimal = 0; 789 char endChar1 ='!';// NR-5008 response sends 3 chars to terminate the packet - 0x1a 0x0d 0x0a 790 char endChar2 ='!'; 791 char endChar3 ='!'; 792 int readDelay = 0; 793 794 if(connected_) 795 { 796 try 797 { 798 System.out.println("\nReading Response Packet,looking for "+(command>0?iscp_.getCommandStr(command):"ALL responses")); 799 eiscpSocket_.setSoTimeout(socketTimeOut_); // this must be set or the following read will BLOCK / hang the method when the messages are done 800 801 //readDelay = calendar_.get(calendar_.MILLISECOND); 802 while(!foundCommand && ((numBytesReceived = in_.read(responseBytes))>=0) ) 803 { 804 totBytesReceived = 0; 805 StringBuilder msgBuffer = new StringBuilder(""); 806 if (debugging_) System.out.println("\n*\n*\n*\n*Buffering received bytes: "+numBytesReceived); 807 if (debugging_) System.out.print( " Packet"+"["+packetCounter+"]:"); 808 809 /* Read ALL the incoming Bytes and buffer them */ 810 // ******************************************* 811 while(numBytesReceived>0 ) 812 { 813 totBytesReceived+=numBytesReceived; 814 msgBuffer.append(new String(responseBytes)); 815 responseBytes = new byte[32]; 816 numBytesReceived = 0; 817 if (in_.available()>0) 818 numBytesReceived = in_.read(responseBytes); 819 if (debugging_) System.out.print(" "+numBytesReceived); 820 } 821 if (debugging_) System.out.println(); 822 convertStringToHex(msgBuffer.toString(), debugging_); 823 824 /* Response is done... process it into dataMessages */ 825 // ******************************************* 826 char [] responseChars = msgBuffer.toString().toCharArray(); // use the charArray to step through 827 msgBuffer = null;// clear for garbageCollection 828 829 System.out.println("\n "+i+") responseChars.length="+responseChars.length); 830 int responseByteCnt = 0; 831 char versionChar = '1'; 832 char dataStartChar = '!'; 833 char dataUnitChar = '1'; 834 char [] headerSizeBytes = new char[4]; 835 char [] dataSizeBytes = new char[4]; 836 char [] dataMessage = null ; //init dynamically 837 int dataByteCnt = 0; 838 839 // loop through all the chars and split out the dataMessages 840 while (!foundCommand && (responseByteCnt< totBytesReceived)) 841 { 842 /* read Header */ 843 // 1st 4 chars are the leadIn 844 responseByteCnt+=4; 845 846 // read headerSize 847 headerSizeBytes[0]=responseChars[responseByteCnt++]; 848 headerSizeBytes[1]=responseChars[responseByteCnt++]; 849 headerSizeBytes[2]=responseChars[responseByteCnt++]; 850 headerSizeBytes[3]=responseChars[responseByteCnt++]; 851 852 // 4 char Big Endian data size; 853 dataSizeBytes[0]=responseChars[responseByteCnt++]; 854 dataSizeBytes[1]=responseChars[responseByteCnt++]; 855 dataSizeBytes[2]=responseChars[responseByteCnt++]; 856 dataSizeBytes[3]=responseChars[responseByteCnt++]; 857 858 if (debugging_) System.out.println(" -HeaderSize-"); 859 headerSizeDecimal = convertHexNumberStringToDecimal(new String(headerSizeBytes), debugging_); 860 if (debugging_) System.out.println(" -DataSize-"); 861 dataSizeDecimal = convertHexNumberStringToDecimal(new String(dataSizeBytes), debugging_); 862 863 // version 864 versionChar = responseChars[responseByteCnt++]; 865 866 // 3 reserved bytes 867 responseByteCnt+=3; 868 dataByteCnt = 0; 869 870 // Now the data message 871 dataStartChar = responseChars[responseByteCnt++]; // parse and throw away (like parsley) 872 dataUnitChar = responseChars[responseByteCnt++]; // dito 873 dataMessage = null; 874 if (debugging_) System.out.println("new dataMessage["+dataSizeDecimal+"]"); 875 if(dataSizeDecimal<4096) 876 dataMessage = new char [dataSizeDecimal]; 877 else 878 { 879 dataMessage= new char[0]; 880 System.out.println("error data message size hexVal="+dataSizeBytes); 881 break; 882 } 883 884 /* Get the dataMessage from this response */ 885 // NR-5008 response sends 3 chars to terminate the packet - so DON't include them in the message 886 while( dataByteCnt < (dataSizeDecimal-5) && responseByteCnt< (totBytesReceived-3)) 887 { 888 dataMessage[dataByteCnt++] = responseChars[responseByteCnt++]; 889 } 890 dataMsgStr = new String(dataMessage); 891 if (debugging_) System.out.println("dataMessage:\n~~~~~~~~~~~~~"); 892 if (debugging_) System.out.println(" "+dataMsgStr); 893 retVal.addElement(dataMsgStr); 894 895 // Read the end packet char(s) "[EOF]" 896 // [EOF] End of File ASCII Code 0x1A 897 // NOTE: the end of packet char (0x1A) for a response message is DIFFERENT that the sent message 898 // NOTE: ITs also different than what is in the Onkyo eISCP docs 899 // NR-5008 sends 3 chars to terminate the packet - 0x1a 0x0d 0x0a 900 endChar1 = responseChars[responseByteCnt++]; 901 endChar2 = responseChars[responseByteCnt++]; 902 endChar3 = responseChars[responseByteCnt++]; 903 if (endChar1 == (char)Integer.parseInt("1A", 16) && 904 endChar2 == (char)Integer.parseInt("0D", 16) && 905 endChar3 == (char)Integer.parseInt("0A", 16) 906 ) 907 if (debugging_) System.out.println(" EndOfPacket["+packetCounter+"]\n"); 908 packetCounter++; 909 // Now check if we end early 910 if (command!=-1 && dataMsgStr.startsWith(iscp_.getCommandStr(command).substring(0,3))) 911 { 912 foundCommand = true; 913 System.out.println(" Found Matched Response:"+iscp_.getCommandStr(command) +" = " + dataMsgStr); 914 } 915 }// done packet 916 System.out.println(" Found Response:"+iscp_.getCommandStr(command) +" = " + dataMsgStr); 917 i++; 918 readDelay = 0; 919 } // check for more data 920 921 } 922 catch( java.net.SocketTimeoutException noMoreDataException) 923 { 924 System.out.println(" EXCEPTION SocketTimeout after "+i+" packets already found"); 925 System.out.println(" received: \""+retVal+"\"" ); 926 if(i>0) retVal.addElement(dataMsgStr); 927 noMoreDataException.printStackTrace(); 928 } 929 catch(EOFException eofException) 930 { 931 System.out.println("received: \""+retVal+"\"" ); 932 } 933 catch(IOException ioException) 934 { 935 ioException.printStackTrace(); 936 } 937 } 938 else 939 System.out.println("!!Not Connected to Receive "); 940 return retVal; 941 } 942 943 944 /** This method creates the set volume command based on the passed value. **/ 945 public static String getVolumeCmdStr(){return iscp_.getVolumeCmdStr(volume_);} 946 public static String getVolumeCmdStr(int vol){return iscp_.getVolumeCmdStr(vol);} 947 948 949 /** This method creates the set volume command based on the passed value. **/ 950 public static String getTuneFreqCmdStr(String freqStr){return iscp_.getTuneFreqCmdStr(freqStr);} 951 952 953 /** Converts the VOLUME_QUERY response into ascii decimal result. **/ 954 public static String decipherVolumeResponse(String queryResponses) 955 { 956 String [] responses = queryResponses.split("[\n]"); 957 String retVal = "VOLUME_QUERY response: "; 958 String queryResponse = ""; 959 String volVal = "00"; 960 Integer IntVal = Integer.decode("0x"+volVal); 961 for (int i=0; i< responses.length; i++) 962 { 963 queryResponse = responses[i]; 964 if (queryResponse.startsWith(iscp_.getCommandStr(iscp_.VOLUME_SET))) 965 { 966 try 967 { 968 volVal = queryResponse.trim().substring(3); 969 IntVal = Integer.decode("0x"+volVal); 970 retVal +="\n Volume=" + IntVal; 971 retVal +=" (0x" + volVal +")\n"; 972 } 973 catch (Exception ex) 974 { 975 // Ignore for now 976 } 977 } 978 } 979 return retVal; 980 } 981 982 983 /** Converts the SOURCE_QUERY response into ascii string result. **/ 984 public static String deciherSourceResponseToString(String queryResponses) 985 { 986 String [] responses = queryResponses.split("[\n]"); 987 String queryResponse = ""; 988 String sourceCodeStr = "00"; 989 String sourceString = "00"; 990 for (int i=0; i< responses.length; i++) 991 { 992 queryResponse = responses[i].trim(); 993 if (queryResponse.startsWith("response:")) 994 { 995 sourceCodeStr = queryResponse.substring("response:".length()).trim(); 996 sourceString = iscp_.getCommandStr( 997 iscp_.getCommandKey(sourceCodeStr.substring(1,sourceCodeStr.length()-1)) 998 ); 999 } 1000 } 1001 return iscp_.getCommandName(queryResponses); //sourceString; 1002 } 1003 1004 1005 /** Converts the VOLUME_QUERY response into ascii decimal result. **/ 1006 public static String deciherVolumeResponseToDecimal(String queryResponses) 1007 { 1008 String [] responses = queryResponses.split("[\n]"); 1009 String retVal = ""; 1010 String queryResponse = ""; 1011 String volVal = "00"; 1012 Integer IntVal = Integer.decode("0x"+volVal); 1013 for (int i=0; i< responses.length; i++) 1014 { 1015 queryResponse = responses[i]; 1016 if (queryResponse.startsWith(iscp_.getCommandStr(iscp_.VOLUME_SET))) 1017 { 1018 try 1019 { 1020 volVal = queryResponse.trim().substring(3); 1021 IntVal = Integer.decode("0x"+volVal); 1022 retVal ="" + IntVal; 1023 // retVal ="0x" + volVal ; 1024 } 1025 catch (Exception ex) 1026 { 1027 // Ignore for now 1028 } 1029 } 1030 } 1031 return retVal; 1032 } 1033 1034 1035 /** Converts the VOLUME_QUERY response into ascii hex result. **/ 1036 public static String deciherVolumeResponseToHex(String queryResponses) 1037 { 1038 String [] responses = queryResponses.split("[\n]"); 1039 String retVal = ""; 1040 String queryResponse = ""; 1041 String volVal = "00"; 1042 Integer IntVal = Integer.decode("0x"+volVal); 1043 for (int i=0; i< responses.length; i++) 1044 { 1045 queryResponse = responses[i]; 1046 if (queryResponse.startsWith(iscp_.getCommandStr(iscp_.VOLUME_SET))) 1047 { 1048 try 1049 { 1050 volVal = queryResponse.trim().substring(3); 1051 IntVal = Integer.decode("0x"+volVal); 1052 // retVal ="" + IntVal; 1053 retVal ="0x" + volVal ; 1054 } 1055 catch (Exception ex) 1056 { 1057 // Ignore for now 1058 } 1059 } 1060 } 1061 return retVal; 1062 } 1063 1064 1065 /** This method takes the 3 character response from the USB Play status query (NETUSB_PLAY_STATUS_QUERY) and creates a human readable String. 1066 * NET/USB Play Status QUERY returns one of 3 letters - PRS.<oL> 1067 * <LI>p -> Play Status<ul><li>"S": STOP</li><li>"P": Play</li><li>"p": Pause</li><li>"F": FF</li><li>"R": FastREW</li></ul></LI> 1068 * <LI>r -> Repeat Status<ul><li>"-": Off</li><li>"R": All</li><li>"F": Folder</li><li>"1": Repeat 1</li></ul></LI> 1069 * <LI>s -> Shuffle Status<ul><li>"-": Off</li><li>"S": All</li><li>"A": Album</li><li>"F": Folder</li></ul></LI></oL> 1070 * @param queryResponses is the entire response packet with the oneOf3 char reply embedded in it. 1071 **/ 1072 public String decipherUsbPlayStatusResponse(String queryResponses) 1073 { 1074 String [] responses = queryResponses.split("[\n]"); 1075 String retVal = "NETUSB_PLAY_STATUS_QUERY response: "+ queryResponses.trim(); 1076 String queryResponse = ""; 1077 for (int i=0; i< responses.length; i++) 1078 { 1079 queryResponse = responses[i]; 1080 if (queryResponse.substring(3,4).equals("P") ) 1081 { 1082 retVal += "\n Play Status: "; 1083 if (queryResponse.substring(5).equals("S") ) 1084 retVal +="Stop"; 1085 else if (queryResponse.substring(5).equals("P") ) 1086 retVal +="Play"; 1087 else if (queryResponse.substring(5).equals("p") ) 1088 retVal +="Pause"; 1089 else if (queryResponse.substring(5).equals("F") ) 1090 retVal +="FastForward"; 1091 else if (queryResponse.substring(5).equals("R") ) 1092 retVal +="FastRewind"; 1093 else retVal+= "NotSpecified"; 1094 } 1095 1096 if (queryResponse.substring(3,4).equals("R") ) 1097 { 1098 retVal += "\n Repeat Status: "; 1099 if (queryResponse.substring(5).equals("-") ) 1100 retVal +="Off"; 1101 else if (queryResponse.substring(5).equals("R") ) 1102 retVal +="All"; 1103 else if (queryResponse.substring(5).equals("F") ) 1104 retVal +="Folder"; 1105 else if (queryResponse.substring(5).equals("1") ) 1106 retVal +="1 song"; 1107 else retVal+= "NotSpecified"; 1108 } 1109 1110 if (queryResponse.substring(3,4).equals("S") ) 1111 { 1112 retVal += "\n Schuffle Status: "; 1113 if (queryResponse.trim().substring(5).equals("-") ) 1114 retVal +="Off"; 1115 else if (queryResponse.trim().substring(5).equals("S") ) 1116 retVal +="All"; 1117 else if (queryResponse.trim().substring(5).equals("A") ) 1118 retVal +="Album"; 1119 else if (queryResponse.trim().substring(5).equals("F") ) 1120 retVal +="Folder"; 1121 else retVal+= "NotSpecified"; 1122 } 1123 } 1124 1125 return retVal; 1126 } 1127 1128 1129 /** Converts the response packets into a JSON result. **/ 1130 public String decipherNetUsbResponse(int command, String queryResponses) 1131 { 1132 String [] responses = queryResponses.split("[\n]"); 1133 1134 System.out.println("decipherNetUsbResponse responses= "+java.util.Arrays.toString(responses)); 1135 String retVal = "{\n \"command\": \""+ iscp_.getCommandStr(command)+"\""; 1136 retVal += ",\n \"numberOfPackets\": "+responses.length; 1137 retVal += ",\n \"responsePackets\": ["; 1138 String queryResponse = ""; 1139 boolean debugging = true; 1140 String [] dirEntry = new String[responses.length]; 1141 String [] parentDirEntry = new String[responses.length]; 1142 1143 System.out.println("\n Eiscp Processing command="+iscp_.getCommandStr(command)); 1144 if (command==iscp_.NETUSB_SONG_TRACK_QUERY) 1145 { 1146 System.out.println("\n Eiscp Processing command="+iscp_.getCommandStr(command)); 1147 for (int i=0; i< responses.length; i++) 1148 { 1149 queryResponse=responses[i].trim(); 1150 //System.out.println("\n "+queryResponse); 1151 if(queryResponse.trim().startsWith("NLTF") ) retVal+= "\nDir ="+queryResponse; 1152 if(queryResponse.trim().startsWith("NLSU") ) retVal+= "\nSong "+queryResponse.substring(4,6).trim()+" = "+queryResponse.substring(6).trim(); 1153 //if(i>0) retVal += ","; 1154 //retVal += "\n \""+queryResponse+"\""; 1155 1156 } 1157 } 1158 else if (command==iscp_.NETUSB_OP_SELECT || command==iscp_.NETUSB_OP_RETURN|| command==iscp_.NETUSB_OP_DISPLAY) 1159 { 1160 int selectedEntry= -1; 1161 // DISPLAY uses NLSC?P as the slected entry indicator 1162 for (int i=0; i< responses.length && selectedEntry>-1; i++) 1163 { 1164 queryResponse=responses[i].trim(); 1165 if(queryResponse!=null && queryResponse.length()>4 && queryResponse.indexOf("NLSC")>-1 ) 1166 selectedEntry=Integer.parseInt(queryResponse.substring(4,5)) ; 1167 } 1168 1169 String selectedPacketKey = "NLSU"+selectedEntry+"-"; 1170 String currentEntry = ""; 1171 String parentEntry = ""; 1172 int entryCounter = 0; 1173 int parentEntryCounter = 0; 1174 boolean inCurrDir = false; 1175 int dirLevel = -1; 1176 1177 for (int i=0; i< responses.length; i++) 1178 { 1179 queryResponse=responses[i].trim(); 1180 if(queryResponse!=null && queryResponse.length()>6 && queryResponse.indexOf("NLTF10")>-1 && Integer.parseInt(queryResponse.substring( 6,7)) > dirLevel) //NLTF10200000000000002FF00SND 1181 { 1182 if( debugging ) System.out.println(" DEBUG: deciphering "+"NETUSB_OP_SELECT"+" currDirLevel="+dirLevel+" parsed val="+Integer.parseInt(queryResponse.substring( 6,7))); 1183 dirLevel = Integer.parseInt(queryResponse.substring( 6,7)); 1184 } 1185 } 1186 if( debugging ) System.out.println(" DEBUG: current dir is listed Under: NLTF10"+dirLevel); 1187 1188 for (int i=0; i< responses.length; i++) 1189 { 1190 queryResponse=responses[i].trim(); 1191 1192 if(queryResponse.indexOf(selectedPacketKey)>-1) 1193 { 1194 //currentEntry = queryResponse.substring( queryResponse.indexOf("02FF0")+"02FF0".length()+1 ).trim(); 1195 currentEntry = queryResponse.substring( queryResponse.indexOf(selectedPacketKey)+selectedPacketKey.length() ).trim(); 1196 inCurrDir=true; 1197 } 1198 1199 if(queryResponse.indexOf("NLTF10")>-1 && queryResponse.indexOf("02FF0") >-1) 1200 { 1201 parentEntry = queryResponse.substring( queryResponse.indexOf("02FF0")+"02FF0".length()+1 ).trim(); 1202 inCurrDir=false; 1203 } 1204 1205 if(queryResponse.indexOf("NLSU")>-1 ) 1206 dirEntry[entryCounter++] = queryResponse.substring( queryResponse.indexOf("NLSU")+"NLSU".length()+2 ).trim(); 1207 //else if(queryResponse.indexOf("NLSU")>-1) 1208 // parentDirEntry[parentEntryCounter++] = queryResponse.substring( queryResponse.indexOf("NLSU")+"NLSU".length()+2 ).trim(); 1209 1210 if( debugging && queryResponse!=null && !"".equals(queryResponse)) 1211 { 1212 if(i==0) retVal += "\n"; 1213 else retVal += ",\n"; 1214 retVal += " \""+queryResponse+"\""; 1215 } 1216 } 1217 //if( debugging ) retVal += ","; 1218 retVal += "\n ]"; 1219 retVal += ",\n \"currentDir\": \""+currentEntry+"\""; 1220 1221 if(entryCounter>0) 1222 { 1223 retVal += ",\n \"currentDirEntries\": [ \n"; 1224 for (int i=0; i< entryCounter; i++) 1225 { 1226 if (i>0) {retVal += ",";} 1227 //retVal += "\n \"entry"+i+"\": "; 1228 retVal += "\""+dirEntry[i]+"\""; 1229 } 1230 retVal += "\n ] "; 1231 } 1232 1233 retVal += ",\n \"parentEntry\": \""+parentEntry+"\""; 1234 if(parentEntryCounter>0) 1235 { 1236 retVal += ",\n \"parentDirEntries\": [ \n"; 1237 for (int i=0; i< parentEntryCounter; i++) 1238 { 1239 if (i>0) {retVal += ",";} 1240 //retVal += "\n \"entry"+i+"\": "; 1241 retVal += "\""+parentDirEntry[i]+"\""; 1242 } 1243 retVal += "\n ] "; 1244 } 1245 } 1246 else if (command==iscp_.NETUSB_OP_DOWN || command==iscp_.NETUSB_OP_UP) 1247 { 1248 // DISPLAY uses NLSU?P as the slected entry indicator/KEY 1249 int selectedEntry= Integer.parseInt(responses[responses.length-1].substring(4,5)) ; 1250 String selectedPacketKey = "NLSU"+selectedEntry+"-"; 1251 String currentEntry = ""; 1252 String parentEntry = ""; 1253 for (int i=0; i< responses.length; i++) 1254 { 1255 queryResponse=responses[i].trim(); 1256 1257 // NLSU0 is the currentselection when NLSC0C is the last packet 1258 // NLSU1 is the currentselection when NLSC1C is the last packet 1259 if(queryResponse.indexOf(selectedPacketKey)>-1) currentEntry = queryResponse.substring( queryResponse.indexOf(selectedPacketKey)+selectedPacketKey.length() ).trim(); 1260 if(queryResponse.indexOf("2FF00")>-1) parentEntry = queryResponse.substring( queryResponse.indexOf("2FF00")+"2FF00".length() ).trim(); 1261 if( debugging && queryResponse!=null && !"".equals(queryResponse)) 1262 { 1263 if(i==0) retVal += "\n"; 1264 else retVal += ",\n"; 1265 retVal += " \""+queryResponse+"\""; 1266 } 1267 } 1268 retVal += "\n ]"; 1269 retVal += ",\n \"currentDir\": \""+currentEntry+"\"";; 1270 retVal += ",\n \"parentEntry\": \""+parentEntry+"\"";; 1271 1272 } 1273 else if (command==iscp_.NETUSB_OP_RIGHT || command==iscp_.NETUSB_OP_LEFT) 1274 { 1275 String currentEntry = ""; 1276 String parentEntry = ""; 1277 for (int i=0; i< responses.length; i++) 1278 { 1279 queryResponse=responses[i].trim(); 1280 1281 if(queryResponse.indexOf("NLSU0-")>-1) currentEntry = queryResponse.substring( queryResponse.indexOf("NLSU0-")+"NLSU0-".length() ).trim(); 1282 if(queryResponse.indexOf("NLTF101")>-1) parentEntry = queryResponse.substring( queryResponse.indexOf("2FF00")+"2FF00".length() ).trim(); 1283 if( debugging && queryResponse!=null && !"".equals(queryResponse)) 1284 { 1285 if(i==0) retVal += "\n"; 1286 else retVal += ",\n"; 1287 retVal += " \""+queryResponse+"\""; 1288 } 1289 } 1290 retVal += "\n ]"; 1291 retVal += ",\n \"currentDir\": \""+currentEntry+"\"";; 1292 retVal += ",\n \"parentEntry\": \""+parentEntry+"\"";; 1293 } 1294 else if (command==iscp_.NETUSB_OP_CHANUP || command==iscp_.NETUSB_OP_CHANDWN) 1295 { 1296 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1297 int selectedEntry= -1; 1298 // DISPLAY uses NLSC?P as the slected entry indicator 1299 for (int i=0; i< responses.length; i++) 1300 { 1301 queryResponse=responses[i].trim(); 1302 if(queryResponse.indexOf("NLSC")>-1 ) selectedEntry=Integer.parseInt(queryResponse.substring(4,5)) ; 1303 } 1304 1305 String selectedPacketKey = "NLSU"+selectedEntry+"-"; 1306 String currentEntry = ""; 1307 String parentEntry = ""; 1308 for (int i=0; i< responses.length; i++) 1309 { 1310 queryResponse=responses[i].trim(); 1311 1312 // NLSU0 is the currentselection when NLSC0C is the last packet 1313 // NLSU1 is the currentselection when NLSC1C is the last packet 1314 if(queryResponse.indexOf(selectedPacketKey)>-1) currentEntry = queryResponse.substring( queryResponse.indexOf(selectedPacketKey)+selectedPacketKey.length() ).trim(); 1315 if(queryResponse.indexOf("2FF00")>-1) parentEntry = queryResponse.substring( queryResponse.indexOf("2FF00")+"2FF00".length() ).trim(); 1316 if( debugging && queryResponse!=null && !"".equals(queryResponse)) 1317 { 1318 if(i==0) retVal += "\n"; 1319 else retVal += ",\n"; 1320 retVal += " \""+queryResponse+"\""; 1321 } 1322 } 1323 retVal += "\n ]"; 1324 retVal += ",\n \"currentDir\": \""+currentEntry+"\"";; 1325 retVal += ",\n \"parentEntry\": \""+parentEntry+"\"";; 1326 1327 } 1328 else if (command==iscp_.NETUSB_PLAY_STATUS_QUERY) 1329 { 1330 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1331 } 1332 else if (command==iscp_.NETUSB_SONG_ELAPSEDTIME_QUERY) 1333 { 1334 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1335 } 1336 else if (command==iscp_.NETUSB_SONG_ARTIST_QUERY) 1337 { 1338 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1339 } 1340 else if (command==iscp_.NETUSB_SONG_ALBUM_QUERY) 1341 { 1342 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1343 } 1344 else if (command==iscp_.NETUSB_SONG_TITLE_QUERY) 1345 { 1346 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1347 } 1348 else if (command==iscp_.NETUSB_OP_DISPLAY) 1349 { 1350 System.out.println("Processing command="+iscp_.getCommandStr(command)); 1351 } 1352 1353 retVal += "\n \n }"; 1354 return retVal; 1355 } 1356 1357 1358 /** 1359 * A method to simply abstract the Try/Catch required to put the current 1360 * thread to sleep for the specified time in ms. 1361 * 1362 * @param waitTime the sleep time in milli seconds (ms). 1363 * @return boolean value specifying if the sleep completed (true) or was interupted (false). 1364 */ 1365 public boolean sleep(long waitTime) 1366 { 1367 boolean retVal = true; 1368 /* 1369 * BLOCK for the spec'd time 1370 */ 1371 try 1372 { 1373 Thread.sleep(waitTime); 1374 } 1375 catch (InterruptedException iex) 1376 { 1377 retVal = false; 1378 } 1379 return retVal; 1380 } 1381 1382 1383 /** gets the help as a String. 1384 * @return the helpMsg in String form 1385 **/ 1386 private static String getHelpMsgStr() {return getHelpMsg().toString();} 1387 1388 1389 /** initializes and gets the helpMsg_ 1390 class var. 1391 * @return the class var helpMsg_ 1392 **/ 1393 private static StringBuffer getHelpMsg() 1394 { 1395 helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR); 1396 helpMsg_.append("--- WebARTS Eiscp Class -----------------------------------------------------"); 1397 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1398 helpMsg_.append("--- $Revision: 1308 $ $Date: 2020-02-02 10:41:39 -0800 (Sun, 02 Feb 2020) $ ---"); 1399 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1400 helpMsg_.append("-------------------------------------------------------------------------------"); 1401 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1402 helpMsg_.append("WebARTS Eiscp Class"); 1403 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1404 helpMsg_.append("SYNTAX:"); 1405 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1406 helpMsg_.append(" java "); 1407 helpMsg_.append(CLASSNAME); 1408 helpMsg_.append(" [hostIP] command [commandArgs]"); 1409 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1410 helpMsg_.append(" - hostIP is optional and defaults to 10.0.0.203"); 1411 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1412 helpMsg_.append(" - command is NOT optional"); 1413 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1414 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1415 helpMsg_.append("Available Commands:"); 1416 /* now add all the commands available */ 1417 Iterator<String> it =iscp_.getIterator(); 1418 while( it.hasNext()) 1419 { 1420 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1421 helpMsg_.append("--> "+it.next()); 1422 } 1423 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1424 helpMsg_.append("---------------------------------------------------------"); 1425 helpMsg_.append("----------------------"); 1426 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1427 1428 return helpMsg_; 1429 } 1430 1431 1432 /** returns a text list of all the commands. 1433 * @return the list of commands as a string 1434 **/ 1435 public static String getCommandList() 1436 { 1437 StringBuffer retVal = new StringBuffer(""); 1438 1439 retVal.append("Available Commands:"); 1440 /* now add all the commands available */ 1441 Iterator<String> it =iscp_.getIterator(); 1442 while( it.hasNext()) 1443 { 1444 retVal.append(SYSTEM_LINE_SEPERATOR); 1445 retVal.append("--> "+it.next()); 1446 } 1447 1448 return retVal.toString(); 1449 } 1450 1451 1452 /** 1453 * Class main commandLine entry method. 1454 **/ 1455 public static void main(String [] args) 1456 { 1457 final String methodName = CLASSNAME + ": main()"; 1458 Eiscp instance = new Eiscp(DEFAULT_EISCP_IP, DEFAULT_EISCP_PORT); 1459 int commandArg = 0; 1460 1461 /* Simple way af parsing the args */ 1462 if (args ==null || args.length<1) 1463 System.out.println(getHelpMsgStr()); 1464 else 1465 { 1466 if (args[0].equals("test")) 1467 { 1468 System.out.println("Testing Eiscp"); 1469 String queryResponse = instance.sendQueryCommand(iscp_.VOLUME_QUERY); 1470 String volumeResponse = instance.decipherVolumeResponse(queryResponse); 1471 System.out.println(volumeResponse); 1472 System.out.println(); 1473 1474 instance.toggleMute(); 1475 System.out.println(); 1476 instance.sleep(750); 1477 instance.toggleMute(); 1478 } 1479 else if (args[0].equals("dump")) 1480 { 1481 System.out.println("Dumping Eiscp Messages as binary values."); 1482 instance.dumpBinaryMessages(); 1483 } 1484 else 1485 { 1486 /* Special case if Receiver IP was spec'd oncommandline */ 1487 if (args.length>1 && iscp_.getCommand(args[commandArg].toUpperCase())!=iscp_.VOLUME_SET) 1488 instance.setReceiverIP(args[commandArg++]); // also bump the commandArg ref counter 1489 1490 // Parse the command 1491 int command = -1; 1492 String commandStr = ""; 1493 // TODO: Set up a loop to handle multiple commands/args in one run with one socket connection 1494 command =iscp_.getCommand(args[commandArg].toUpperCase()); //returns -1 if not found 1495 commandStr=iscp_.getCommandStr(command); 1496 System.out.println("command: "+commandStr); 1497 1498 /* Special case VOLUME_SET command needs to parse a parameter. */ 1499 if ( command == iscp_.VOLUME_SET ) instance.setVolume(Integer.parseInt(args[commandArg+1])); 1500 1501 String queryResponse = ""; 1502 if (args[commandArg].toUpperCase().equals("DUMP")) 1503 { 1504 System.out.println("Dumping eIscp Messages as binary values.\n----------------------------------------------------"); 1505 instance.dumpBinaryMessages(); 1506 } 1507 else if (command!=-1) 1508 { 1509 /* It is a query command so send AND parse response */ 1510 if(args[commandArg].toUpperCase().endsWith("QUERY") 1511 && !args[commandArg].toUpperCase().startsWith("NETUSB_")) 1512 { 1513 //send the command and get the response 1514 queryResponse = instance.sendQueryCommand(command, true, false); 1515 System.out.print("\nResponses: \n " +queryResponse); 1516 if (queryResponse!=null && !queryResponse.equals("")) 1517 { 1518 if (command==iscp_.VOLUME_QUERY) 1519 { 1520 System.out.println(instance.decipherVolumeResponse(queryResponse)); 1521 } 1522 else 1523 System.out.println(" ="+ iscp_.getCommandName(queryResponse.trim())); 1524 } 1525 else 1526 System.out.println("\nEMPTY"); 1527 } 1528 else if( args[commandArg].toUpperCase().startsWith("NETUSB_")) 1529 { 1530 System.out.print("\nDEBUGGING: "+args[commandArg].toUpperCase()); 1531 //send the command and get the response 1532 queryResponse = instance.sendQueryCommand(command, true, true); 1533 //System.out.print("\nResponses: \n " +queryResponse); 1534 if (queryResponse!=null && !queryResponse.equals("")) 1535 { 1536 if (args[commandArg].toUpperCase().startsWith("NETUSB_")) 1537 { 1538 System.out.println(instance.decipherNetUsbResponse(command, queryResponse)); 1539 } 1540 } 1541 else 1542 System.out.println("\nEMPTY"); 1543 } 1544 1545 /* It is a basic change setting command (with no response) */ 1546 else 1547 { 1548 instance.sendCommand(command); //send the command 1549 } 1550 } 1551 else 1552 { 1553 System.out.println(getHelpMsgStr()+"\n *!*!*!*! --> "); 1554 System.out.println(args[commandArg].toUpperCase() + " not found"); 1555 } 1556 } 1557 instance.closeSocket(); 1558 } 1559 } // main 1560 1561 1562 /** 1563 * get the class volume_. 1564 * @return the volume_ 1565 **/ 1566 public int getVolume() 1567 { 1568 return volume_; 1569 } 1570 1571 1572 /** sets the class volume_ AND sends the VOLUME_SET command to the Onkyo device. 1573 * @param volume the DECIMAL value to set the class volume_ and MUST be volume<99 && volume>-1</pre> 1574 **/ 1575 public void setVolume(int volume) 1576 { 1577 if(volume<99 && volume>-1) 1578 { 1579 volume_ = volume; 1580 String vStr = ""+volume_; 1581 if(vStr.length()==1) vStr="0"+vStr; 1582 sendCommand(iscp_.VOLUME_SET, vStr); 1583 } 1584 } 1585 1586 1587 /** Toggles the MUTE setting.. 1588 **/ 1589 public void toggleMute() 1590 { 1591 String queryResponse = sendQueryCommand(IscpCommands.MUTE_QUERY); 1592 if (true || debugging_) System.out.print("Responses: \n " +queryResponse.trim() + "("+iscp_.getCommandName(queryResponse.trim())+")"); 1593 if ( iscp_.getCommandName(queryResponse.trim()).equals("UNMUTE")) 1594 { 1595 if (true || debugging_) System.out.println("\nMuting ."); 1596 sendCommand(IscpCommands.MUTE); 1597 } 1598 else 1599 { 1600 if (true || debugging_) System.out.println("\nUN-Muting ."); 1601 sendCommand(IscpCommands.UNMUTE); 1602 } 1603 } 1604 1605} // class 1606 1607/* 1608Dumping eIscp Messages as binary values. 1609---------------------------------------------------- 1610POWER_OFF: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;80;87;82;48;48;13 1611POWER_ON: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;80;87;82;48;49;13 1612POWER_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;80;87;82;81;83;84;78;13 1613MUTE: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;65;77;84;48;49;13 1614UNMUTE: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;65;77;84;48;48;13 1615MUTE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;65;77;84;81;83;84;78;13 1616VOLUME_DOWN: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;77;86;76;68;79;87;78;13 1617VOLUME_DOWN1: 73;83;67;80;0;0;0;16;0;0;0;27;1;0;0;0;33;49;77;86;76;68;79;87;78;49;13 1618VOLUME_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;77;86;76;81;83;84;78;13 1619VOLUME_SET: 73;83;67;80;0;0;0;16;0;0;0;22;1;0;0;0;33;49;77;86;76;50;48;13 1620VOLUME_UP: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;77;86;76;85;80;13 1621VOLUME_UP1: 73;83;67;80;0;0;0;16;0;0;0;25;1;0;0;0;33;49;77;86;76;85;80;49;13 1622AUDIO_INFO_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;73;70;65;81;83;84;78;13 1623LISTEN_MODE_ALCHANSTEREO: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;48;67;13 1624LISTEN_MODE_AUDYSSEY_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;49;54;13 1625LISTEN_MODE_NEO_CINEMA_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;51;13 1626LISTEN_MODE_NEO_MUSIC_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;52;13 1627LISTEN_MODE_NEURAL_DIGITAL_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;54;13 1628LISTEN_MODE_NEURAL_SURROUND_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;53;13 1629LISTEN_MODE_PLII_GAME_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;50;13 1630LISTEN_MODE_PLII_MOVIE_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;48;13 1631LISTEN_MODE_PLII_MUSIC_DSX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;65;49;13 1632LISTEN_MODE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;76;77;68;81;83;84;78;13 1633LISTEN_MODE_STEREO: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;48;48;13 1634LISTEN_MODE_THEATER_DIMENSIONAL: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;76;77;68;48;68;13 1635NETUSB_OP_0: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;48;13 1636NETUSB_OP_1: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;49;13 1637NETUSB_OP_2: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;50;13 1638NETUSB_OP_3: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;51;13 1639NETUSB_OP_4: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;52;13 1640NETUSB_OP_5: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;53;13 1641NETUSB_OP_6: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;54;13 1642NETUSB_OP_7: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;55;13 1643NETUSB_OP_8: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;56;13 1644NETUSB_OP_9: 73;83;67;80;0;0;0;16;0;0;0;23;1;0;0;0;33;49;78;84;67;57;13 1645NETUSB_OP_CAPS: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;67;65;80;83;13 1646NETUSB_OP_CHANDWN: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;67;72;68;78;13 1647NETUSB_OP_CHANUP: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;67;72;85;80;13 1648NETUSB_OP_DELETE: 73;83;67;80;0;0;0;16;0;0;0;28;1;0;0;0;33;49;78;84;67;68;69;76;69;84;69;13 1649NETUSB_OP_DISPLAY: 73;83;67;80;0;0;0;16;0;0;0;29;1;0;0;0;33;49;78;84;67;68;73;83;80;76;65;89;13 1650NETUSB_OP_DOWN: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;68;79;87;78;13 1651NETUSB_OP_FF: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;78;84;67;70;70;13 1652NETUSB_OP_LEFT: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;76;69;70;84;13 1653NETUSB_OP_MENU: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;77;69;78;85;13 1654NETUSB_OP_PAUSE: 73;83;67;80;0;0;0;16;0;0;0;27;1;0;0;0;33;49;78;84;67;80;65;85;83;69;13 1655NETUSB_OP_PLAY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;80;76;65;89;13 1656NETUSB_OP_RANDOM: 73;83;67;80;0;0;0;16;0;0;0;28;1;0;0;0;33;49;78;84;67;82;65;78;68;79;77;13 1657NETUSB_OP_REPEAT: 73;83;67;80;0;0;0;16;0;0;0;28;1;0;0;0;33;49;78;84;67;82;69;80;69;65;84;13 1658NETUSB_OP_RETURN: 73;83;67;80;0;0;0;16;0;0;0;28;1;0;0;0;33;49;78;84;67;82;69;84;85;82;78;13 1659NETUSB_OP_REW: 73;83;67;80;0;0;0;16;0;0;0;25;1;0;0;0;33;49;78;84;67;82;69;87;13 1660NETUSB_OP_RIGHT: 73;83;67;80;0;0;0;16;0;0;0;27;1;0;0;0;33;49;78;84;67;82;73;71;72;84;13 1661NETUSB_OP_SELECT: 73;83;67;80;0;0;0;16;0;0;0;28;1;0;0;0;33;49;78;84;67;83;69;76;69;67;84;13 1662NETUSB_OP_SETUP: 73;83;67;80;0;0;0;16;0;0;0;27;1;0;0;0;33;49;78;84;67;83;69;84;85;80;13 1663NETUSB_OP_STOP: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;83;84;79;80;13 1664NETUSB_OP_TOPMENU: 73;83;67;80;0;0;0;16;0;0;0;25;1;0;0;0;33;49;78;84;67;84;79;80;13 1665NETUSB_OP_TRACKDWN: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;84;82;68;78;13 1666NETUSB_OP_TRACKUP: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;67;84;82;85;80;13 1667NETUSB_OP_UP: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;78;84;67;85;80;13 1668NETUSB_PLAY_STATUS_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;83;84;81;83;84;78;13 1669NETUSB_SONG_ALBUM_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;65;76;81;83;84;78;13 1670NETUSB_SONG_ARTIST_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;65;84;81;83;84;78;13 1671NETUSB_SONG_ELAPSEDTIME_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;77;81;83;84;78;13 1672NETUSB_SONG_TITLE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;73;81;83;84;78;13 1673NETUSB_SONG_TRACK_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;78;84;82;81;83;84;78;13 1674SOURCE_AM: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;53;13 1675SOURCE_AUX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;51;13 1676SOURCE_AUXILIARY: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;51;13 1677SOURCE_BLURAY: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;49;48;13 1678SOURCE_CD: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;51;13 1679SOURCE_COMPUTER: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;53;13 1680SOURCE_DOWN: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;83;76;73;68;79;87;78;13 1681SOURCE_DVR: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;48;13 1682SOURCE_FM: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;52;13 1683SOURCE_GAME: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;50;13 1684SOURCE_INTERETRADIO: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;56;13 1685SOURCE_MULTICH: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;51;48;13 1686SOURCE_MUSICSERVER: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;55;13 1687SOURCE_NETWORK: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;67;13 1688SOURCE_PC: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;53;13 1689SOURCE_PHONO: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;50;13 1690SOURCE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;83;76;73;81;83;84;78;13 1691SOURCE_SATELLITE: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;49;13 1692SOURCE_SIRIUS: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;51;50;13 1693SOURCE_TAPE1: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;48;13 1694SOURCE_TAPE2: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;49;13 1695SOURCE_TUNER: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;54;13 1696SOURCE_UP: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;85;80;13 1697SOURCE_USB: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;57;13 1698SOURCE_USB_BACK: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;50;65;13 1699SOURCE_VIDEO5: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;73;48;52;13 1700VIDEO_INFO_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;73;70;86;81;83;84;78;13 1701VIDEO_WIDE_43: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;49;13 1702VIDEO_WIDE_AUTO: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;48;13 1703VIDEO_WIDE_FULL: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;50;13 1704VIDEO_WIDE_NEXT: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;85;80;13 1705VIDEO_WIDE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;86;87;77;81;83;84;78;13 1706VIDEO_WIDE_SMARTZOOM: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;53;13 1707VIDEO_WIDE_WIDEZOOM: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;52;13 1708VIDEO_WIDE_ZOOM: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;86;87;77;48;51;13 1709ZONE2_POWER_ON: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;90;80;87;48;49;13 1710ZONE2_POWER_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;90;80;87;81;83;84;78;13 1711ZONE2_POWER_SBY: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;90;80;87;48;48;13 1712ZONE2_SOURCE_AUX: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;51;13 1713ZONE2_SOURCE_BLURAY: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;49;48;13 1714ZONE2_SOURCE_COMPUTER: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;53;13 1715ZONE2_SOURCE_DVR: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;48;13 1716ZONE2_SOURCE_GAME: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;50;13 1717ZONE2_SOURCE_QUERY: 73;83;67;80;0;0;0;16;0;0;0;26;1;0;0;0;33;49;83;76;90;81;83;84;78;13 1718ZONE2_SOURCE_SATELLITE: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;49;13 1719ZONE2_SOURCE_VIDEO5: 73;83;67;80;0;0;0;16;0;0;0;24;1;0;0;0;33;49;83;76;90;48;52;13 1720*/