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}