001/* 002 * $URL: svn://fred.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/lednet/LedNetProxy.java $ 003 * $Author: tgutwin $ 004 * $Revision: 1302 $ 005 * $Date: 2019-11-03 17:19:03 -0800 (Sun, 03 Nov 2019) $ 006 */ 007/* 008 * 009 * Written by Tom Gutwin - WebARTS Design. 010 * Copyright (C) 2016-2017 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.lednet; 029 030import java.io.*; 031import java.net.*; 032import java.util.Arrays; 033import java.util.concurrent.atomic.DoubleAdder; 034import java.util.HashMap; 035import java.util.TreeSet; 036import java.util.Iterator; 037import java.util.Vector; 038 039/** 040 * A class that wraps the comunication to LedNet devices using the 041 * reverse engineered Protocol. Thanks go to the contributors on the Universal Device 042 * <a href="http://forum.universal-devices.com/topic/19913-magic-ufo-controller-for-rgbw" > Forum POST</a>. 043 * They wireSharked the message format. 044 * <br /> 045 * The TCP packets look like:<br /> 046 * On: 113;35;15;163;129;138;139;150<br /> 047 * Off: 113;36;15;164;129;138;139;150<br /> 048 * <br /> 049 * Red: 49;255;0;0;0;0;0;15;63;129;138;139;150<br /> 050 * Green: 49;0;255;0;0;0;0;15;63;129;138;139;150<br /> 051 * Blue: 49;0;0;255;0;0;0;15;63;129;138;139;150<br /> 052 * White: 49;0;0;0;255;0;0;15;63;129;138;139;150<br /> 053 * Cyan: 49;0;255;255;0;0;0;15;62;129;138;139;150<br /> 054 *<br /> 055 * You need to send the TCP packet to the LedNet IP at Port 5577. 056 *<br /> 057 * The bytes after the 15 (63) are stated as being checksum value of the first eight values and have to change for each code you send.<br /> 058 * Notice how the ON/Off commands use 163, 164? IT would seem the byte after the 15 (packet terminator) is always the sum of the digits from the first until the 15 (inclusive)<br /> 059 * In a normal protocol if the checksum didn't add up correctly the packet would be ignored as noise.<br /> 060 *<br /> 061 * Having said all that, the first single (primary = not cyan) colour packets you sent did add up to the 63 checksum and should have worked. 062 063 * <br /> See also <a href="http://forum.universal-devices.com/topic/19913-magic-ufo-controller-for-rgbw" > UDI Forum</a> writeup. 064 * 065 * @author Tom Gutwin P.Eng 066 */ 067public class LedNetProxy 068{ 069 /** A holder for this clients System File Separator. */ 070 public final static String SYSTEM_FILE_SEPERATOR = File.separator; 071 072 /** A holder for this clients System line termination separator. */ 073 public final static String SYSTEM_LINE_SEPERATOR = 074 System.getProperty("line.separator"); 075 076 /** The VM classpath (used in some methods).. */ 077 public static String CLASSPATH = System.getProperty("class.path"); 078 079 /** The users home ditrectory. */ 080 public static String USERHOME = System.getProperty("user.home"); 081 082 /** The users pwd ditrectory. */ 083 public static String USERDIR = System.getProperty("user.dir"); 084 085 /** A holder This classes name (used when logging). */ 086 private static String CLASSNAME = "ca.bc.webarts.tools.lednet.LedNetProxy"; 087 088 /** Class flag signifying if the initUtil method has been called */ 089 private static boolean classInit = false; 090 091 /** Class flag signifying if debugging_ messages are ptinted */ 092 private static boolean debugging_ = false; 093 094 /** default receiver IP Address. **/ 095 public static final String DEFAULT_LEDNET_IP = "10.0.0.40"; 096 /** Instantiated class IP for the receiver to communicate with. **/ 097 private String receiverIP_ = DEFAULT_LEDNET_IP; 098 099 /** default LEDNET port. **/ 100 public static final int DEFAULT_LEDNET_PORT = 5577; 101 /** Instantiated class Port for the receiver to communicate with. **/ 102 private int receiverPort_ = DEFAULT_LEDNET_PORT; 103 104 /** the socket for communication - the protocol spec says to use one socket connection AND HOLD ONTO IT for re-use. **/ 105 private static Socket lednetSocket_ = null; 106 /** the timeout in ms for socket reads. **/ 107 private static int socketTimeOut_ = 500; 108 private static ObjectOutputStream out_ = null; 109 private static DataInputStream in_ = null; 110 private static boolean connected_ = false; 111 112 private static StringBuffer helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR); 113 114 private HashMap<Integer, Integer> levels_ = null; 115 private HashMap<Integer, Integer> reverseLevels_ = null; 116 private int levelCount = 0; 117 public enum FadeSpeed 118 { 119 INSTANT (1), //calls constructor with value 1 step 120 VERYFAST (2), //calls constructor with value 2 121 FAST (4), //calls constructor with value 4 122 MEDIUM (8), //calls constructor with value 8 123 SLOW (16), //calls constructor with value 16 124 VERYSLOW (32), //calls constructor with value 32 125 SMOOTH (64), //calls constructor with value 64 126 MOLASSES (128), //calls constructor with value 128 127 BYONES (255) //calls constructor with value 128 128 ; // semicolon needed when fields / methods follow 129 private final int levelSteps; 130 private FadeSpeed(int levelSteps) 131 { 132 this.levelSteps = levelSteps; 133 } 134 public int getLevelSteps() 135 { 136 return this.levelSteps; 137 } 138 } 139 140 141 /** Simple class Constructor (using deafult IP and port) that gets all the class command constants 142 * set-up. 143 **/ 144 public LedNetProxy() 145 { 146 initLevelsMap(); 147 } 148 149 150 /** Constructor that takes your receivers ip and default port, gets all the class command 151 * constants set-up . 152 **/ 153 public LedNetProxy(String ip) 154 { 155 initLevelsMap(); 156 if (ip==null || ip.equals("")) 157 receiverIP_=DEFAULT_LEDNET_IP; 158 else 159 receiverIP_=ip; 160 receiverPort_=DEFAULT_LEDNET_PORT; 161 } 162 163 164 /** Constructor that takes your receivers ip and port, gets all the class command 165 * constants set-up . 166 **/ 167 public LedNetProxy(String ip, int ipPort) 168 { 169 initLevelsMap(); 170 if (ip==null || ip.equals("")) 171 receiverIP_=DEFAULT_LEDNET_IP; 172 else 173 receiverIP_=ip; 174 if (ipPort<1 ) 175 receiverPort_=DEFAULT_LEDNET_PORT; 176 else 177 receiverPort_=ipPort; 178 } 179 180 181 /** Makes Chocolate glazed doughnuts. **/ 182 public void setReceiverIP( String ip) { receiverIP_ = ip;} 183 /** Makes Sprinkle doughnuts. **/ 184 public String getReceiverIP() {return receiverIP_;} 185 /** Makes mini doughnuts. **/ 186 public void setReceiverPort( int port) { receiverPort_ = port;} 187 /** Makes glazed doughnuts. **/ 188 public int getReceiverPort() {return receiverPort_;} 189 190 /** 191 * Connects to the receiver by opening a socket connection through the DEFaULT IP and DEFAULT eISCP port. 192 **/ 193 public boolean connectSocket() { return connectSocket(null, -1);} 194 195 196 /** 197 * Connects to the receiver by opening a socket connection through the DEFAULT LedNet Receiver Port. 198 **/ 199 public boolean connectSocket(String ip) { return connectSocket(ip,-1);} 200 201 202 /** 203 * Connects to the receiver by opening a socket connection through the passed in port (or default LedNet Receiver Port). 204 **/ 205 public boolean connectSocket(String ip, int ipPort) 206 { 207 if (ip==null || ip.equals("")) ip=receiverIP_; 208 if (ipPort<1 ) ipPort=receiverPort_; 209 210 if (lednetSocket_==null || !connected_ || !lednetSocket_.isConnected()) 211 try 212 { 213 //1. creating a socket to connect to the server 214 lednetSocket_ = new Socket(ip, ipPort); 215 System.out.println("Connected to LedNetProxy at "+ip+" on port "+ipPort); 216 //2. get Input and Output streams 217 out_ = new ObjectOutputStream(lednetSocket_.getOutputStream()); 218 in_ = new DataInputStream(lednetSocket_.getInputStream()); 219 220 //System.out.println("out_Init"); 221 out_.flush(); 222 // System.out.println("inInit"); 223 connected_ = true; 224 } 225 catch(UnknownHostException unknownHost) 226 { 227 System.err.println("You are trying to connect to an unknown host!"); 228 } 229 catch(IOException ioException) 230 { 231 System.err.println("Can't Connect: "+ioException.getMessage()); 232 } 233 return connected_; 234 } 235 236 237 /** 238 * Tests the Connection to the receiver by opening a socket connection through the DEFaULT IP and DEFAULT eISCP port. 239 * @return true if already connected or can connect, and false if can't connect 240 **/ 241 public boolean testConnection() { return testConnection(DEFAULT_LEDNET_IP,DEFAULT_LEDNET_PORT);} 242 243 244 /** 245 * Tests the Connection to the receiver by opening a socket connection through the specified IP and DEFAULT eISCP port. 246 * @param ip is the ip address (as a String) of the AV receiver to connect 247 * @return true if already connected or can connect, and false if can't connect 248 **/ 249 public boolean testConnection(String ip) { return testConnection(DEFAULT_LEDNET_IP,DEFAULT_LEDNET_PORT);} 250 251 252 /** 253 * test the connection to the receiver by opening a socket connection AND THEN CLOSES it if it was not already open. 254 * 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 255 * {@link #testConnection(String) testConnection} method (that used the default port) or the {@link #testConnection() testConnection} 256 * method (that used the default IP and port). 257 * 258 * @param ip is the ip address (as a String) of the AV receiver to connect 259 * @param ipPort is the IP Port of the AV receiver to connect with (Onkyo's default is 60128) 260 * @return true if already connected or can connect, and false if can't connect 261 **/ 262 public boolean testConnection(String ip, int ipPort) 263 { 264 boolean retVal = false; 265 if (ip==null || ip.equals("")) ip=DEFAULT_LEDNET_IP; 266 if (ipPort==0 ) ipPort=DEFAULT_LEDNET_PORT; 267 268 if (connected_) 269 { 270 // test existing connection 271 if (lednetSocket_.isConnected()) retVal = true; 272 } 273 else 274 { 275 // test a new connection 276 try 277 { 278 //1. creating a socket to connect to the server 279 lednetSocket_ = new Socket(ip, ipPort); 280 if (lednetSocket_!=null) lednetSocket_.close(); 281 retVal = true; 282 } 283 catch(UnknownHostException unknownHost) 284 { 285 System.err.println("You are trying to connect to an unknown host!"); 286 } 287 catch(IOException ioException) 288 { 289 System.err.println("Can't Connect: "+ioException.getMessage()); 290 } 291 } 292 return retVal; 293 } 294 295 296 /** 297 * Closes the socket connection. 298 * @return true if the closed succesfully 299 **/ 300 public boolean closeSocket() 301 { 302 //4: Closing connection 303 try 304 { 305 boolean acted = false; 306 if (in_!=null) {in_.close();in_=null;acted = true;} 307 if (out_!=null) {out_.close();out_=null;acted = true;} 308 if (lednetSocket_!=null) {lednetSocket_.close();lednetSocket_=null;acted = true;} 309 if (acted) System.out.println("closed connections"); 310 connected_ = false; 311 } 312 catch(IOException ioException) 313 { 314 ioException.printStackTrace(); 315 } 316 return connected_; 317 } 318 319 320 public static String convertAsciiToBase10(String str) {return convertAsciiToBase10( str, false);} 321 public static String convertAsciiToBase10(String str, boolean dumpOut) 322 { 323 char[] chars = str.toCharArray(); 324 StringBuffer base10 = new StringBuffer(); 325 if (dumpOut) System.out.print(" Base10: "); 326 for(int i = 0; i < chars.length; i++) 327 { 328 base10.append( (int)chars[i]); 329 if(i+1<chars.length) base10.append( ";" ); 330 if (dumpOut) System.out.print(" "+((""+(int)chars[i]).length()==1?"0":"")+(int)chars[i] + " "); 331 } 332 if (dumpOut) System.out.println(""); 333 return base10.toString(); 334 } 335 336 337 /** Converts an ascii decimal String to a hex String. 338 * @param str holding the string to convert to HEX 339 * @return a string holding the HEX representation of the passed in decimal str. 340 **/ 341 public static String convertStringToHex(String str) 342 { 343 return convertStringToHex( str, false); 344 } 345 346 347 /** Converts an ascii decimal String to a hex String. 348 * @param str holding the string to convert to HEX 349 * @param dumpOut flag to turn some debug output on/off 350 * @return a string holding the HEX representation of the passed in str. 351 **/ 352 public static String convertStringToHex(String str, boolean dumpOut) 353 { 354 char[] chars = str.toCharArray(); 355 String out_put = ""; 356 357 if (dumpOut) System.out.println(" Ascii: "+str); 358 if (dumpOut) System.out.print(" Hex: "); 359 StringBuffer hex = new StringBuffer(); 360 for(int i = 0; i < chars.length; i++) 361 { 362 out_put = Integer.toHexString((int)chars[i]); 363 if (out_put.length()==1) hex.append("0"); 364 hex.append(out_put); 365 if (dumpOut) System.out.print("0x"+(out_put.length()==1?"0":"")+ out_put+" "); 366 } 367 if (dumpOut) System.out.println(""); 368 if (dumpOut) convertAsciiToBase10(str,dumpOut); 369 /* 370 if (dumpOut) System.out.print(" Base10: "); 371 for(int i = 0; i < chars.length; i++) 372 { 373 System.out.print(" "+convertHexNumberStringToDecimal(chars[i])); 374 } 375 if (dumpOut) System.out.println(""); 376 */ 377 378 return hex.toString(); 379 } 380 381 382 public static final byte[] intToByteArray(int value) 383 { 384 return new byte[] { 385 (byte)(value >>> 24), 386 (byte)(value >>> 16), 387 (byte)(value >>> 8), 388 (byte)value}; 389 } 390 391 /** Converts an HEX number String to its decimal equivalent. 392 * @param str holding the Hex Number string to convert to decimal 393 * @return an int holding the decimal equivalent of the passed in HEX numberStr. 394 **/ 395 public static int convertHexNumberStringToDecimal(String str) 396 { 397 return convertHexNumberStringToDecimal(str, false); 398 } 399 400 401 /** Converts an HEX number String to its decimal equivalent. 402 * @param str holding the Hex Number string to convert to decimal 403 * @param dumpOut boolean flag to turn some debug output on/off 404 * @return an int holding the decimal equivalent of the passed in HEX numberStr. 405 **/ 406 public static int convertHexNumberStringToDecimal(String str, boolean dumpOut) 407 { 408 char[] chars = str.toCharArray(); 409 String out_put = ""; 410 411 if (dumpOut) System.out.println("\n AsciiHex: 0x"+str); 412 if (dumpOut) System.out.print( " Decimal: "); 413 414 StringBuffer hex = new StringBuffer(); 415 String hexInt = new String(); 416 for(int i = 0; i < chars.length; i++) 417 { 418 out_put = Integer.toHexString((int)chars[i]); 419 if (out_put.length()==1) hex.append("0"); 420 hex.append(out_put); 421 if (dumpOut) System.out.print((out_put.length()==1?"0":"")+ out_put); 422 } 423 hexInt = ""+(Integer.parseInt( hex.toString(), 16)); 424 if (dumpOut) System.out.println(""); 425 if (dumpOut) System.out.println( " Decimal: "+hexInt.toString()); 426 427 return Integer.parseInt(hexInt.toString()); 428 429 //return Integer.decode("0x"+str); 430 } 431 432 433 /** Converts a hex byte to an ascii String. 434 * @param hex byte holding the HEX string to convert back to decimal 435 * @return a string holding the HEX representation of the passed in str. 436 **/ 437 public static String convertHexToString(byte hex) 438 { 439 byte [] bytes = {hex}; 440 return convertHexToString( new String(bytes), false); 441 } 442 443 444 /** Converts a hex String to an ascii String. 445 * @param hex the HEX string to convert back to decimal 446 * @return a string holding the HEX representation of the passed in str. 447 **/ 448 public static String convertHexToString(String hex) 449 { 450 return convertHexToString( hex, false); 451 } 452 453 454 /** Converts a hex String to an ascii String. 455 * @param hex the HEX string to convert backk to decimal 456 * @param dumpOut boolean flag to turn some debug output on/off 457 * @return a string holding the HEX representation of the passed in str. 458 **/ 459 public static String convertHexToString(String hex, boolean dumpOut) 460 { 461 462 StringBuilder sb = new StringBuilder(); 463 StringBuilder temp = new StringBuilder(); 464 String out_put = ""; 465 466 if (dumpOut) System.out.print(" Hex: "); 467 //49204c6f7665204a617661 split into two characters 49, 20, 4c... 468 for( int i=0; i<hex.length()-1; i+=2 ){ 469 470 //grab the hex in pairs 471 out_put = hex.substring(i, (i + 2)); 472 if (dumpOut) System.out.print("0x"+out_put+" "); 473 //convert hex to decimal 474 int decimal = Integer.parseInt(out_put, 16); 475 //convert the decimal to character 476 sb.append((char)decimal); 477 478 temp.append(decimal); 479 } 480 if (dumpOut) System.out.println(" Decimal : " + temp.toString()); 481 482 return temp.toString(); 483 } 484 485 486 /** 487 * Wraps a command in a colour data message (data characters). 488 * <br /> 489 * 49, r, g, b, ww, cw, 0, 15<br /> 490 * <span style="color: #FF0000">Red</span>: 49;255;0;0;0;0;0;15;63<br /> 491 * <span style="color: #00FF00">Green</span>: 49;0;255;0;0;0;0;15;63<br /> 492 * <span style="color: #0000FF">Blue</span>: 49;0;0;255;0;0;0;15;63<br /> 493 * <span style="color: #FFFFFF; background: #333333">ColdWhite</span>: 49;0;0;0;0;255;0;15;63 (isy networkResource command = 49;0;0;0;0;255;255;15;62;129;138;139;150)<br /> 494 * <span style="color: #00FFFF">Cyan</span>: 49;0;255;255;0;0;0;15;62;129;138;139;150<br /> 495 *<br /> 496 * The bytes after the 15 (63) are stated as being checksum value of the first eight values and have to change for each code you send.<br /> 497 * Notice how the ON/Off commands use 163, 164? IT would seem the byte after the 15 (packet terminator) is always the sum of the digits from the first until the 15 (inclusive)<br /> 498 * In a normal protocol if the checksum didn't add up correctly the packet would be ignored as noise.<br /> 499 * <br /> Thanks go to the contributors at the <a href="http://forum.universal-devices.com/topic/19913-magic-ufo-controller-for-rgbw" > UDI Forum POST</a> writeup. 500 * 501 * @param rgbw must be one of the 0-255 representing a decimal val for the colour 502 * @return StringBuffer holing the full message packet 503 **/ 504 public StringBuilder getLedNetColourMessage(int r, int g, int b, int w) 505 { 506 String cmdStr = ""; 507 if(r<0)r=0;if(r>255)r=255; 508 if(g<0)g=0;if(g>255)g=255; 509 if(b<0)b=0;if(b>255)b=255; 510 if(w<0)w=0;if(w>255)w=255; 511 512 int chkSum = 0; //49+r+g+b+w+15; //+240; 513 514 StringBuilder sb = new StringBuilder(); 515 516 /* This is where I construct the entire message character by character. */ 517 /* 518 0x31 command of setting color and color temperature 519 Send [0X31] + [8bit red data ] + [8bit green data] + [8bit blue data] + [8bit warm white data] + [8bit cold white data] 520 + [8bit status sign] + [0xF0 remote,0x0F local] + [check digit] (length of command:9) 521 522 Return Local(0x0F):no return 523 Remote(0xF0): [0xF0 remote] + [0X31] + [0x00] + [check digit] 524 Status sign: [0XF0] means changing RGB, [0X0F] means W 525 Note:phone send commands which control static color.Range of static color value is 00-0xff.When value is 0,PWM is 0%;when value is 0XFF,PWM is 100%; 526 527 The ISY msg for 25% BLU = 49; 0;0;64; 0;0; 0; 15; 128;129;138;139;150 528 dido for 100% CW = 49; 0;0;0;0;255;255;15; 62;129;138;139;150 529 */ 530 sb.append((char)Integer.parseInt("31", 16)); //0x31 = 49 531 chkSum += 49; 532 533 // char for R G B wW cW 534 sb.append((char)Integer.parseInt(""+r, 10)); 535 chkSum += Integer.parseInt(""+r, 10); 536 sb.append((char)Integer.parseInt(""+g, 10)); 537 chkSum += Integer.parseInt(""+g, 10); 538 sb.append((char)Integer.parseInt(""+b, 10)); 539 chkSum += Integer.parseInt(""+b, 10); 540 sb.append((char)Integer.parseInt("00", 16));// 1 char for Warm White (mine is not connected) 541 chkSum += Integer.parseInt(""+0, 10); 542 sb.append((char)Integer.parseInt(""+w, 10));// 1 char for Cold White 543 chkSum += Integer.parseInt(""+w, 10); 544 545 //8bit status sign: [0XF0] means RGB, [0X0F] means W, [0xff] means both 546 /* 547 if( (r+g+b)>0 && w==0) 548 sb.append((char)Integer.parseInt("F0", 16)); 549 else if( (r+g+b)==0 && w>0) 550 sb.append((char)Integer.parseInt("0F", 16)); 551 else if( (r+g+b)>0 && w>0) 552 sb.append((char)Integer.parseInt("FF", 16)); 553 else if( (r+g+b)==0 && w==0) 554 sb.append((char)Integer.parseInt("FF", 16)); 555 */ 556 557 if( (r+g+b)>0 && w==0) // [0X00] means RGB 558 { 559 sb.append((char)Integer.parseInt("00", 16)); 560 chkSum += Integer.parseInt("00", 16); 561 } 562 else if( (r+g+b)==0 && w>0) // [0XFF] means W 563 { 564 sb.append((char)Integer.parseInt("FF", 16)); 565 chkSum += Integer.parseInt("FF", 16); 566 } 567 else if( (r+g+b)>0 && w>0) 568 { 569 sb.append((char)Integer.parseInt("00", 16)); 570 chkSum += Integer.parseInt("00", 16); 571 } 572 else if( (r+g+b)==0 && w==0) 573 { 574 sb.append((char)Integer.parseInt("00", 16)); 575 chkSum += Integer.parseInt("00", 16); 576 } 577 578 sb.append((char)Integer.parseInt("0F", 16)); //0xF0 remote WIFI, 0x0F local / direct WIFI (0x0f=15) 579 chkSum += Integer.parseInt("0F", 16); 580 581 // keep the ckecksum below 256 582 if(chkSum>(5*256)) 583 chkSum-=(5*256); 584 else if(chkSum>(4*256)) 585 chkSum-=(4*256); 586 else if(chkSum>(3*256)) 587 chkSum-=(3*256); 588 else if(chkSum>(2*256)) 589 chkSum-=(2*256); 590 else if(chkSum>(256)) 591 chkSum-=(256); 592 593 // 1 char for checkSum 594 sb.append((char)Integer.parseInt(""+chkSum, 10)); 595 596 // msg end 597 sb.append((char)Integer.parseInt(""+129, 10)); 598 sb.append((char)Integer.parseInt(""+138, 10)); 599 sb.append((char)Integer.parseInt(""+139, 10)); 600 sb.append((char)Integer.parseInt(""+150, 10)); 601 602 return sb; 603 } //getLedNetColourMessage 604 605 606 /** 607 * This implements the custom message format - NOT DONE YET. 608 **/ 609 public StringBuilder getCustomMessage(int r, int g, int b, int w, int r2, int g2, int b2, int w2, int speed) 610 { 611 String cmdStr = ""; 612 w=0; w2=0; // ignore for now 613 if(r<0)r=0;if(r>255)r=255; 614 if(g<0)g=0;if(g>255)g=255; 615 if(b<0)b=0;if(b>255)b=255; 616 if(w<0)w=0;if(w>255)w=255; 617 618 int chkSum = Integer.parseInt("51", 16)+ 619 r+g+b+w+r2+g2+b2+w2+ 620 speed+ 621 Integer.parseInt("60", 16)+Integer.parseInt("FF", 16)+Integer.parseInt("0F", 16); 622 623 if(chkSum>(13*256)) 624 chkSum-=(13*256); 625 else if(chkSum>(12*256)) 626 chkSum-=(12*256); 627 else if(chkSum>(11*256)) 628 chkSum-=(11*256); 629 else if(chkSum>(10*256)) 630 chkSum-=(10*256); 631 else if(chkSum>(9*256)) 632 chkSum-=(9*256); 633 else if(chkSum>(8*256)) 634 chkSum-=(8*256); 635 else if(chkSum>(7*256)) 636 chkSum-=(7*256); 637 else if(chkSum>(6*256)) 638 chkSum-=(6*256); 639 else if(chkSum>(5*256)) 640 chkSum-=(5*256); 641 else if(chkSum>(4*256)) 642 chkSum-=(4*256); 643 else if(chkSum>(3*256)) 644 chkSum-=(3*256); 645 else if(chkSum>(2*256)) 646 chkSum-=(2*256); 647 else if(chkSum>(256)) 648 chkSum-=(256); 649 650 StringBuilder sb = new StringBuilder(); 651 String zeroColour5ByteStr = ""+(char)Integer.parseInt("00", 16)+(char)Integer.parseInt("00", 16)+(char)Integer.parseInt("00", 16); 652 int numColours = 0; 653 //int speed = 50; // 0 - 100 654 655 /* This is where I construct the entire message character by character. */ 656 /* 657 0x51 command of setting command of custom mode 658 Send [0X51] + [First point 32bit color value] + [Second point 32bit color value] + [Third point 32bit color value] + 659 [Fourth point 32bit color value] + [Fifth point 32bit color value] + [Sixth point 32bit color value] + 660 [Seventh point 32bit color value] + [Eighth point 32bit color value] + [Ninth point 32bit color value] + 661 [Tenth point 32bit color value] + [Eleventh point 32bit color value] + [Twelfth point 32bit color value] + 662 [Thirteenth point 32bit color value] + [Fourteenth point 32bit color value] + [Fifteenth point 32bit color value] + 663 [Sixteenth point 32bit color value] + [8bit speed value] + [8bit mode value] + 664 [0XFF] + [0xF0 remote,0x0F local] + [check digit] (length of command:55)" 665 666 Return If command is local(0x0F):no return 667 If command is remote (0xF0): [0xF0 remote] + [0X51] + [0x00] + [check digit] 668 669 Note:In command of custom mode,value of RGB cannot be 0x01,0x02,0x03.Otherwise,RGB is over. 670 mode: Custome mode is 0x60 671 672 32bit colour: ARGB values are typically expressed using 8 hexadecimal digits, with each pair of the hexadecimal digits 673 representing the values of the Alpha, Red, Green and Blue channel, respectively. 674 For example, 80FFFF00 represents 50.2% opaque (non-premultiplied) yellow. 675 SEE: https://en.wikipedia.org/wiki/RGBA_color_space#RGBA_hexadecimal_.28word-order.29 676 */ 677 sb.append((char)Integer.parseInt("51", 16)); //0x51 678 // char for R G B wW cW 679 //int first32BitColour = Integer.parseInt(""+r, 10)+Integer.parseInt(""+g, 10)+Integer.parseInt(""+b, 10)+Integer.parseInt(""+w, 10); 680 String first32BitColourHexStr = convertStringToHex(""+r,true)+convertStringToHex(""+g,true)+convertStringToHex(""+b,true)+convertStringToHex(""+w,true); 681 byte [] bytes1 = intToByteArray(Integer.parseInt(first32BitColourHexStr, 16)); 682 if (debugging_) System.out.println("32bit Colour1: "+Arrays.toString(bytes1)); 683 String second32BitColourHexStr = convertStringToHex(""+r2,true)+convertStringToHex(""+g2,true)+convertStringToHex(""+b2,true)+convertStringToHex(""+w2,true); 684 byte [] bytes2 = intToByteArray(Integer.parseInt(second32BitColourHexStr, 16)); 685 if (debugging_) System.out.println("32bit Colour2: "+Arrays.toString(bytes2)); 686 687 for (int i=0;i<bytes1.length;i++) sb.append((char)bytes1[i]); 688 numColours++; 689 690 for (int i=0;i<bytes2.length;i++) sb.append((char)bytes2[i]); 691 numColours++; 692 693 for (int i=0; i< 16-numColours;i++) sb.append(zeroColour5ByteStr); 694 695 sb.append((char)Integer.parseInt(""+speed, 10)); 696 sb.append((char)Integer.parseInt("60", 16)); // mode: custom mode is 0x60 697 698 sb.append((char)Integer.parseInt("FF", 16)); 699 sb.append((char)Integer.parseInt("0F", 16)); //0xF0 remote WIFI, 0x0F local / direct WIFI 700 701 // 1 char for checkSum 702 sb.append((char)Integer.parseInt(""+chkSum, 10)); 703 704 // msg end 705 sb.append((char)Integer.parseInt(""+129, 10)); 706 sb.append((char)Integer.parseInt(""+138, 10)); 707 sb.append((char)Integer.parseInt(""+139, 10)); 708 sb.append((char)Integer.parseInt(""+150, 10)); 709 710 return sb; 711 } //getLedNetColourMessage 712 713 714 /** Override helper method to redirect to getLedNetOnOffMessage true. **/ 715 public StringBuilder getLedNetOnMessage(){ return getLedNetOnOffMessage(true);} 716 /** Override helper method to redirect to getLedNetOnOffMessage false. **/ 717 public StringBuilder getLedNetOffMessage(){ return getLedNetOnOffMessage(false);} 718 719 720 /** 721 * Wraps an On or Off command in a data message (data characters). 722 * <br /> 723 * On: 113;35;15;163;129;138;139;150<br /> 724 * Off: 113;36;15;164;129;138;139;150<br /> 725 *<br /> 726 * The bytes after the 15 (163) are stated as being checksum value of the first eight values and have to change for each code you send.<br /> 727 * Notice how the ON/Off commands use 163, 164? IT would seem the byte after the 15 (packet terminator) is always the sum of the digits from the first until the 15 (inclusive)<br /> 728 * In a normal protocol if the checksum didn't add up correctly the packet would be ignored as noise.<br /> * 729 * @param on must be true to send on command, or false to send OFF command 730 * @return StringBuffer holing the full message packet 731 **/ 732 public StringBuilder getLedNetOnOffMessage(boolean on) 733 { 734 String cmdStr = ""; 735 int chkSum = (on?35:36)+113+15; 736 StringBuilder sb = new StringBuilder(); 737 738 /* This is where I construct the entire message 739 character by character. */ 740 sb.append((char)Integer.parseInt("113", 10)); 741 742 // 1 char for On/Off 743 sb.append((char)Integer.parseInt(""+(on?35:36), 10)); 744 sb.append((char)Integer.parseInt(""+15, 10)); 745 746 // 1 char for checkSum 747 sb.append((char)Integer.parseInt(""+chkSum, 10)); 748 749 // msg end 750 sb.append((char)Integer.parseInt(""+129, 10)); 751 sb.append((char)Integer.parseInt(""+138, 10)); 752 sb.append((char)Integer.parseInt(""+139, 10)); 753 sb.append((char)Integer.parseInt(""+150, 10)); 754 755 return sb; 756 } //getLedNetOnOffMessage 757 758 759 /** Sends the passed in on or off command to LedNet and leaves the socket open. 760 * 761 * @param on true or falso to send On or Off. 762 **/ 763 public String sendOnOffCommand(boolean on){return sendOnOffCommand(on, false);} 764 765 766 /** 767 * Sends to command to the receiver and does not wait for a reply. 768 * 769 * @param on true or falso to send On or Off. 770 * @param closeSocket flag to close the connection when done or leave it open. 771 **/ 772 public String sendOnOffCommand(boolean on, boolean closeSocket) 773 { 774 String retVal = ""; 775 776 StringBuilder sb = getLedNetOnOffMessage(on); 777 if(connectSocket()) 778 { 779 try 780 { 781 if (debugging_) System.out.print(" sending "+sb.length() +" chars: "); 782 //out_.writeObject(sb.toString()); 783 //out_.writeChars(sb.toString()); 784 out_.writeBytes(sb.toString()); // <--- This is the one that works 785 //out_.writeBytes(convertStringToHex(sb.toString(), false)); 786 //out_.writeChars(convertStringToHex(sb.toString(), false)); 787 out_.flush(); 788 if (debugging_) System.out.println((on?" ON ":" OFF ")+"sent!" ); 789 } 790 catch(IOException ioException) 791 { 792 ioException.printStackTrace(); 793 } 794 } 795 if (closeSocket) closeSocket(); 796 797 return retVal; 798 } 799 800 801 /** 802 * Sends to command to the receiver and does not wait for a reply AND leaves the socket open. 803 * 804 * @param rgbw are the colour levels (0-255) 805 **/ 806 public String sendColourCommand(int r, int g, int b, int w){return sendColourCommand(r, g, b, w, false, false);} 807 808 809 /** 810 * Sends to command to the receiver and does not wait for a reply. 811 * 812 * @param rgbw are the colour levels (0-255) 813 * @param closeSocket flag to close the connection when done or leave it open. 814 **/ 815 public String sendColourCommand(int r, int g, int b, int w, boolean waitForResponse, boolean closeSocket) 816 { 817 String retVal = ""; 818 StringBuilder sb = getLedNetColourMessage(r,g,b,w); 819 //StringBuilder sb2 = getLedNetColourMessage(0,128,0,0); 820 if(connectSocket()) 821 { 822 try 823 { 824 if(debugging_)System.out.print(" sending "+sb.toString().getBytes("UNICODE").length +" chars (bytes): "); 825 826 //convertStringToHex(sb.toString(), true); 827 //out_.writeObject(sb.toString()); 828 //out_.writeChars(sb.toString()); 829 830 if(debugging_)System.out.println(sb.toString().getBytes("UNICODE")); 831 out_.writeBytes(sb.toString()); // <--- This is the one that works 832 833 //if(debugging_)System.out.println(convertStringToHex(sb.toString(),false)); 834 //out_.writeBytes(convertStringToHex(sb.toString(), false)); 835 //out_.writeChars(convertStringToHex(sb.toString(), false)); 836 out_.flush(); 837 838 //out_.writeBytes(sb2.toString()); 839 //out_.flush(); 840 841 if(debugging_)System.out.println("sent!" ); 842 if(waitForResponse) 843 { 844 /* now listen for the response. */ 845 Vector <String> rv = null; 846 rv = readQueryResponses(); 847 } 848 } 849 catch(IOException ioException) 850 { 851 ioException.printStackTrace(); 852 } 853 } 854 if (closeSocket) closeSocket(); 855 856 return retVal; 857 } 858 859 860 /** 861 * Sends to command to the receiver and does not wait for a reply AND leaves the socket open. 862 * 863 * @param rgbw are the colour levels (0-255) 864 **/ 865 public void sendCustomCommand(int r, int g, int b, int w, int r2, int g2, int b2, int w2, int speed){sendCustomCommand(r, g, b, w, r2, g2, b2, w2, speed, false);} 866 867 868 /** 869 * Sends to command to the receiver and does not wait for a reply. 870 * 871 * @param rgbw are the colour levels (0-255) 872 * @param closeSocket flag to close the connection when done or leave it open. 873 **/ 874 public void sendCustomCommand(int r, int g, int b, int w, int r2, int g2, int b2, int w2, int speed, boolean closeSocket) 875 { 876 boolean waitForResponse = false; 877 StringBuilder sb = getCustomMessage(r,g,b,w,r2,g2,b2,w2,speed); 878 StringBuilder sb2 = getLedNetColourMessage(0,128,0,0); 879 if(connectSocket()) 880 { 881 try 882 { 883 if(debugging_)System.out.println(" sending "+sb.length() +" chars: "); 884 if(debugging_)System.out.println(convertStringToHex(sb.toString(),true)); 885 //convertStringToHex(sb.toString(), true); 886 //out_.writeObject(sb.toString()); 887 //out_.writeChars(sb.toString()); 888 out_.writeBytes(sb.toString()); // <--- This is the one that works 889 //out_.writeBytes(convertStringToHex(sb.toString(), false)); 890 //out_.writeChars(convertStringToHex(sb.toString(), false)); 891 out_.flush(); 892 893 //out_.writeBytes(sb2.toString()); 894 //out_.flush(); 895 896 if(debugging_)System.out.println("sent!" ); 897 if(waitForResponse) 898 { 899 /* now listen for the response. */ 900 Vector <String> rv = null; 901 rv = readQueryResponses(); 902 } 903 904 } 905 catch(IOException ioException) 906 { 907 ioException.printStackTrace(); 908 } 909 } 910 if (closeSocket) closeSocket(); 911 } 912 913 914 /** A method to wrap a number of colour change calls (just for fun). 915 * 916 * @param loopTime is how long to loop the fun OR -1 to run forever. 917 **/ 918 public void fun(int loopTime){ fun(loopTime,0);} 919 /** A method to wrap a number of colour change calls (just for fun). 920 * 921 * @param loopTime is how long to loop the fun OR -1 to run forever. 922 * @param pause is the delay between colour change calls in the loop 923 **/ 924 public void fun(int loopTime, long pause) 925 { 926 int r = 10; int g = 0; int b = 0; int w = 0; 927 long looping = 0; 928 long msgTime = 505; 929 int count = 0; 930 System.out.println("Fun "+(loopTime!=-1?" for "+loopTime +"ms.":" Indefinately.")); 931 String t1 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 932 int []reds = {15,15, 0, 0, 0, 5}; 933 int []grns = { 0,15,15,15, 0, 0}; 934 int []blus = { 0, 0, 0, 5,15,15}; 935 int []whts = { 0, 0, 0, 0, 0, 0}; 936 while(loopTime==-1||looping<loopTime) 937 { 938 for(int i=0; i< reds.length;i++) 939 { 940 r = reds[i]; g = grns[i]; b = blus[i]; w = whts[i]; 941 sendColourCommand(r,g,b,w); sleep(pause); 942 } 943 944 if(loopTime!=-1) {looping+=6*(pause+msgTime);count++;} 945 } 946 String t2 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 947 double duration = secondsBetween(t1,t2); // in ms 948 System.out.println("duration="+duration); 949 System.out.println("count="+count); 950 System.out.println("msgDuration="+(duration*1000/count/6 - pause) ); 951 } 952 953 954 /** A method to wrap a number of colour change calls (just for fun). 955 * 956 * @param loopTime is how long to loop the fun OR -1 to run forever. 957 **/ 958 public void christmasFun(int loopTime){ fun(loopTime,0);} 959 /** A method to wrap a number of colour change calls (just for fun). 960 * 961 * @param loopTime is how long to loop the fun OR -1 to run forever. 962 * @param pause is the delay between colour change calls in the loop 963 **/ 964 public void christmasFun(int loopTime, long pause) 965 { 966 boolean dim = true; 967 int r = 10; int g = 0; int b = 0; int w = 0; 968 long looping = 0; 969 long msgTime = 505; 970 int count = 0; 971 System.out.println("Xmas Fun "+(loopTime!=-1?" for "+loopTime +"ms.":" Indefinately.")); 972 String t1 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 973 int []reds1 = {60,45,60,30,30,20,15, 8, 8, 8, 8, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 974 int []grns1 = { 0, 0, 0, 0, 0, 0, 1, 2, 4, 8,15,15,15,15,15,20,20,30,30,60,45,60}; 975 int []blus1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 976 int []whts1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 977 978 int []reds2 = { 8, 8, 7, 6, 5, 4, 4, 3, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 979 int []grns2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 8}; 980 int []blus2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 981 int []whts2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 982 983 int []reds = reds1; 984 int []grns = grns1; 985 int []blus = blus1; 986 int []whts = whts1; 987 988 if (dim) 989 { 990 reds = reds2; 991 grns = grns2; 992 blus = blus2; 993 whts = whts2; 994 } 995 996 while(loopTime==-1||looping<loopTime) 997 { 998 for(int i=0; i< reds.length;i++) 999 { 1000 r = reds[i]; g = grns[i]; b = 0; w = 0; 1001 sendColourCommand(r,g,b,w); sleep(pause); 1002 } 1003 for(int i=reds.length-1; i>=0 ;i--) 1004 { 1005 r = reds[i]; g = grns[i]; b = 0; w = 0; 1006 sendColourCommand(r,g,b,w); sleep(pause); 1007 } 1008 1009 if(loopTime!=-1) {looping+=6*(pause+msgTime);count++;} 1010 } 1011 String t2 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 1012 double duration = secondsBetween(t1,t2); // in ms 1013 System.out.println("duration="+duration); 1014 System.out.println("count="+count); 1015 System.out.println("msgDuration="+(duration*1000/count/6 - pause) ); 1016 } 1017 1018 1019 /** A method to wrap a number of colour change calls (just for fun). 1020 * 1021 * @param loopTime is how long to loop the fun OR -1 to run forever. 1022 **/ 1023 public void christmasFade(){ christmasFade(64,-1,0);} 1024 /** A method to wrap a number of colour change calls (just for fun). 1025 * 1026 * @param loopTime is how long to loop the fun OR -1 to run forever. 1027 **/ 1028 public void christmasFade(int loopTime){ christmasFade(64, loopTime,0);} 1029 /** A method to wrap a number of colour change calls (just for fun). 1030 * 1031 * @param loopTime is how long to loop the fun OR -1 to run forever. 1032 * @param pause is the delay between colour change calls in the loop 1033 **/ 1034 public void christmasFade(int toLevel, int loopTime, long pause) 1035 { 1036 long looping = 0; 1037 //int loopTime = -1; 1038 //long pause = 250; 1039 long msgTime = 505; 1040 int count = 0; 1041 1042 // Turn On 1043 sendColourCommand(0,0,0,0); 1044 String queryResponse = sendQueryOnOffCommand(true, false); 1045 1046 // Fade 1047 while(loopTime==-1||looping<loopTime) 1048 { 1049 1050 fadeBetweenCommand( 0,1,0,0, 0,toLevel,0,0 , FadeSpeed.SLOW); // green 1051 fadeBetweenCommand( 0,toLevel,0,0, 0,2,0,0, FadeSpeed.SLOW); // dim the green 1052 fadeBetweenCommand( 0,2,0,0, 2,2,0,0, FadeSpeed.SLOW); // red 1053 fadeBetweenCommand( 2,2,0,0, toLevel,0,0,0, FadeSpeed.SLOW); // red 1054 sleep(1000); 1055 sendColourCommand(4,0,0,0); 1056 sleep(250); 1057 sendColourCommand(toLevel,0,0,0); 1058 sleep(250); 1059 sendColourCommand(4,0,0,0); 1060 sleep(250); 1061 //sendColourCommand(toLevel,0,0,0); 1062 fadeBetweenCommand( toLevel,0,0,0 ,2,2,0,0, FadeSpeed.SLOW); // dim the red 1063 fadeBetweenCommand( 2,2,0,0, 0,2,0,0, FadeSpeed.SLOW); // green 1064 sleep(1000); 1065 sendColourCommand(0,4,0,0); 1066 sleep(250); 1067 sendColourCommand(0,toLevel,0,0); 1068 sleep(250); 1069 sendColourCommand(0,4,0,0); 1070 sleep(250); 1071 if(loopTime!=-1) {looping+=6*(pause+msgTime);count++;} 1072 } 1073 1074 //Turn OFF 1075 sendQueryOnOffCommand(false, true); 1076 } 1077 1078 1079 public void slowBurn(int toLevel, int loopTime, long pause) 1080 { 1081 long looping = 0; 1082 //int loopTime = -1; 1083 //long pause = 250; 1084 long msgTime = 505; 1085 int count = 0; 1086 1087 // Turn On 1088 sendColourCommand(0,0,0,0); 1089 String queryResponse = sendQueryOnOffCommand(true, false); 1090 1091 // Fade 1092 boolean waitDelay = true; 1093 int waitDelayMs = 750; 1094 while(loopTime==-1||looping<loopTime) 1095 { 1096 //fadeBetweenCommand(int r, int g, int b, int w, int r2, int g2, int b2, int w2, FadeSpeed speed, boolean nonLinear) 1097 sendColourCommand( 6,0,0,0, waitDelay, false);sleep(waitDelayMs); 1098 sendColourCommand( 6,0,0,0, waitDelay, false);sleep(waitDelayMs); 1099 sendColourCommand( 5,0,1,0, waitDelay, false);sleep(waitDelayMs); 1100 sendColourCommand( 5,0,1,0, waitDelay, false);sleep(waitDelayMs); 1101 sendColourCommand( 4,0,2,0, waitDelay, false);sleep(waitDelayMs); 1102 sendColourCommand( 3,0,3,0, waitDelay, false);sleep(waitDelayMs); 1103 sendColourCommand( 2,0,4,0, waitDelay, false);sleep(waitDelayMs); 1104 sendColourCommand( 2,0,5,0, waitDelay, false);sleep(waitDelayMs); 1105 sendColourCommand( 2,0,5,0, waitDelay, false);sleep(waitDelayMs); 1106 sendColourCommand( 2,0,6,0, waitDelay, false);sleep(waitDelayMs); 1107 sendColourCommand( 1,0,6,0, waitDelay, false);sleep(waitDelayMs); 1108 sendColourCommand( 1,0,7,0, waitDelay, false);sleep(waitDelayMs); 1109 sendColourCommand( 1,0,7,0, waitDelay, false);sleep(waitDelayMs); 1110 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1111 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1112 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1113 //sendColourCommand( 0,0,10,0, waitDelay, false);sleep(waitDelayMs); 1114 //sendColourCommand( 0,0,10,0, waitDelay, false);sleep(waitDelayMs); 1115 //sendColourCommand( 0,0,11,0, waitDelay, false);sleep(waitDelayMs); 1116 //sendColourCommand( 0,0,11,0, waitDelay, false);sleep(waitDelayMs); 1117 //sendColourCommand( 0,0,12,0, waitDelay, false);sleep(waitDelayMs); 1118 //sendColourCommand( 0,0,12,0, waitDelay, false);sleep(waitDelayMs); 1119 sleep(1500); 1120 //sendColourCommand( 0,0,11,0, waitDelay, false);sleep(waitDelayMs); 1121 //sendColourCommand( 0,0,11,0, waitDelay, false);sleep(waitDelayMs); 1122 //sendColourCommand( 0,0,10,0, waitDelay, false);sleep(waitDelayMs); 1123 //sendColourCommand( 0,0,10,0, waitDelay, false);sleep(waitDelayMs); 1124 //sendColourCommand( 0,0,9,0, waitDelay, false);sleep(waitDelayMs); 1125 //sendColourCommand( 0,0,9,0, waitDelay, false);sleep(waitDelayMs); 1126 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1127 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1128 sendColourCommand( 0,0,7,0, waitDelay, false);sleep(waitDelayMs); 1129 sendColourCommand( 1,0,7,0, waitDelay, false);sleep(waitDelayMs); 1130 sendColourCommand( 1,0,7,0, waitDelay, false);sleep(waitDelayMs); 1131 sendColourCommand( 2,0,7,0, waitDelay, false);sleep(waitDelayMs); 1132 sendColourCommand( 2,0,6,0, waitDelay, false);sleep(waitDelayMs); 1133 sendColourCommand( 3,0,6,0, waitDelay, false);sleep(waitDelayMs); 1134 sendColourCommand( 3,0,5,0, waitDelay, false);sleep(waitDelayMs); 1135 sendColourCommand( 4,0,5,0, waitDelay, false);sleep(waitDelayMs); 1136 sendColourCommand( 4,0,4,0, waitDelay, false);sleep(waitDelayMs); 1137 sendColourCommand( 4,0,3,0, waitDelay, false);sleep(waitDelayMs); 1138 sendColourCommand( 4,0,2,0, waitDelay, false);sleep(waitDelayMs); 1139 sendColourCommand( 4,0,1,0, waitDelay, false);sleep(waitDelayMs); 1140 sendColourCommand( 4,0,1,0, waitDelay, false);sleep(waitDelayMs); 1141 sendColourCommand( 4,0,0,0, waitDelay, false);sleep(waitDelayMs); 1142 sendColourCommand( 4,0,0,0, waitDelay, false);sleep(waitDelayMs); 1143 sleep(1500); 1144 if(loopTime!=-1) {looping+=6*(pause+msgTime);count++;} 1145 } 1146 1147 //Turn OFF 1148 sendQueryOnOffCommand(false, true); 1149 } 1150 1151 1152 /** 1153 * linear Steps the rgbw between the passed values to provide a fade. It will NOT turn the LedNet ON if not already on. 1154 * 1155 * @param r starting red value 1156 * @param r2 ending red value 1157 **/ 1158 public void stepBetween(int r, int g, int b, int w, int r2, int g2, int b2, int w2) 1159 { 1160 int maxD = 0; 1161 int rD = r2-r; 1162 if(java.lang.Math.abs(rD)>maxD) maxD=java.lang.Math.abs(rD); 1163 int gD = g2-g; 1164 if(java.lang.Math.abs(gD)>maxD) maxD=java.lang.Math.abs(gD); 1165 int bD = b2-b; 1166 if(java.lang.Math.abs(bD)>maxD) maxD=java.lang.Math.abs(bD); 1167 int wD = w2-w; 1168 if(java.lang.Math.abs(wD)>maxD) maxD=java.lang.Math.abs(wD); 1169 if(debugging_)System.out.println("\nStepping\n rD="+rD+" gD="+gD+" bD="+bD+" wD="+wD+" maxD="+maxD); 1170 int steps = maxD; 1171 double stepsd = steps; 1172 if(debugging_)System.out.println("Stepping "+maxD+" times: r "+r+"-->"+r2+" g "+g+"-->"+g2+" b "+b+"-->"+b2+" w "+w+"-->"+w2); 1173 1174 int nextR = r; 1175 int nextG = g; 1176 int nextB = b; 1177 int nextW = w; 1178 int rStepSize = (rD>0?1:(rD<0?-1:0)); 1179 int gStepSize = (gD>0?1:(gD<0?-1:0)); 1180 int bStepSize = (bD>0?1:(bD<0?-1:0)); 1181 int wStepSize = (wD>0?1:(wD<0?-1:0)); 1182 int rSteps = 0; 1183 int gSteps = 0; 1184 int bSteps = 0; 1185 int wSteps = 0; 1186 int rStepCount = 0; 1187 int gStepCount = 0; 1188 int bStepCount = 0; 1189 int wStepCount = 0; 1190 1191 if(rD!=0) rSteps = dToi(maxD / rD); 1192 if(gD!=0) gSteps = dToi(maxD / gD); 1193 if(bD!=0) bSteps = dToi(maxD / bD); 1194 if(wD!=0) wSteps = dToi(maxD / wD); 1195 if(debugging_)System.out.println("Stepping "+maxD+" times: red "+rSteps+" green "+gSteps+" blue "+bSteps+" w "+wSteps); 1196 1197 1198 int i=0; 1199 for (i=0; i< steps; i++) 1200 { 1201 if(rStepCount == java.lang.Math.abs(rSteps)) 1202 { 1203 nextR += rStepSize; 1204 rStepCount = 1; 1205 } 1206 else 1207 { 1208 rStepCount++; 1209 } 1210 if(gStepCount == java.lang.Math.abs(gSteps)) 1211 { 1212 nextG += gStepSize; 1213 gStepCount = 1; 1214 } 1215 else 1216 { 1217 gStepCount++; 1218 } 1219 if(bStepCount == java.lang.Math.abs(bSteps)) 1220 { 1221 nextB += bStepSize; 1222 bStepCount = 1; 1223 } 1224 else 1225 { 1226 bStepCount++; 1227 } 1228 if(wStepCount == java.lang.Math.abs(wSteps)) 1229 { 1230 nextW += wStepSize; 1231 wStepCount = 1; 1232 } 1233 else 1234 { 1235 wStepCount++; 1236 } 1237 1238 if(debugging_) System.out.println(""+i+"/"+steps+" ] nextR="+nextR+" nextG="+nextG+" nextB="+nextB+" nextW="+nextW); 1239 sendColourCommand(nextR, nextG, nextB, nextW); 1240 } 1241 // One Last Step 1242 nextR += rStepSize; 1243 nextG += gStepSize; 1244 nextB += bStepSize; 1245 nextW += wStepSize; 1246 if(debugging_) System.out.println(""+i+"/"+steps+" ] nextR="+nextR+" nextG="+nextG+" nextB="+nextB+" nextW="+nextW); 1247 sendColourCommand(nextR, nextG, nextB, nextW); 1248 } 1249 1250 1251 /** 1252 * Steps the non-linear LedLevel rgbw between the passed values to provide a fade. It will also turn the LedNet ON if not already on. 1253 * 1254 * @param nonLinear boolean flag to choose between linear or default non-linear level lookup. 1255 **/ 1256 public void fadeBetweenCommand(int r, int g, int b, int w, int r2, int g2, int b2, int w2, FadeSpeed speed) 1257 { 1258 fadeBetweenCommand(r, g, b, w, r2, g2, b2, w2, speed, true); 1259 } 1260 1261 1262 /** 1263 * Steps the rgbw (linear or non-linear LedLevel ) between the passed values to provide a fade. It will also turn the LedNet ON if not already on. 1264 * 1265 * @param nonLinear boolean flag to choose between linear or default non-linear level lookup. 1266 **/ 1267 public void fadeBetweenCommand(int r, int g, int b, int w, int r2, int g2, int b2, int w2, FadeSpeed speed, boolean nonLinear) 1268 { 1269 boolean dryRun = false; 1270 int stepMultiple = 1; 1271 int fadeSteps = speed.getLevelSteps(); 1272 double fadeStepsd = fadeSteps; 1273 double stepMultipled = stepMultiple; 1274 1275 if(debugging_)System.out.println((nonLinear?"NON-linear ":"")+"Fading "+fadeSteps+": r "+r+"-->"+r2+" g "+g+"-->"+g2+" b "+b+"-->"+b2+" w "+w+"-->"+w2); 1276 int rD = r2-r; 1277 int gD = g2-g; 1278 int bD = b2-b; 1279 int wD = w2-w; 1280 if(debugging_)System.out.println(" rD="+rD+" gD="+gD+" bD="+bD+" wD="+wD); 1281 1282 int rlD = levelsDiff(r,r2, nonLinear); // returns the abs diff between the ledLevels for r and r2 1283 int glD = levelsDiff(g,g2, nonLinear); 1284 int blD = levelsDiff(b,b2, nonLinear); 1285 int wlD = levelsDiff(w,w2, nonLinear); 1286 double rlDd = rlD; 1287 double glDd = glD; 1288 double blDd = blD; 1289 double wlDd = wlD; 1290 1291 int maxLevelDiff = Math.max(Math.max(Math.max(rlD,glD),blD),wlD); 1292 1293 int maxLevelStep = (int) Math.round((double)(maxLevelDiff/fadeSteps)); 1294 1295 if(debugging_) 1296 { 1297 System.out.println("FadingLevelSteps "+fadeSteps+": r "+r+"/"+ledLevel(r, nonLinear)+"-->"+ledLevel(r2, nonLinear)+ 1298 " g "+g+"/"+ledLevel(g, nonLinear)+"-->"+ledLevel(g2, nonLinear)+" b "+b+"/"+ledLevel(b, nonLinear)+"-->"+ledLevel(b2, nonLinear)+" w "+w+"/"+ledLevel(w, nonLinear)+"-->"+ledLevel(w2, nonLinear)); 1299 System.out.println(" LevelDIFFs rlD="+rlD+" glD="+glD+" blD="+blD+" wlD="+wlD); 1300 System.out.println(" maxLevelDiff="+maxLevelDiff); 1301 } 1302 1303 if(fadeSteps>maxLevelDiff) fadeSteps=maxLevelDiff; 1304 int levelStepSize = fadeSteps; 1305 1306 //if(stepTime < fastestStep) stepTime = fastestStep; 1307 1308 int rlStep = (rD<0?-1:1)*(rlD==0?0:rlD/fadeSteps)*stepMultiple; // these are in ledLevels 1309 int glStep = (gD<0?-1:1)*(glD==0?0:glD/fadeSteps)*stepMultiple; 1310 int blStep = (bD<0?-1:1)*(blD==0?0:blD/fadeSteps)*stepMultiple; 1311 int wlStep = (wD<0?-1:1)*(wlD==0?0:wlD/fadeSteps)*stepMultiple; 1312 double rlStepd = (rD<0?-1:1)*(rlD==0?0:rlDd/fadeStepsd)*stepMultipled; // these are in ledLevels 1313 double glStepd = (gD<0?-1:1)*(glD==0?0:glDd/fadeStepsd)*stepMultipled; 1314 double blStepd = (bD<0?-1:1)*(blD==0?0:blDd/fadeStepsd)*stepMultipled; 1315 double wlStepd = (wD<0?-1:1)*(wlD==0?0:wlDd/fadeStepsd)*stepMultipled; 1316 1317 DoubleAdder currRleveld = new DoubleAdder(); 1318 DoubleAdder currGleveld = new DoubleAdder(); 1319 DoubleAdder currBleveld = new DoubleAdder(); 1320 DoubleAdder currWleveld = new DoubleAdder(); 1321 1322 int currRlevel=ledLevel(r, nonLinear); 1323 currRleveld.add(Double.parseDouble(""+currRlevel)); 1324 int currGlevel=ledLevel(g, nonLinear); 1325 currGleveld.add(Double.parseDouble(""+currGlevel)); 1326 int currBlevel=ledLevel(b, nonLinear); 1327 currBleveld.add(Double.parseDouble(""+currBlevel)); 1328 int currWlevel=ledLevel(w, nonLinear); 1329 currWleveld.add(Double.parseDouble(""+currWlevel)); 1330 int prevRlevel=currRlevel; 1331 int prevGlevel=currGlevel; 1332 int prevBlevel=currBlevel; 1333 int prevWlevel=currWlevel; 1334 if(debugging_) 1335 { 1336 System.out.println("testFading : rlStep="+rlStep+" glStep="+glStep+" blStep="+blStep+" wlStep="+wlStep); 1337 System.out.println("testFading : rlStepd="+rlStepd+" glStepd="+glStepd+" blStepd="+blStepd+" wlStepd="+wlStepd); 1338 System.out.println("num steps : fadeSteps="+fadeSteps); 1339 } 1340 String t1 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 1341 if(!dryRun) 1342 { 1343 //sendColourCommand(r,g,b,w); 1344 //sleep(100); 1345 } 1346 String t2 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 1347 for(int i=0; i<= fadeSteps; i++) 1348 { 1349 /*System.out.println("i:"+i+" rLevel="+currRlevel+ 1350 " gLevel="+currGlevel+ 1351 " bLevel="+currBlevel+ 1352 " wLevel="+currWlevel 1353 );*/ 1354 if(debugging_) 1355 { 1356 System.out.println("i:"+i+" rLevelda="+daToi(currRleveld)+ 1357 " gLevelda="+daToi(currGleveld)+ 1358 " bLevelda="+daToi(currBleveld)+ 1359 " wLevelda="+daToi(currWleveld) 1360 ); 1361 } 1362 1363 if(!dryRun) 1364 { 1365 boolean oldDebug = debugging_; 1366 debugging_=false; 1367 //sendOnOffCommand(true,false); 1368 //sendColourCommand(currRlevel,currGlevel,currBlevel,currWlevel); // these are already ledLevel'd 1369 sendColourCommand(daToi(currRleveld),daToi(currGleveld),daToi(currBleveld),daToi(currWleveld)); // these are already ledLevel'd 1370 debugging_=oldDebug; 1371 //sleep(100); 1372 } 1373 prevRlevel=currRlevel; 1374 prevGlevel=currGlevel; 1375 prevBlevel=currBlevel; 1376 prevWlevel=currWlevel; 1377 currRlevel+=rlStep;currGlevel+=glStep;currBlevel+=blStep;currWlevel+=wlStep; 1378 currRleveld.add(rlStepd);currGleveld.add(glStepd);currBleveld.add(blStepd);currWleveld.add(wlStepd); 1379 } 1380 String t3 = ca.bc.webarts.widgets.Util.createCurrentTimeStamp(); 1381 if(!debugging_) 1382 { 1383 System.out.println("t1= "+t1); 1384 System.out.println("t2= "+t2); 1385 System.out.println("t3= "+t3); 1386 } 1387 } 1388 1389 1390 /** 1391 * Function to accepts a double and returns an int primitive. Could also get implemented as a java 8 java.util.function.DoubleToIntFunction 1392 **/ 1393 private int dToi(double d) { return (new Double(d)).intValue();} 1394 1395 1396 /** 1397 * Function to accepts a java 8 doubleAdder and returns an int primitive. 1398 **/ 1399 private int daToi(DoubleAdder d) { return (new Double(d.sum())).intValue();} 1400 1401 1402 public String right(String value, int length) 1403 { 1404 // To get right characters from a string, change the begin index. 1405 return value.substring(value.length() - length); 1406 } 1407 1408 1409 /** 1410 * Calculates the seconds between the 2 passed timeStamps. 1411 **/ 1412 public double secondsBetween(String t1,String t2) 1413 { 1414 /* 1415 System.out.println("t1= "+t1); 1416 System.out.println("t2= "+t2); 1417 System.out.println("tm1= "+t1.substring((t1.length() - (t1.startsWith("0")?8:9)), 5)); 1418 System.out.println("tm2= "+t2.substring((t2.length() - (t2.startsWith("0")?8:9)), 5)); 1419 System.out.println("add60= "+!t2.substring((t2.length() - (t2.startsWith("0")?8:9)), 5).equals(t1.substring((t1.length() - (t1.startsWith("0")?8:9)), 5))); 1420 */ 1421 double add60 = 0d; 1422 double mins = Double.parseDouble(t2.substring((t2.length() - (t2.startsWith("0")?8:9)), 5)) - Double.parseDouble(t1.substring((t1.length() - (t1.startsWith("0")?8:9)), 5)); 1423 if(!t2.substring((t2.length() - (t2.startsWith("0")?8:9)), 5).equals(t1.substring((t1.length() - (t1.startsWith("0")?8:9)), 5))) add60 = 60d; 1424 //System.out.println("t2.length()= "+t2.length()); 1425 //System.out.println("seconds= "+t2.substring((t2.length() - (t2.startsWith("0")?5:6)), 8)+"."+right(t2,3)); 1426 return Double.parseDouble(t2.substring((t2.length() - (t2.startsWith("0")?5:6)), 8)+"."+right(t2,3))+ mins*add60 - 1427 Double.parseDouble(t1.substring((t1.length() - (t1.startsWith("0")?5:6)), 8)+"."+right(t1,3)); 1428 } 1429 1430 1431 /** 1432 * LED Level lookup from the <b>non-linear</b> hashmap setup in {@link #initLevelsMap() initLevelsMap}. 1433 * 1434 * @param v is the (0-255) level to lookup the non-linear level lookup. 1435 **/ 1436 private int ledLevel(int v) { return ledLevel(v, true);} 1437 1438 1439 /** 1440 * LED Level lookup from the linear or non-linear hashmap setup in {@link #initLevelsMap() initLevelsMap}. 1441 * 1442 * @param v is the (0-255) level to lookup the non-linear level lookup. 1443 * @param nonLinear boolean flag to choose between linear or default non-linear level lookup from {@link #HashMap levels_} map. 1444 **/ 1445 private int ledLevel(int v, boolean nonLinear) 1446 { 1447 int retVal = levels_.get(Integer.valueOf(v)).intValue(); // start with the default map lookup 1448 if(v<0)v=0;if(v>255)v=255; 1449 1450 boolean direct = false; 1451 boolean lookup = false; 1452 boolean useExponential = true; 1453 //(1+EXP(((A2/21)-6)*-1))*255 1454 //int form = Math.round( (int)(1/((1+Math.exp(((v/21)-6)*-1))*255))); 1455 1456 //System.out.println("v="+v+" "+levels_.get(Integer.valueOf(v)).intValue()); 1457 //System.out.println("v="+v+" ExpLevel="+1/((1+Math.exp(((v/21)-6)*-1))*255)); 1458 if (direct) retVal = v; 1459 else if (useExponential) retVal = expLedLevel(v); 1460 1461 //System.out.println("v="+v+" "+(useExponential?" ExponLevel=":"")+retVal); 1462 return retVal; 1463 } 1464 1465 1466 /** 1467 * LED Level lookup from an exponential formula. 1468 * 1469 * @param v is the (0-255) level to lookup the non-linear level lookup. 1470 **/ 1471 private int expLedLevel(int v) 1472 { 1473 double vd = (double) v; 1474 if(vd<0.0)vd=0.0;if(vd>255.0)vd=255.0; 1475 //double retVal = (1/(1+Math.exp(vd*-1))*255); 1476 int retVal = (int) Math.round( 1/(1+Math.exp((((vd)/21)-6)*-1))*255+0.5); 1477 if(v==0) retVal = 0; 1478 return retVal; 1479 } 1480 1481 1482 /** 1483 * The difference between the LED Level lookup from the non-linear hashmap setup in {@link #initLevelsMap() initLevelsMap}. 1484 * 1485 * @param l1 is the (0-255) level to lookup the non-linear level lookup. 1486 * @param l2 is the (0-255) level to lookup the non-linear level lookup. 1487 **/ 1488 private int levelsDiff(int l1, int l2) {return levelsDiff(l1,l2,true);} 1489 /** 1490 * The difference between the LED Level lookup from the linear or non-linear hashmap setup in {@link #initLevelsMap() initLevelsMap}. 1491 * 1492 * @param l1 is the (0-255) level to lookup the non-linear level lookup. 1493 * @param l2 is the (0-255) level to lookup the non-linear level lookup. 1494 * @param nonLinear boolean flag to choose between linear or default non-linear level lookup. 1495 **/ 1496 private int levelsDiff(int l1, int l2, boolean nonLinear) 1497 { 1498 int levelDiff = l1-l2; 1499 //System.err.println("Diffing: l1="+l1+" l2="+l2); 1500 //System.err.println("Diffing: ledLevel(l1)="+ledLevel(l1)+" ledLevel(l2)="+ledLevel(l2)); 1501 try 1502 { 1503 if (nonLinear) 1504 levelDiff = Math.abs(ledLevel(l1)-ledLevel(l2)); 1505 else 1506 levelDiff = Math.abs(levelDiff); 1507 } 1508 catch (java.lang.NullPointerException npe) 1509 { 1510 System.err.println("ERROR: levelsDiff l1="+l1+" l2="+l2); 1511 npe.printStackTrace(); 1512 } 1513 return levelDiff; 1514 } 1515 1516 1517 /** 1518 * Set Method for class field 'levelCount'. 1519 * 1520 * @param levelCount is the value to set this class field to. 1521 * 1522 **/ 1523 public void setLevelCount(int levelCount) 1524 { 1525 this.levelCount = levelCount; 1526 } // setLevelCount Method 1527 1528 1529 /** 1530 * Get Method for class field 'levelCount'. 1531 * 1532 * @return int - The value the class field 'levelCount'. 1533 * 1534 **/ 1535 public int getLevelCount() 1536 { 1537 return levelCount; 1538 } // getLevelCount Method 1539 1540 1541 /** 1542 * Lookup the linear value from the non-linear hashmap setup in {@link #initLevelsMap() initLevelsMap}. 1543 * 1544 * @param v is the non-level value to lookup the linear level . 1545 **/ 1546 private int reverseLedLevel(int v) 1547 { 1548 if(v<0){v=0;} 1549 else if(v>255){v=255;} 1550 Integer ii = Integer.valueOf(v); 1551 if(debugging_) System.out.println("ii="+ii); 1552 Integer iii = reverseLevels_.get(ii); 1553 if(debugging_) System.out.println("iii="+iii); 1554 return (iii!=null?iii.intValue():-1); 1555 } 1556 1557 1558 /** 1559 * Sends to command to the receiver and then waits for the response(s). The responses often have nothing to do with the command sent 1560 * so this method can filter them to return only the responses related to the command sent. 1561 * 1562 * @param command must be one of the Command Class Constants from the eiscp.Eiscp.Command class. 1563 * @param closeSocket flag to close the connection when done or leave it open. 1564 * @param returnAll flags if all response packetMessages are returned, if no then ONLY the ones related to the command requested 1565 * @return the response to the command 1566 **/ 1567 public String sendQueryOnOffCommand(boolean on, boolean closeSocket) 1568 { 1569 String retVal = ""; 1570 1571 /* Send The Command and then... */ 1572 sendOnOffCommand(on,false); 1573 //sleep(50); // docs say so 1574 1575 /* now listen for the response. */ 1576 Vector <String> rv = null; 1577 rv = readQueryResponses(); 1578 String currResponse = ""; 1579 for (int i=0; i < rv.size(); i++) 1580 { 1581 currResponse = (String) rv.elementAt(i); 1582 retVal+= currResponse+"\n"; 1583 } 1584 1585 if (closeSocket) closeSocket(); 1586 1587 return retVal ; 1588 } 1589 1590 1591 /** 1592 * This method reads responses (possibly more than one) after a command. 1593 * @return an array of the data portion of the response messages only - There might be more than one response message received. 1594 **/ 1595 public Vector <String> readQueryResponses() 1596 { 1597 //boolean debugging = debugging_; 1598 boolean foundCommand = false; 1599 Vector <String> retVal = new Vector <String> (); 1600 byte [] responseBytes = new byte[32] ; 1601 String currResponse = ""; 1602 int numBytesReceived = 0; 1603 int totBytesReceived = 0; 1604 int i=0; 1605 int packetCounter=0; 1606 int headerSizeDecimal = 0; 1607 int dataSizeDecimal = 0; 1608 char endChar1 ='!';// NR-5008 response sends 3 chars to terminate the packet - 0x1a 0x0d 0x0a 1609 char endChar2 ='!'; 1610 char endChar3 ='!'; 1611 1612 if(connected_) 1613 { 1614 try 1615 { 1616 if (debugging_) System.out.println("\nReading Response Packet"); 1617 lednetSocket_.setSoTimeout(socketTimeOut_); // this must be set or the following read will BLOCK / hang the method when the messages are done 1618 1619 while(!foundCommand && ((numBytesReceived = in_.read(responseBytes))>0) ) 1620 { 1621 totBytesReceived = 0; 1622 StringBuilder msgBuffer = new StringBuilder(""); 1623 if (debugging_) System.out.println("\n*\n*\n*\n*Buffering bytes: "+numBytesReceived); 1624 if (debugging_) System.out.print( " Packet"+"["+packetCounter+"]:"); 1625 1626 /* Read ALL the incoming Bytes and buffer them */ 1627 // ******************************************* 1628 while(numBytesReceived>0 ) 1629 { 1630 totBytesReceived+=numBytesReceived; 1631 msgBuffer.append(new String(responseBytes)); 1632 responseBytes = new byte[32]; 1633 numBytesReceived = 0; 1634 if (in_.available()>0) 1635 numBytesReceived = in_.read(responseBytes); 1636 if (debugging_) System.out.print(" "+numBytesReceived); 1637 } 1638 if (debugging_) System.out.println(); 1639 convertStringToHex(msgBuffer.toString(), debugging_); 1640 1641 /* Response is done... process it into dataMessages */ 1642 // ******************************************* 1643 char [] responseChars = msgBuffer.toString().toCharArray(); // use the charArray to step through 1644 msgBuffer = null;// clear for garbageCollection 1645 1646 if (debugging_) System.out.println("responseChars.length="+responseChars.length); 1647 int responseByteCnt = 0; 1648 char [] headerSizeBytes = new char[4]; 1649 char [] dataSizeBytes = new char[4]; 1650 char [] dataMessage = null ; //init dynamically 1651 int dataByteCnt = 0; 1652 String dataMsgStr = ""; 1653 1654 if(debugging_ && msgBuffer!=null) System.out.println("Message Received: "+msgBuffer.toString()); 1655 // loop through all the chars and split out the dataMessages 1656 //while (!foundCommand && (responseByteCnt< totBytesReceived)) 1657 //{ 1658 // read Header 1659 // 1st 4 chars are the leadIn 1660 // responseByteCnt+=4; 1661 1662 // read headerSize 1663 //headerSizeBytes[0]=responseChars[responseByteCnt++]; 1664 // headerSizeBytes[1]=responseChars[responseByteCnt++]; 1665 // headerSizeBytes[2]=responseChars[responseByteCnt++]; 1666 // headerSizeBytes[3]=responseChars[responseByteCnt++]; 1667 1668 //packetCounter++; 1669 //}// done packet 1670 1671 } // check for more data 1672 1673 } 1674 catch( java.net.SocketTimeoutException noMoreDataException) 1675 { 1676 if (debugging_) System.out.println("Response Done: " ); 1677 } 1678 catch(EOFException eofException) 1679 { 1680 System.out.println("received: \""+retVal+"\"" ); 1681 } 1682 catch(IOException ioException) 1683 { 1684 ioException.printStackTrace(); 1685 } 1686 } 1687 else 1688 System.out.println("!!Not Connected to Receive "); 1689 return retVal; 1690 } 1691 1692 1693 /** 1694 * A method to simply abstract the Try/Catch required to put the current 1695 * thread to sleep for the specified time in ms. 1696 * 1697 * @param waitTime the sleep time in milli seconds (ms). 1698 * @return boolean value specifying if the sleep completed (true) or was interupted (false). 1699 */ 1700 public boolean sleep(long waitTime) 1701 { 1702 boolean retVal = true; 1703 /* 1704 * BLOCK for the spec'd time 1705 */ 1706 if(waitTime>0) 1707 try 1708 { 1709 Thread.sleep(waitTime); 1710 } 1711 catch (InterruptedException iex) 1712 { 1713 retVal = false; 1714 } 1715 return retVal; 1716 } 1717 1718 1719 /** gets the help as a String. 1720 * @return the helpMsg in String form 1721 **/ 1722 private static String getHelpMsgStr() {return getHelpMsg().toString();} 1723 1724 1725 /** initializes and gets the helpMsg_ 1726 class var. 1727 * @return the class var helpMsg_ 1728 **/ 1729 private static StringBuffer getHelpMsg() 1730 { 1731 helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR); 1732 helpMsg_.append("--- WebARTS LedNetProxy Class -----------------------------------------------------"); 1733 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1734 helpMsg_.append("--- $Revision: 1302 $ $Date: 2019-11-03 17:19:03 -0800 (Sun, 03 Nov 2019) $ ---"); 1735 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1736 helpMsg_.append("-------------------------------------------------------------------------------"); 1737 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1738 helpMsg_.append("WebARTS LedNetProxy Class"); 1739 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1740 helpMsg_.append("SYNTAX:"); 1741 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1742 helpMsg_.append(" java "); 1743 helpMsg_.append(CLASSNAME); 1744 helpMsg_.append(" [hostIP:port] command [commandArgs]"); 1745 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1746 helpMsg_.append(" - hostIP:port is optional and defaults to 10.0.0.247:5577"); 1747 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1748 helpMsg_.append(" - command is NOT optional"); 1749 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1750 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1751 helpMsg_.append("Available Commands:"); 1752 /* now add all the commands available */ 1753 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1754 helpMsg_.append("--> "+"test"); 1755 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1756 helpMsg_.append("--> "+"on"); 1757 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1758 helpMsg_.append("--> "+"off"); 1759 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1760 helpMsg_.append("--> "+"colour r g b w"); 1761 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1762 helpMsg_.append("--> "+"r"); 1763 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1764 helpMsg_.append("--> "+"g"); 1765 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1766 helpMsg_.append("--> "+"b"); 1767 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1768 helpMsg_.append("--> "+"w"); 1769 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1770 helpMsg_.append("--> "+"cw"); 1771 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1772 helpMsg_.append("--> "+"p"); 1773 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1774 helpMsg_.append("--> "+"cyan"); 1775 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1776 helpMsg_.append("--> "+"fade r g b w r2 g2 b2 w2"); 1777 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1778 helpMsg_.append(" --> "+"the from and to rgbw levels"); 1779 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1780 helpMsg_.append("--> "+"fun [loopTime-ms [pausetime-ms]]"); 1781 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1782 helpMsg_.append(" --> "+"loopTime-ms can be -1 to loop indefinitely"); 1783 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1784 helpMsg_.append(" --> "+"pausetime-ms is the pause between the colour changes"); 1785 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1786 helpMsg_.append("--> "+"christmasFun [loopTime-ms [pausetime-ms]]"); 1787 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1788 helpMsg_.append(" --> "+"loopTime-ms can be -1 to loop indefinitely"); 1789 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1790 helpMsg_.append(" --> "+"pausetime-ms is the pause between the colour changes"); 1791 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1792 helpMsg_.append("--> "+"christmasFade [loopTime-ms [pausetime-ms]]"); 1793 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1794 helpMsg_.append(" --> "+"loopTime-ms can be -1 to loop indefinitely"); 1795 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1796 helpMsg_.append(" --> "+"pausetime-ms is the pause between the colour changes"); 1797 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1798 helpMsg_.append("--> "+"slowBurn [loopTime-ms [pausetime-ms]]"); 1799 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1800 helpMsg_.append(" --> "+"loopTime-ms can be -1 to loop indefinitely"); 1801 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1802 helpMsg_.append(" --> "+"pausetime-ms is the pause between the colour changes"); 1803 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1804 helpMsg_.append("--> "+"dumpLevels"); 1805 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1806 helpMsg_.append("---------------------------------------------------------"); 1807 helpMsg_.append("----------------------"); 1808 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1809 1810 return helpMsg_; 1811 } 1812 1813 1814 /** 1815 * Class main commandLine entry method. 1816 **/ 1817 public static void main(String [] args) 1818 { 1819 final String methodName = CLASSNAME + ": main()"; 1820 LedNetProxy instance = new LedNetProxy(DEFAULT_LEDNET_IP, DEFAULT_LEDNET_PORT); 1821 int commandArg = 0; 1822 1823 // if there are more than 1 args, then the 1st is assumed to be a non-default port number 1824 if (args.length>1 && args[commandArg].contains(":")) 1825 { 1826 System.out.println("Overriding DEFAULT IP & port with: "+args[commandArg]); 1827 String [] ipPort = args[commandArg].split("\\:"); 1828 instance.setReceiverIP(ipPort[0]); 1829 instance.setReceiverPort(Integer.parseInt(ipPort[1])); 1830 commandArg++; 1831 } 1832 1833 /* Simple way af parsing the args */ 1834 if (args ==null || args.length<1) 1835 System.out.println(getHelpMsgStr()); 1836 else 1837 { 1838 /* *********************************************** */ 1839 if (args[commandArg].equalsIgnoreCase("test")) 1840 { 1841 System.out.println("Testing LedNetProxy"); 1842 String queryResponse = instance.sendQueryOnOffCommand(true, false); 1843 System.out.println(queryResponse); 1844 System.out.println(); 1845 1846 int delay = 250; 1847 instance.sendColourCommand(128,0,0,0); 1848 instance.fadeBetweenCommand(255,0,0,0, 0,255,0,0, FadeSpeed.MEDIUM); 1849 instance.fadeBetweenCommand(0,255,0,0, 0,0,255,0, FadeSpeed.MEDIUM); 1850 1851 instance.sendColourCommand(0,0,0,0); 1852 instance.sendColourCommand(180,180,180,0); 1853 instance.sendColourCommand(0,0,0,180); 1854 instance.sendColourCommand(0,0,0,0); 1855 instance.sendColourCommand(0,0,0,180); 1856 instance.sendColourCommand(0,0,0,0); 1857 instance.sendColourCommand(0,0,0,180); 1858 instance.sendColourCommand(0,0,0,0); 1859 instance.sendColourCommand(0,0,0,180); 1860 1861 instance.fadeBetweenCommand(255,0,0,0, 0,255,0,0 , FadeSpeed.MEDIUM); 1862 1863 instance.sendQueryOnOffCommand(false, true); 1864 } 1865 /* *********************************************** */ 1866 else if (args[commandArg].equalsIgnoreCase("test2")) 1867 { 1868 int toLevel = 255; 1869 instance.debugging_=true; 1870 instance.sendQueryOnOffCommand(true, false); 1871 // Test Fade 1872 instance.fadeBetweenCommand( toLevel,0,toLevel,0, (toLevel/20),0,(toLevel/20),0 , FadeSpeed.MOLASSES, true); 1873 instance.fadeBetweenCommand( (toLevel/20),0,(toLevel/20),0 , toLevel,0,toLevel,0, FadeSpeed.MOLASSES, true); 1874 1875 //Turn OFF 1876 instance.sendQueryOnOffCommand(false, true); 1877 } 1878 /* *********************************************** */ 1879 else if (args[commandArg].equalsIgnoreCase("testFade")) 1880 { 1881 int toLevel = 128; 1882 if(args.length>1) toLevel = Integer.parseInt(args[commandArg+1]); 1883 System.out.println("Testing LedNetProxy Fading to level:"+toLevel); 1884 // Turn On 1885 instance.sendColourCommand(0,0,0,0); 1886 String queryResponse = instance.sendQueryOnOffCommand(true, false); 1887 1888 // Test Fade 1889 instance.fadeBetweenCommand( toLevel,0,toLevel,0, (toLevel/20),0,(toLevel/20),0 , FadeSpeed.VERYSLOW); 1890 instance.fadeBetweenCommand( (toLevel/20),0,(toLevel/20),0 , toLevel,0,toLevel,0, FadeSpeed.VERYSLOW); 1891 1892 //Turn OFF 1893 instance.sendQueryOnOffCommand(false, true); 1894 } 1895 /* *********************************************** */ 1896 else if (args[commandArg].equalsIgnoreCase("testCustom")) 1897 { 1898 //instance.sendQueryOnOffCommand(true, true); 1899 instance.sendCustomCommand(255,0,0,0,0,0,255,0,60); 1900 } 1901 1902 1903 /* *********************************************** */ 1904 else if (args[commandArg].equalsIgnoreCase("on")) 1905 { 1906 //instance.sendQueryOnOffCommand(true, true); 1907 String queryResponse = instance.sendQueryOnOffCommand(true, true); 1908 } 1909 /* *********************************************** */ 1910 else if (args[commandArg].equalsIgnoreCase("off")) 1911 { 1912 //instance.sendQueryOnOffCommand(true, true); 1913 String queryResponse = instance.sendQueryOnOffCommand(false, true); 1914 } 1915 /* *********************************************** */ 1916 else if (args[commandArg].equalsIgnoreCase("r")) 1917 { 1918 //instance.sendQueryOnOffCommand(true, true); 1919 instance.sendColourCommand(255,0,0,0); 1920 } 1921 /* *********************************************** */ 1922 else if (args[commandArg].equalsIgnoreCase("g")) 1923 { 1924 //instance.sendQueryOnOffCommand(true, true); 1925 instance.sendColourCommand(0,255,0,0); 1926 } 1927 /* *********************************************** */ 1928 else if (args[commandArg].equalsIgnoreCase("b")) 1929 { 1930 //instance.sendQueryOnOffCommand(true, true); 1931 instance.sendColourCommand(0,0,255,0); 1932 } 1933 /* *********************************************** */ 1934 else if (args[commandArg].equalsIgnoreCase("p")) 1935 { 1936 //instance.sendQueryOnOffCommand(true, true); 1937 instance.sendColourCommand(5,0,15,0); 1938 } 1939 /* *********************************************** */ 1940 else if (args[commandArg].equalsIgnoreCase("y")) 1941 { 1942 //instance.sendQueryOnOffCommand(true, true); 1943 instance.sendColourCommand(255,255,0,0); 1944 } 1945 /* *********************************************** */ 1946 else if (args[commandArg].equalsIgnoreCase("w")) 1947 { 1948 //instance.sendQueryOnOffCommand(true, true); 1949 instance.sendColourCommand(200,200,200,255); 1950 } 1951 /* *********************************************** */ 1952 else if (args[commandArg].equalsIgnoreCase("ww")) 1953 { 1954 //instance.sendQueryOnOffCommand(true, true); 1955 instance.sendColourCommand(0,0,0,255); 1956 } 1957 /* *********************************************** */ 1958 else if (args[commandArg].equalsIgnoreCase("cw")) 1959 { 1960 //instance.sendQueryOnOffCommand(true, true); 1961 instance.sendColourCommand(240,240,255,80); 1962 } 1963 /* *********************************************** */ 1964 else if (args[commandArg].equalsIgnoreCase("cyan")) 1965 { 1966 //instance.sendQueryOnOffCommand(true, true); 1967 instance.sendColourCommand(0,20,10,0); 1968 } 1969 /* *********************************************** */ 1970 else if (args[commandArg].equalsIgnoreCase("fade")) 1971 { 1972 if(args.length>8) 1973 { 1974 instance.sendQueryOnOffCommand(true, false); 1975 instance.fadeBetweenCommand(Integer.parseInt(args[commandArg+1]), 1976 Integer.parseInt(args[commandArg+2]), 1977 Integer.parseInt(args[commandArg+3]), 1978 Integer.parseInt(args[commandArg+4]), 1979 Integer.parseInt(args[commandArg+5]), 1980 Integer.parseInt(args[commandArg+6]), 1981 Integer.parseInt(args[commandArg+7]), 1982 Integer.parseInt(args[commandArg+8]), 1983 FadeSpeed.VERYSLOW, 1984 false); 1985 } 1986 } 1987 /* *********************************************** */ 1988 else if (args[commandArg].equalsIgnoreCase("colour")) 1989 { 1990 //System.out.println("args.length="+args.length+"\ncommandArg="+commandArg); 1991 int r = (args.length>commandArg+1 ? Integer.parseInt(args[commandArg+1]):0); 1992 int g = (args.length>commandArg+2?Integer.parseInt(args[commandArg+2]):0); 1993 int b = (args.length>commandArg+3?Integer.parseInt(args[commandArg+3]):0); 1994 int w = (args.length>commandArg+4?Integer.parseInt(args[commandArg+4]):0); 1995 //instance.sendQueryOnOffCommand(true, true); 1996 instance.sendColourCommand(r,g,b,w); 1997 } 1998 /* *********************************************** */ 1999 else if (args[commandArg].equalsIgnoreCase("dumplevels")) 2000 { 2001 //instance.sendQueryOnOffCommand(true, true); 2002 instance.dumpLevels(); 2003 instance.dumpReverseLevels(); 2004 } 2005 /* *********************************************** */ 2006 else if (args[commandArg].equalsIgnoreCase("dumpExpLevels")) 2007 { 2008 //instance.sendQueryOnOffCommand(true, true); 2009 instance.dumpExpLevels(); 2010 } 2011 2012 2013 /* *********************************************** */ 2014 else if (args[commandArg].equalsIgnoreCase("fun")) 2015 { 2016 //instance.sendQueryOnOffCommand(true, true); 2017 instance.fun((args.length>1?Integer.parseInt(args[commandArg+1]):-1), 2018 (args.length>2?Integer.parseInt(args[commandArg+2]):200)); // loopTime, pause 2019 } 2020 /* *********************************************** */ 2021 else if (args[commandArg].equalsIgnoreCase("christmasFun")) 2022 { 2023 //instance.sendQueryOnOffCommand(true, true); 2024 instance.christmasFun((args.length>1?Integer.parseInt(args[commandArg+1]):-1), 2025 (args.length>2?Integer.parseInt(args[commandArg+2]):200)); // loopTime, pause 2026 } 2027 /* *********************************************** */ 2028 else if (args[commandArg].equalsIgnoreCase("christmasFade")) 2029 { 2030 int loopTime = -1; 2031 long pause = 250; 2032 int toLevel = 64; 2033 if(args.length>1) toLevel = Integer.parseInt(args[commandArg+1]); 2034 instance.christmasFade(toLevel, loopTime, pause); 2035 2036 //Turn OFF 2037 instance.sendQueryOnOffCommand(false, true); 2038 } 2039 /* *********************************************** */ 2040 else if (args[commandArg].equalsIgnoreCase("slowBurn")) 2041 { 2042 int loopTime = -1; 2043 long pause = 250; 2044 int toLevel = 10; 2045 if(args.length>1) toLevel = Integer.parseInt(args[commandArg+1]); 2046 instance.slowBurn(toLevel, loopTime, pause); 2047 2048 //Turn OFF 2049 instance.sendQueryOnOffCommand(false, true); 2050 } 2051 /* *********************************************** */ 2052 else if (args[commandArg].equalsIgnoreCase("nightFade")) 2053 { 2054 instance.sendQueryOnOffCommand(true, false); 2055 2056 while(true) 2057 { 2058 instance.stepBetween(1,0,1,0, 8,0,16,0); 2059 instance.stepBetween(8,0,16,0, 1,0,1,0); 2060 } 2061 } 2062 instance.closeSocket(); 2063 } 2064 } // main 2065 2066 2067 /** Prints out the non-linear levels from the class var Exponential formula. **/ 2068 public void dumpExpLevels() 2069 { 2070 for (int i=0; i<256; i++) 2071 System.out.println("v="+i+" "+expLedLevel(i)); 2072 } 2073 2074 2075 /** Prints out the non-linear levels from the class var levels_. **/ 2076 public void dumpLevels() 2077 { 2078 for (int i=0; i<256; i++) 2079 //System.out.println("v="+i+" "+levels_.get(Integer.valueOf(i)).intValue()); 2080 System.out.println("v="+i+" "+ledLevel(i)); 2081 //System.out.println("\nLevelCount="+levelCount); 2082 2083 } 2084 2085 2086 /** Prints out the reverse non-linear lookup levels from the class var reverseLevels_. **/ 2087 public void dumpReverseLevels() 2088 { 2089 System.out.println("\rreverseLevels_ size="+reverseLevels_.size()); 2090 for (int i=0; i<256; i++) 2091 if (reverseLevels_.get(Integer.valueOf(i))!=null) 2092 System.out.println("v="+i+" "+reverseLevels_.get(Integer.valueOf(i)).intValue()); 2093 System.out.println("\nLevelCount="+levelCount); 2094 2095 } 2096 2097 2098 /** 2099 * Initializes the class var 'levels_' HashMap of non-linear lookup values for the LED brightness levels. 2100 **/ 2101 private void initLevelsMap() 2102 { 2103 int inc = 1; 2104 int currVal = 0; 2105 levelCount = 0; 2106 int [] levelMarks = {0,16,32,64,128,256}; 2107 int currMark = 0; 2108 int maxVal = 255; 2109 2110 levels_ = new HashMap<Integer, Integer>(256); 2111 2112 for (int loop=0; loop<levelMarks.length-1; loop++) 2113 { 2114 currMark = levelMarks[loop]; 2115 //System.out.println("\n initLevelsMap currMark="+currMark); 2116 // count through all numbers 0-255 and assign its lookupLevel 2117 for (int i=currMark; i<levelMarks[loop+1]; i++) 2118 { 2119 levels_.put(Integer.valueOf(i), Integer.valueOf(currVal)); 2120 //System.out.println(" i="+i+" mapped to "+currVal); 2121 currVal+=inc; 2122 if(currVal>maxVal) currVal=maxVal; 2123 } 2124 inc*=2; // double the incrementer after every levelMark 2125 /*for (int i=currMark; i<levelMarks[loop+1]; i+=inc) 2126 { 2127 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2128 currVal+=inc; levelCount++; 2129 } 2130 currVal+=inc; inc*=2; // double the incrementer after every levelMark*/ 2131 } 2132 2133 // manually set the levels 2134 /* 2135 for (int i=0; i<8; i++) 2136 { 2137 levels_.put(Integer.valueOf(i), Integer.valueOf(currVal)); 2138 currVal+=inc; 2139 levelCount++; 2140 } 2141 2142 currVal+=inc; 2143 inc=2; 2144 for (int i=8; i<16; i+=inc) 2145 { 2146 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2147 currVal+=inc; levelCount++; 2148 } 2149 2150 currVal+=inc; 2151 inc=4; 2152 for (int i=16; i<32; i+=inc) 2153 { 2154 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2155 currVal+=inc; levelCount++; 2156 } 2157 2158 currVal+=inc; 2159 inc=8; 2160 for (int i=32; i<64; i+=inc) 2161 { 2162 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2163 currVal+=inc; levelCount++; 2164 } 2165 2166 currVal+=inc; 2167 inc=16; 2168 for (int i=64; i<128; i+=inc) 2169 { 2170 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2171 currVal+=inc; levelCount++; 2172 } 2173 2174 currVal+=inc; 2175 inc=32; 2176 for (int i=128; i<256; i+=inc) 2177 { 2178 for(int j=0; j<inc; j++) {levels_.put(Integer.valueOf(i+j), Integer.valueOf(currVal));} 2179 currVal+=inc; levelCount++; 2180 } 2181 */ 2182 2183 2184 //System.out.println("Creating reverseLevels_ levelsCount="+levelCount); 2185 reverseLevels_ = new HashMap<Integer, Integer>(levelCount); 2186 for (int i=levelMarks[0]; i<levelMarks[levelMarks.length-1]; i++) 2187 { 2188 for(int j=levelMarks[0];j<levelMarks[levelMarks.length-1];j++) 2189 { 2190 if(levels_.get(Integer.valueOf(j))!=null) 2191 { 2192 //System.out.println(" Checking "+i+" for level "+levels_.get(Integer.valueOf(j))); 2193 if(levels_.get(Integer.valueOf(j)).intValue()==i) 2194 { 2195 //System.out.println(" ..... adding "+Integer.valueOf(j) + " "+ Integer.valueOf(i)); 2196 reverseLevels_.put(Integer.valueOf(j), Integer.valueOf(i)); 2197 j=levelMarks[levelMarks.length-1]; 2198 } 2199 } 2200 } 2201 } 2202 //System.out.println("reverseLevels_ size="+reverseLevels_.size()); 2203 2204 } 2205 2206} // class