001package ca.bc.webarts.raspberry; 002 003/* 004 * $Rev: $: Revision of last commit 005 * $Author: $: Author of last commit 006 * $Date: $: Date of last commit 007 * $URL: $ 008 * 009 * Written by Tom Gutwin 010 * Copyright (C) 2015 Tom B. Gutwin, North Vancouver BC Canada 011 * 012 * This program is free software; you can redistribute it and/or modify 013 * it under the terms of the GNU General Public License as published by 014 * the Free Software Foundation; either version 3of the License, or 015 * (at your option) any later version. 016 * 017 * This program is distributed in the hope that it will be useful, 018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 020 * GNU General Public License for more details. 021 * 022 * You should have received a copy of the GNU General Public License 023 * along with this program; If not, see <http://www.gnu.org/licenses/>. 024 */ 025 026import com.pi4j.wiringpi.SoftPwm; 027 028import java.io.BufferedReader; 029import java.io.InputStreamReader; 030 031 032/** A simple example class to control 3 GPIO pins with a Pulse Width Modulation (PWM) signal that are connected to a RGB LED. 033 * This allows many more combinations of colours to be displayed with the GPIO. <br /> 034 * It is somewhat based on the Pi4J example: WiringPiSoftPWMExample. 035 **/ 036public class SoftPWMRGB 037{ 038 /** Used for user commandline input. **/ 039 private static final BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 040 public static final int RED_COLOUR = 0; 041 public static final int GREEN_COLOUR = 1; 042 public static final int BLUE_COLOUR = 2; 043 public static final int WHITE_COLOUR = 3; 044 public static final int GRADIENT_STEPSIZE = 2; 045 public static final int GRADIENT_SLEEPSPEED = 100; 046 /** the create gpio controller. **/ 047 //final GpioController gpio = GpioFactory.getInstance(); 048 049 //private GpioPinDigitalOutput redPin = null; 050 //private GpioPinDigitalOutput greenPin = null; 051 //private GpioPinDigitalOutput bluePin = null; 052 053 /** The GPIO Pin number (wiringPi/Pi4J) that will be connected to the Red LED. **/ 054 private int redPinNumber = 23; 055 /** The GPIO Pin number (wiringPi/Pi4J) that will be connected to the Green LED. **/ 056 private int greenPinNumber = 24; 057 /** The GPIO Pin number (wiringPi/Pi4J) that will be connected to the Blue LED. **/ 058 private int bluePinNumber = 25; 059 060 /** The Level of the Red LED GPIO pin - it is the PWM duty. **/ 061 private int redLevel = 0; 062 /** The Level of the Green LED GPIO pin - it is the PWM duty. **/ 063 private int greenLevel = 0; 064 /** The Level of the Blue LED GPIO pin - it is the PWM duty. **/ 065 private int blueLevel = 0; 066 067 068 /** Instantiates and gets the initial pins setup for use. **/ 069 public SoftPWMRGB() 070 { 071 // initialize wiringPi library 072 com.pi4j.wiringpi.Gpio.wiringPiSetup(); 073 074 // init the pins 075 setRedPinNumber(redPinNumber); 076 setGreenPinNumber(greenPinNumber); 077 setBluePinNumber(bluePinNumber); 078 } 079 080 081 /** 082 * Returns the value of redPinNumber. 083 */ 084 public int getRedPinNumber() { return redPinNumber; } 085 086 087 /** 088 * Sets the value of redPinNumber and re-inits the redPin GPIO Pin Object. 089 * @param redPinNumber The GPIO Pin Number for the Red. 090 */ 091 public void setRedPinNumber(int redPinNumber) 092 { 093 this.redPinNumber = redPinNumber; 094 //redPin = gpio.provisionDigitalOutputPin(RaspiPin.getPinByName("GPIO_"+redPinNumber, "red", PinState.LOW); 095 initRedPWMPin(); 096 } 097 098 099 /** 100 * Returns the value of greenPinNumber. 101 */ 102 public int getGreenPinNumber() { return greenPinNumber; } 103 104 105 /** 106 * Sets the value of redPinNumber and re-inits the greenPin GPIO Pin Object. 107 * @param greenPinNumber The GPIO Pin Number for the Green LED . 108 */ 109 public void setGreenPinNumber(int greenPinNumber) 110 { 111 this.greenPinNumber = greenPinNumber; 112 //greenPin = gpio.provisionDigitalOutputPin(RaspiPin.getPinByName("GPIO_"+greenPinNumber, "green", PinState.LOW); 113 initGreenPWMPin(); 114 } 115 116 117 /** 118 * Returns the value of bluePinNumber. 119 */ 120 public int getBluePinNumber() { return bluePinNumber; } 121 122 123 /** 124 * Sets the value of redPinNumber and re-inits the bluePin GPIO Pin Object. 125 * @param bluePinNumber The GPIO Pin Number for the blue LED . 126 */ 127 public void setBluePinNumber(int bluePinNumber) 128 { 129 this.bluePinNumber = bluePinNumber; 130 //bluePin = gpio.provisionDigitalOutputPin(RaspiPin.getPinByName("GPIO_"+bluePinNumber, "blue", PinState.LOW); 131 initBluePWMPin(); 132 133 } 134 135 136 /** 137 * Set Method for class field 'redLevel'. 138 * 139 * @param redLevel is the value to set this class field to. 140 * 141 **/ 142 public void setRedLevel(int redLevel) 143 { 144 this.redLevel = redLevel; 145 System.out.println("Setting Red to:"+redLevel); 146 SoftPwm.softPwmWrite(getRedPinNumber() , redLevel); 147 } // setRedLevel Method 148 149 150 /** 151 * Get Method for class field 'redLevel'. 152 * 153 * @return int - The value the class field 'redLevel'. 154 * 155 **/ 156 public int getRedLevel() 157 { 158 return redLevel; 159 } // getRedLevel Method 160 161 162 /** 163 * Set Method for class field 'greenLevel'. 164 * 165 * @param greenLevel is the value to set this class field to. 166 * 167 **/ 168 public void setGreenLevel(int greenLevel) 169 { 170 this.greenLevel = greenLevel; 171 System.out.println("Setting Green to:"+greenLevel); 172 SoftPwm.softPwmWrite(getGreenPinNumber() , greenLevel); 173 } // setGreenLevel Method 174 175 176 /** 177 * Get Method for class field 'greenLevel'. 178 * 179 * @return int - The value the class field 'greenLevel'. 180 * 181 **/ 182 public int getGreenLevel() 183 { 184 return greenLevel; 185 } // getGreenLevel Method 186 187 188 /** 189 * Set Method for class field 'blueLevel'. 190 * 191 * @param blueLevel is the value to set this class field to. 192 * 193 **/ 194 public void setBlueLevel(int blueLevel) 195 { 196 this.blueLevel = blueLevel; 197 System.out.println("Setting Blue to:"+blueLevel); 198 SoftPwm.softPwmWrite(getBluePinNumber() , blueLevel); 199 } // setBlueLevel Method 200 201 202 /** 203 * Get Method for class field 'blueLevel'. 204 * 205 * @return int - The value the class field 'blueLevel'. 206 * 207 **/ 208 public int getBlueLevel() 209 { 210 return blueLevel; 211 } // getBlueLevel Method 212 213 214 215 /** This provisions/creates a software controlled PWM pin. You can use any GPIO pin and the 216 * pin numbering is that of the wiringPiSetup function you used. 217 * The PWM range is from 0 to 100: 0 (off) to 100 (fully on) for the given pin. 218 * 219 * @param pin is the wiringPI pin number to initialize as a PWM pin. 220 * @return The return value is 0 for success, Anything else and you should check the global errno variable to see what went wrong. 221 **/ 222 private int initPWMPin(int pin) 223 { 224 // create soft-pwm pins (default min=0 ; max=100) 225 int retVal = SoftPwm.softPwmCreate( pin, 0, 100); 226 if(retVal!=0) System.out.println("ERROR: Could Not Init Pin "+pin+" as a PWM pin. \n"); 227 return retVal; 228 } 229 230 /** Provisions the Red Pin as a PWM pin. **/ 231 public int initRedPWMPin() 232 { 233 return initPWMPin(redPinNumber); 234 } 235 236 237 /** Provisions the Green Pin as a PWM pin. **/ 238 public int initGreenPWMPin() 239 { 240 return initPWMPin(greenPinNumber); 241 } 242 243 244 /** Provisions the blue Pin as a PWM pin. **/ 245 public int initBluePWMPin() 246 { 247 return initPWMPin(bluePinNumber); 248 } 249 250 251 public void gradualRedOn() {gradualOn(RED_COLOUR);} 252 public void gradualRedOn(int onLevel) {gradualOn(RED_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 253 public void gradualRedOn(int stepSize, int sleepSpeedMillis) {gradualOn(RED_COLOUR, 100, stepSize, sleepSpeedMillis);} 254 public void gradualGreenOn() {gradualOn(GREEN_COLOUR);} 255 public void gradualGreenOn(int onLevel) {gradualOn(GREEN_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 256 public void gradualGreenOn(int stepSize, int sleepSpeedMillis) {gradualOn(GREEN_COLOUR, 100, stepSize, sleepSpeedMillis);} 257 public void gradualBlueOn() {gradualOn(BLUE_COLOUR);} 258 public void gradualBlueOn(int onLevel) {gradualOn(BLUE_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 259 public void gradualBlueOn(int stepSize, int sleepSpeedMillis) {gradualOn(BLUE_COLOUR, 100, stepSize, sleepSpeedMillis);} 260 public void gradualWhiteOn() {gradualOn(WHITE_COLOUR);} 261 public void gradualWhiteOn(int onLevel) {gradualOn(WHITE_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 262 public void gradualWhiteOn(int stepSize, int sleepSpeedMillis) {gradualOn(WHITE_COLOUR, 100, stepSize, sleepSpeedMillis);} 263 264 public void gradualOn(int rgbColour) {gradualOn(rgbColour, 100, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 265 public void gradualOn(int rgbColour, int stepSize, int sleepSpeedMillis) {gradualOn(rgbColour, 100, stepSize, sleepSpeedMillis);} 266 267 268 public void gradualRedOff() {gradualOff(RED_COLOUR);} 269 public void gradualRedOff(int onLevel) {gradualOff(RED_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 270 public void gradualRedOff(int stepSize, int sleepSpeedMillis) {gradualOff(RED_COLOUR, 0, stepSize, sleepSpeedMillis);} 271 public void gradualGreenOff() {gradualOff(GREEN_COLOUR);} 272 public void gradualGreenOff(int onLevel) {gradualOff(GREEN_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 273 public void gradualGreenOff(int stepSize, int sleepSpeedMillis) {gradualOff(GREEN_COLOUR, 0, stepSize, sleepSpeedMillis);} 274 public void gradualBlueOff() {gradualOff(BLUE_COLOUR);} 275 public void gradualBlueOff(int onLevel) {gradualOff(BLUE_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 276 public void gradualBlueOff(int stepSize, int sleepSpeedMillis) {gradualOff(BLUE_COLOUR, 0, stepSize, sleepSpeedMillis);} 277 public void gradualWhiteOff() {gradualOff(WHITE_COLOUR);} 278 public void gradualWhiteOff(int onLevel) {gradualOff(WHITE_COLOUR, onLevel, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 279 public void gradualWhiteOff(int stepSize, int sleepSpeedMillis) {gradualOff(WHITE_COLOUR, 0, stepSize, sleepSpeedMillis);} 280 281 public void gradualOff(int rgbColour) {gradualOff(rgbColour, 0, GRADIENT_STEPSIZE, GRADIENT_SLEEPSPEED);} 282 public void gradualOff(int rgbColour, int stepSize, int sleepSpeedMillis) {gradualOff(rgbColour, 0, stepSize, sleepSpeedMillis);} 283 284 285 /** Gradually steps the PWM colour up to the specified level. **/ 286 public void gradualOn(int rgbColour, int onLevel, int stepSize, int sleepSpeedMillis) 287 { 288 if (sleepSpeedMillis<0) sleepSpeedMillis=GRADIENT_SLEEPSPEED; 289 if (stepSize<0) stepSize=GRADIENT_STEPSIZE; 290 for (int rL=0; rL<=onLevel; rL+=stepSize) 291 { 292 if(getRedLevel() < rL && (rgbColour==WHITE_COLOUR || rgbColour== RED_COLOUR)) setRedLevel(rL); 293 if(getGreenLevel() < rL && (rgbColour==WHITE_COLOUR || rgbColour== GREEN_COLOUR)) setGreenLevel(rL); 294 if(getBlueLevel() < rL && (rgbColour==WHITE_COLOUR || rgbColour== BLUE_COLOUR)) setBlueLevel(rL); 295 sleep(sleepSpeedMillis); 296 } 297 } 298 299 300 /** Gradually steps the PWM colour down to the specified level. **/ 301 public void gradualOff(int rgbColour, int onLevel, int stepSize, int sleepSpeedMillis) 302 { 303 if (sleepSpeedMillis<0) sleepSpeedMillis=GRADIENT_SLEEPSPEED; 304 if (stepSize<0) stepSize=GRADIENT_STEPSIZE; 305 int startLevel = 0; 306 if(rgbColour== RED_COLOUR) startLevel=getRedLevel(); 307 if(rgbColour== GREEN_COLOUR) startLevel=getGreenLevel(); 308 if(rgbColour== BLUE_COLOUR) startLevel=getBlueLevel(); 309 if(rgbColour== WHITE_COLOUR) 310 { 311 if(startLevel<getBlueLevel() ) startLevel=getBlueLevel(); 312 if(startLevel<getGreenLevel() ) startLevel=getGreenLevel(); 313 if(startLevel<getRedLevel() ) startLevel=getRedLevel(); 314 } 315 for (int rL=startLevel; rL>=onLevel; rL-=stepSize) 316 { 317 if(getRedLevel() > rL && (rgbColour==WHITE_COLOUR || rgbColour== RED_COLOUR)) setRedLevel(rL); 318 if(getGreenLevel() > rL && (rgbColour==WHITE_COLOUR || rgbColour== GREEN_COLOUR)) setGreenLevel(rL); 319 if(getBlueLevel() > rL && (rgbColour==WHITE_COLOUR || rgbColour== BLUE_COLOUR)) setBlueLevel(rL); 320 sleep(sleepSpeedMillis); 321 } 322 } 323 324 325 public void cycleAllGradients(int numLoops){ cycleAllGradients(numLoops, 100);} 326 public void cycleAllGradients(int numLoops, int onLevel) 327 { 328 // Now sone fancy panning through the colours befor shuting down 329 setRedLevel(0); 330 setGreenLevel(0); 331 setBlueLevel(0); 332 for (int loopNum=0; loopNum< numLoops; loopNum++) 333 { 334 gradualRedOn(onLevel); 335 gradualBlueOn(onLevel); 336 gradualRedOff(); 337 gradualGreenOn(onLevel); 338 gradualBlueOff(); 339 gradualRedOn(onLevel); 340 gradualBlueOn(onLevel); 341 gradualWhiteOff(); 342 } 343 } 344 345 346 /** gather user input from the commandline. **/ 347 public static String userInput(String prompt) 348 { 349 String retString = ""; 350 System.err.print(prompt); 351 try 352 { 353 retString = stdin.readLine(); 354 } 355 catch(Exception e) 356 { 357 System.out.println(e); 358 String s; 359 try 360 { 361 s = userInput("<Oooch/>"); 362 } 363 catch(Exception exception) 364 { 365 exception.printStackTrace(); 366 } 367 } 368 return retString; 369 } 370 371 372 /** Run the demo from here. It will ask for a colour letter and level (0-100). **/ 373 public static void main(String[] args) throws InterruptedException 374 { 375 SoftPWMRGB instance = new SoftPWMRGB(); 376 377 boolean go = true; 378 String sIn = ""; 379 int intVal = 0; 380 while (go) 381 { 382 sIn = userInput("R XXX, G YYY, B ZZZ, or QUIT > "); 383 try 384 { 385 if (sIn.toUpperCase().startsWith("R") ) 386 { 387 if(sIn.trim().length()==1) 388 if(instance.getRedLevel()==100) intVal = 0; 389 else intVal = 100; 390 else 391 intVal =Integer.parseInt(sIn.substring(1).trim()); 392 instance.setRedLevel(intVal); 393 } 394 else if (sIn.toUpperCase().startsWith("G") ) 395 { 396 if(sIn.trim().length()==1) 397 if(instance.getGreenLevel()==100) intVal = 0; 398 else intVal = 100; 399 else 400 intVal =Integer.parseInt(sIn.substring(1).trim()); 401 instance.setGreenLevel(intVal); 402 } 403 else if (sIn.toUpperCase().startsWith("B") ) 404 { 405 if(sIn.trim().length()==1) 406 if(instance.getBlueLevel()==100) intVal = 0; 407 else intVal = 100; 408 else 409 intVal =Integer.parseInt(sIn.substring(1).trim()); 410 instance.setBlueLevel(intVal); 411 } 412 else if ("QUIT".equals(sIn.toUpperCase()) || "Q".equals(sIn.toUpperCase())) 413 { 414 go = false; 415 } 416 else 417 System.out.println("Unknown command [" + sIn + "]"); 418 } 419 catch(Exception e) 420 { 421 System.out.println("Error Parsing Input values from: "+sIn); 422 System.out.println("Please Try Again \n"); 423 } 424 } 425 426 // Now sone fancy panning through the colours befor shuting down 427 instance.cycleAllGradients(3,20); 428 429 430 // FlashyFlashy 431 instance.setRedLevel(100); 432 instance.setGreenLevel(100); 433 instance.setBlueLevel(100); 434 sleep(250); 435 instance.setRedLevel(0); 436 instance.setGreenLevel(0); 437 instance.setBlueLevel(0); 438 sleep(250); 439 instance.setRedLevel(100); 440 instance.setGreenLevel(100); 441 instance.setBlueLevel(100); 442 sleep(250); 443 instance.setRedLevel(0); 444 instance.setGreenLevel(0); 445 instance.setBlueLevel(0); 446 sleep(250); 447 instance.setRedLevel(100); 448 instance.setGreenLevel(100); 449 instance.setBlueLevel(100); 450 sleep(250); 451 instance.setRedLevel(0); 452 instance.setGreenLevel(0); 453 instance.setBlueLevel(0); 454 sleep(250); 455 instance.setRedLevel(100); 456 instance.setGreenLevel(100); 457 instance.setBlueLevel(100); 458 sleep(250); 459 instance.setRedLevel(0); 460 instance.setGreenLevel(0); 461 instance.setBlueLevel(0); 462 sleep(250); 463 instance.setRedLevel(100); 464 instance.setGreenLevel(100); 465 instance.setBlueLevel(100); 466 sleep(250); 467 instance.setRedLevel(0); 468 instance.setGreenLevel(0); 469 instance.setBlueLevel(0); 470 sleep(250); 471 instance.setRedLevel(100); 472 instance.setGreenLevel(100); 473 instance.setBlueLevel(100); 474 sleep(250); 475 instance.setRedLevel(0); 476 instance.setGreenLevel(0); 477 instance.setBlueLevel(0); 478 } 479 480 /** 481 * A method to simply abstract the Try/Catch required to put the current 482 * thread to sleep for the specified time in ms. 483 * 484 * @param waitTime the sleep time in milli seconds (ms). 485 * @return boolean value specifying if the sleep completed (true) or was interupted (false). 486 */ 487 public static boolean sleep(long waitTime) 488 { 489 boolean retVal = true; 490 if (waitTime<0) 491 retVal=false; 492 else 493 { 494 /* 495 * BLOCK for the spec'd time 496 */ 497 try 498 { 499 Thread.sleep(waitTime); 500 } 501 catch (InterruptedException iex) 502 { 503 retVal = false; 504 } 505 } 506 return retVal; 507 } 508}