001/*
002 *  $Rev: 1005 $:     Revision of last commit
003 *  $Author: tgutwin $:  Author of last commit
004 *  $Date: 2015-10-05 12:44:37 -0700 (Mon, 05 Oct 2015) $:    Date of last commit
005 *  $URL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/raspberry/ca/bc/webarts/raspberry/GpioCycler.java $
006 *
007 *  Written by Tom Gutwin
008 *  Copyright (C) 2015 Tom B. Gutwin, North Vancouver BC Canada
009 *
010 *  This program is free software; you can redistribute it and/or modify
011 *  it under the terms of the GNU General Public License as published by
012 *  the Free Software Foundation; either version 3of the License, or
013 *  (at your option) any later version.
014 *
015 *  This program is distributed in the hope that it will be useful,
016 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
017 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
018 *  GNU General Public License for more details.
019 *
020 *  You should have received a copy of the GNU General Public License
021 *  along with this program; If not, see <http://www.gnu.org/licenses/>.
022 */
023
024package ca.bc.webarts.raspberry;
025
026import com.pi4j.io.gpio.GpioController;
027import com.pi4j.io.gpio.GpioFactory;
028import com.pi4j.io.gpio.GpioPinDigitalOutput;
029import com.pi4j.io.gpio.Pin;
030import com.pi4j.io.gpio.PinState;
031import com.pi4j.io.gpio.RaspiPin;
032import com.pi4j.system.SystemInfo;
033
034import ca.bc.webarts.widgets.Util;
035/**
036 * This code demonstrates cycling Raspberry Pi GPIO pins on and off sequentially as an example of how to
037 * perform simple state control of a GPIO pin on the Raspberry Pi.
038 *
039 * It uses the <a href="http://www.pi4j.com">Pi4J library</a>.
040 *
041 * @author <a href="http://red.webarts.bc.ca/roller/tom/en_CA/">Tom Gutwin</a>
042 */
043public class GpioCycler
044{
045  /** Class constant for a PI board type A. **/
046  public static final short BOARD_TYPE_A = 0;
047  /** Class constant for a PI board type A+. **/
048  public static final short BOARD_TYPE_APLUS = 1;
049  /** Class constant for a PI board type B. **/
050  public static final short BOARD_TYPE_B = 2;
051  /** Class constant for a PI board type B2. **/
052  public static final short BOARD_TYPE_B2 = 3;
053  /** Class constant for a PI board type B+. **/
054  public static final short BOARD_TYPE_BPLUS = 4;
055  /** Class constant for a PI board type Pi2. **/
056  public static final short BOARD_TYPE_2 = 5;
057  /** Class constant for its DEFAULT  PI board type = BOARD_TYPE_2. **/
058  public static final short DEFAULT_BOARD_TYPE = BOARD_TYPE_2;
059
060  /** The DEFAULT time in milliSeconds the cycle loop should run. **/
061  public static final int DEFAULT_LOOP_TIME_MS = 20000;
062
063  /** The DEFAULT time in milliSeconds the GPIO will go HIGH. **/
064  public static final short DEFAULT_CYCLE_TIME_MS = 100;
065
066  /** The DEFAULT time in milliSeconds the <b>next</b> GPIO pin will come on before the previous
067    * one goes LOW. Its the overlap time. **/
068  public static final short DEFAULT_OVERLAP_TIME_MS = 0;
069
070  /** The default set of pins for a Raspberry Pi Model A or B board that will be controlled. Defaults to all pins. **/
071  public static final short [] DEFAULT_PIAB_PINS =    {0,1,2,3,4,5,6,7,8,9,
072                                                       10,11,12,13,14,15,16};
073  /** The default set of pins for a Raspberry Pi Model B Plus board that will be controlled. Defaults to all pins. **/
074  public static final short [] DEFAULT_PIBPLUS_PINS=  {0,1,2,3,4,5,6,7,8,9,
075                                                       10,11,12,13,14,15,16,
076                                                       21,22,23,24,25,26,27,28,29};
077  /** The default set of pins for a Raspberry Pi 2 Model B board that will be controlled. Defaults to all pins. **/
078  public static final short [] DEFAULT_PI2_PINS = DEFAULT_PIBPLUS_PINS;
079  public static final short [] DEFAULT_PINS = DEFAULT_PI2_PINS;
080
081  /** The default set of pins that will be used / enabled [0-11 are enabled]. **/
082  public static final boolean [] DEFAULT_ENABLED_PINS = {true,true,true,true,true,true,true,true,true,true,true,true,
083                                                         false,false,false,false,false,false,false,false,
084                                                         false,false,false,false,false,false,false,false,false};
085
086  /** The default pin to start the cycle from. **/
087  public static final short DEFAULT_START_PIN = DEFAULT_PINS[0];
088  /** The default pin to end the cycle from. **/
089  public static final short DEFAULT_END_PIN = DEFAULT_PINS[DEFAULT_PINS.length-1];
090
091  /** Default pin state is LOW. **/
092  public static final PinState DEFAULT_PINSTATE = PinState.LOW;
093
094
095  /** Class var specifying the active board type - it starts as the   DEFAULT_BOARD_TYPE. **/
096  private short boardType = DEFAULT_BOARD_TYPE;
097  /** The time that the whole thing should run/looping back and forth - use -1 to go forever **/
098  private int loopTime = DEFAULT_LOOP_TIME_MS;
099  /** The duty cycle time in ms that the GPIO will cycle ON. **/
100  private short cycleTime = DEFAULT_CYCLE_TIME_MS;
101  /** The time in ms that the next GPIO will come ON before the previous one is OFF -
102    * it can be a negative number to specify a delAY. **/
103  private short overlapTime = DEFAULT_OVERLAP_TIME_MS;
104  /** pins represents the GPIO pin numbers on the board. **/
105  private short[] pins = DEFAULT_PINS;
106
107  /** The pins that are enabled.**/
108  private boolean[] enabledPins = DEFAULT_ENABLED_PINS;
109
110  /** The gpioPin number associated with the first enabled GPIO pin that is 1st used in the cycle - zero based. **/
111  private short startPin = DEFAULT_START_PIN;
112  /** The gpioPin number associated with the last enabled GPIO pin that is LAST used in the cycle - zero based. **/
113  private short endPin =   DEFAULT_END_PIN;
114  /** The usable GPIO pins that will be used by this class - it does NOT get init until provisionPins is called. **/
115  private GpioPinDigitalOutput[] gpioPins = new GpioPinDigitalOutput[pins.length];
116
117  /** supervisor class flag to save re-provisioning. **/
118  private boolean allPinsProvisioned = false;
119
120  /** gpio controller used by all methods in this class. **/
121  private final GpioController gpio = GpioFactory.getInstance();
122
123
124  /** constructor **/
125  public GpioCycler()
126  {
127    try
128    {
129      SystemInfo.BoardType bt = SystemInfo.getBoardType();
130      if(bt.equals(SystemInfo.BoardType.Model2B_Rev1)) boardType = BOARD_TYPE_2;
131      else if(bt.equals(SystemInfo.BoardType.ModelB_Plus_Rev1)) boardType = BOARD_TYPE_BPLUS;
132      else if(bt.equals(SystemInfo.BoardType.ModelB_Rev2)) boardType = BOARD_TYPE_B;
133      else if(bt.equals(SystemInfo.BoardType.ModelB_Rev1)) boardType = BOARD_TYPE_B2;
134      else if(bt.equals(SystemInfo.BoardType.ModelA_Plus_Rev1)) boardType = BOARD_TYPE_APLUS;
135      else if(bt.equals(SystemInfo.BoardType.ModelA_Rev1)) boardType = BOARD_TYPE_A;
136      else boardType = DEFAULT_BOARD_TYPE;
137    }
138    catch (java.io.IOException ioEx)
139    {
140      boardType = DEFAULT_BOARD_TYPE;
141    }
142    catch (java.lang.InterruptedException iEx)
143    {
144      boardType = DEFAULT_BOARD_TYPE;
145    }
146  }
147
148
149  /** Stop all GPIO activity/threads by shutting down the GPIO controller.
150    * This method will forcefully shutdown all GPIO monitoring threads and scheduled tasks.
151    **/
152  public void shutdown()
153  {
154        // stop all GPIO activity/threads by shutting down the GPIO controller
155        // (this method will forcefully shutdown all GPIO monitoring threads and scheduled tasks)
156        gpio.shutdown();
157
158  }
159
160
161  /**
162    * Sets the 3 timing paramets based on optional commandline parameters - passed to this method in args[].
163    *
164    * @param args is the commandline args array
165    **/
166  protected void parseCommandlineParms(String [] args)
167  {
168      if (args!=null && args.length >0)
169      {
170        System.out.println("  > Override loopTime="+args[0]);
171        loopTime = Short.parseShort(args[0]);
172      }
173      if (args!=null && args.length >1)
174      {
175        System.out.println("  > Override duty cycleTime="+args[1]);
176        cycleTime = Short.parseShort(args[1]);
177      }
178      if (args!=null && args.length >2)
179      {
180        System.out.println("  > Override overlapTime="+args[2]);
181        overlapTime = Short.parseShort(args[2]);
182      }
183  }
184
185
186  /** Cycles ALL gpio pins on / off 2 times for 500ms each. **/
187  public void flashAllPins()  {  flashAllPins((short)2, (short)500); }
188
189
190  /** Cycles ALL gpio pins on / off numFlashes times with a duty time of flashTimeMS . **/
191  public void flashAllPins(short numFlashes, short flashTimeMS)
192  {
193    if (!allPinsProvisioned) provisionPins(true);
194    //enableAllPin();
195    for (short flashNum = 0;flashNum<numFlashes;flashNum++)
196    {
197      for (short i=0; i< pins.length; i++) gpioPins[i].low();
198      sleep(flashTimeMS);
199      System.out.print("ON...");
200      for (short i=0; i< pins.length; i++) gpioPins[i].high();
201      sleep(flashTimeMS);
202      System.out.println("OFF");
203      for (short i=0; i< pins.length; i++) gpioPins[i].low();
204      sleep(flashTimeMS);
205    }
206  }
207
208
209  /** figures out, sets the class Var endPin, and returns the array ref for the last ENABLED GPIO pin. **/
210  private int lastEnabledPinRef()
211  {
212    int lastEnabledPinRef = 0;
213    int i=0;
214    for (i=0; i< pins.length; i++)
215    {
216      if(enabledPins[i] && gpioPins[i]!=null)
217      {
218        lastEnabledPinRef = i;
219      }
220    }
221    setEndPin(pins[lastEnabledPinRef]);
222    return lastEnabledPinRef;
223  }
224
225
226  /** figures out, sets the class Var startPin, and returns the array ref for the FIRST ENABLED GPIO pin. **/
227  private int firstEnabledPinRef()
228  {
229    int firstEnabledPinRef = 0;
230    int i=0;
231    for (i=0; i< pins.length; i++)
232    {
233      if(enabledPins[i] && gpioPins[i]!=null)
234      {
235        firstEnabledPinRef = i;
236        break;
237      }
238    }
239    setStartPin(pins[firstEnabledPinRef]);
240    return firstEnabledPinRef;
241  }
242
243
244  /** Run the Cycling of te GPIO pins that have been defined, for the Class set loopTime (which defaults to DEFAULT_LOOP_TIME_MS if not set).    **/
245  public void cycle(){ cycle(loopTime);}
246
247
248  /** Run the Cycling of te GPIO pins that have been defined.
249    * @param loopTime is the length of time in ms to run the loop.
250    **/
251  public void cycle(int loopTime)
252  {
253    System.out.print("[");
254    for (short i=0; i< pins.length; i++) if(enabledPins[i]) System.out.print(pins[i]+((i<pins.length-1)?",":""));
255    System.out.println("]");
256    System.out.print(" ... ");
257    if(overlapTime<0) delayCycle(loopTime);
258    else overlapCycle(loopTime);
259    System.out.println("...done!");
260  }
261
262
263  /** This is the method that actually cyles the GPIO states - when overlapTime is positive - the LEDs overlap their ON,
264    * for the Class set loopTime (which defaults to DEFAULT_LOOP_TIME_MS if not set).    **/
265  public void overlapCycle(){ overlapCycle(loopTime);}
266
267
268  /** This is the method that actually cyles the GPIO states - when overlapTime is positive - the LEDs overlap their ON.
269    * @param loopTime is the length of time in ms to run the loop.
270    **/
271  public void overlapCycle(int loopTime)
272  {
273    int runTime = 0;
274    short currDelay = 0;
275    int lastEnabledPinRef = lastEnabledPinRef();
276    int firstEnabledPinRef = firstEnabledPinRef();
277    System.out.println(" overlapping: dutyCycleTime="+(cycleTime)+"ms   overlapTime="+(overlapTime)+"ms");
278
279    if(enabledPins[firstEnabledPinRef] && gpioPins[firstEnabledPinRef]!=null)
280    {
281      gpioPins[firstEnabledPinRef].high();
282          currDelay = (short)(overlapTime);
283          sleep(currDelay);
284          runTime+=currDelay;
285    }
286    while(loopTime==-1 || runTime<loopTime)
287    {
288      // loop through the GPIO cycling
289      for (short i=(short)firstEnabledPinRef; i< (short)lastEnabledPinRef; i++)
290      {
291        if(enabledPins[i] && gpioPins[i]!=null)
292        {
293          currDelay = (short)(cycleTime-(2*overlapTime));
294          sleep(currDelay);
295          runTime+=currDelay;
296          if(enabledPins[i+1] && gpioPins[i+1]!=null) gpioPins[i+1].high();
297
298          currDelay = (short)(overlapTime);
299          sleep(currDelay);
300          runTime+=currDelay;
301          gpioPins[i].low();
302        }
303      }
304
305      // Bounce at the end of the loop and go back
306      for (short i=(short)lastEnabledPinRef; i>(short)firstEnabledPinRef; i--)
307      {
308        if(enabledPins[i] && gpioPins[i]!=null)
309        {
310          currDelay = (short)(cycleTime-(2*overlapTime));
311          sleep(currDelay);
312          runTime+=currDelay;
313          if(enabledPins[i-1] && gpioPins[i-1]!=null) gpioPins[i-1].high();
314
315          currDelay = (short)(overlapTime);
316          sleep(currDelay);
317          runTime+=currDelay;
318          gpioPins[i].low();
319        }
320      }
321
322    } // while loop
323    gpioPins[firstEnabledPinRef].low();
324    System.out.println(" Completed in:"+ runTime +"ms");
325
326  }
327
328
329  /** This is the method that actually cyles the GPIO states - used when overlapTime is negative - there is a gap between the LEDs,
330    * for the Class set loopTime (which defaults to DEFAULT_LOOP_TIME_MS if not set).    **/
331  public void delayCycle(){ delayCycle(loopTime);}
332
333
334  /** This is the method that actually cyles the GPIO states - used when overlapTime is negative - there is a gap between the LEDs.
335    * @param loopTime is the length of time in ms to run the loop.
336    **/
337  public void delayCycle(int loopTime)
338  {
339    int runTime = 0;
340    short currDelay = 0;
341    int lastEnabledPinRef = lastEnabledPinRef();
342    int firstEnabledPinRef = firstEnabledPinRef();
343    System.out.println(" delay "+(-1*overlapTime));
344    while(loopTime==-1 || runTime<loopTime)
345    {
346      // fill in GPIO cycling
347      for (short i=(short)firstEnabledPinRef; i<= (short)lastEnabledPinRef; i++)
348      {
349        if(enabledPins[i] && gpioPins[i]!=null)
350        {
351          gpioPins[i].high();
352          currDelay = (short)cycleTime;
353          this.sleep(currDelay);
354          runTime+=currDelay;
355
356          gpioPins[i].low();
357          currDelay = (short)(-1*overlapTime);
358          this.sleep(currDelay);
359          runTime+=currDelay;
360        }
361      }
362      // Bounce at the end of the loop
363      currDelay = (short)(overlapTime);
364      this.sleep(currDelay);
365      runTime+=currDelay;
366      if(enabledPins[lastEnabledPinRef] && gpioPins[lastEnabledPinRef]!=null)gpioPins[lastEnabledPinRef].low();
367
368      for (short i=(short)(lastEnabledPinRef-1); i>=firstEnabledPinRef; i--)
369      {
370        if(enabledPins[i] && gpioPins[i]!=null)
371        {
372          gpioPins[i].high();
373          currDelay = cycleTime;
374          this.sleep(currDelay);
375          runTime+=currDelay;
376
377          gpioPins[i].low();
378          currDelay = (short)(-1*overlapTime);
379          this.sleep(currDelay);
380          runTime+=currDelay;
381        }
382      }
383      currDelay = (short)(-1*overlapTime);
384      this.sleep(currDelay);
385      runTime+=currDelay;
386    } // while loop
387
388  }
389
390  /** Mark a pin as DISABLED - it sets the class var that keeps track of which GPIO pins are enabled; 'enabledPins' to false.
391    * If the passed var 'pin' is NOT one of the available pins for the connected board, this method simply/silently does nothing.
392    * @param pin is the GPIO pin number to disable
393    **/
394  public void disablePin(short pin)
395  {
396    for (short i=0; i< pins.length; i++)
397    {
398      if(pins[i]==pin)
399      {
400        enabledPins[i] = false;
401        break;
402      }
403    }
404  }
405
406
407  /** Mark a pin as ENABLED - it sets the class var that keeps track of which GPIO pins are enabled; 'enabledPins' to true.
408    * If the passed var 'pin' is NOT one of the available pins for the connected board, this method simply/silently does nothing.
409    * @param pin is the GPIO pin number to enable
410    **/
411  public void enablePin(short pin)
412  {
413    for (short i=0; i< pins.length; i++)
414    {
415      if(pins[i]==pin)
416      {
417        enabledPins[i] = true;
418        break;
419      }
420    }
421  }
422
423
424  /** Mark all available pins for the active boardType as ENABLED - it sets the class var that keeps track of
425    * which GPIO pins are enabled; 'enabledPins' to true. **/
426  public void enableAllPin()
427  {
428    for (short i=0; i< pins.length; i++)
429    {
430        enabledPins[i] = true;
431    }
432  }
433
434
435  /**
436    * Set the boardType to use, must be one of the Class constants  BOARD_TYPE_*.
437    *
438    * @param boardType is the value to set this class field to.
439    *
440    * @return short - The value boardType if successful ELSE -1.
441    **/
442  public  short setBoardType(short boardType)
443  {
444    short retVal = -1;
445
446    if( boardType>=0 && boardType<=BOARD_TYPE_2)
447    {
448      this.boardType = boardType;
449      retVal = boardType;
450    }
451    return retVal;
452  }  // setBoardType Method
453
454
455  /**
456    * Get Method for class field 'boardType'.
457    *
458    * @return short - The boardType being used; will be one of the Class constants  BOARD_TYPE_*.
459    *
460    **/
461  public short getBoardType()
462  {
463    return boardType;
464  }  // getBoardType Method
465
466
467
468  /**
469    * Set Method for class field 'startPin'.
470    *
471    * @param pin is the value to set this class field to.
472    *
473    **/
474  public  void setStartPin(short pin)
475  {
476    this.startPin = pin;
477  }  // setStartPin Method
478
479
480  /**
481    * Get Method for class field 'startPin'.
482    *
483    * @return short - The value the class field 'startPin'.
484    *
485    **/
486  public short getStartPin()
487  {
488    return startPin;
489  }  // getStartPin Method
490
491
492  /**
493    * Set Method for class field 'endPin'.
494    *
495    * @param pin is the value to set this class field to.
496    *
497    **/
498  public  void setEndPin(short pin)
499  {
500    this.endPin = pin;
501  }  // setEndPin Method
502
503
504  /**
505    * Get Method for class field 'endPin'.
506    *
507    * @return short - The value the class field 'endPin'.
508    *
509    **/
510  public short getEndPin()
511  {
512    return endPin;
513  }  // getEndPin Method
514
515
516  /**
517    * Set Method for class field 'cycleTime'.
518    *
519    * @param cycleTime is the value to set this class field to.
520    *
521    **/
522  public  void setCycleTime(short cycleTime)
523  {
524    this.cycleTime = cycleTime;
525  }  // setCycleTime Method
526
527
528  /**
529    * Get Method for class field 'cycleTime'.
530    *
531    * @return short - The value the class field 'cycleTime'.
532    *
533    **/
534  public short getCycleTime()
535  {
536    return cycleTime;
537  }  // getCycleTime Method
538
539
540  /**
541    * Set Method for class field 'overlapTime'.
542    *
543    * @param overlapTime is the value to set this class field to.
544    *
545    **/
546  public  void setOverlapTime(short overlapTime)
547  {
548    this.overlapTime = overlapTime;
549  }  // setOverlapTime Method
550
551
552  /**
553    * Get Method for class field 'overlapTime'.
554    *
555    * @return short - The value the class field 'overlapTime'.
556    *
557    **/
558  public short getOverlapTime()
559  {
560    return overlapTime;
561  }  // getOverlapTime Method
562
563
564  /**
565    * Set Method for class field 'pins' that represents the GPIO pin numbers on the board.
566    *
567    * @param short[] is the value to set this class field pinsto.
568    *
569    **/
570  public  void setPins(short[] pins)
571  {
572    this.pins = pins;
573  }  // setPins Method
574
575
576  /**
577    * Get Method for class field '[]'.
578    *
579    * @return short - The value the class field '[]'.
580    *
581    **/
582  public short[] getPins()
583  {
584    return pins;
585  }  // getPins[] Method
586
587
588  private short getEnabledPinCount()
589  {
590    short pinCount = 0;
591    for (short i=0; i< pins.length; i++) if(enabledPins[i]) pinCount++;
592    return pinCount;
593  }
594
595
596  /** RaspiPINS have names of the form 'GPIO 4' or 'GPIO 12'.
597    * @param pin is the Pi4j (wiringPI) pin number.
598    **/
599  private Pin getRaspiPin(short pin)
600  {
601    Pin retVal = null;
602    String pinName = "GPIO ";
603    /*
604    if(pin>0 && pin<10)
605    {
606      pinName += "0"+pin;
607      retVal = RaspiPin.getPinByName(pinName);
608    }
609    else if(pin>9)
610    */
611   // {
612      pinName += ""+pin;
613      retVal = RaspiPin.getPinByName(pinName);
614   // }
615    return retVal;
616  }
617
618
619  /** provisions and returns a Gpio Outpout Pin with the DEFAULT state. **/
620  private GpioPinDigitalOutput provisionOutputPin(short pin)
621  {
622    return provisionOutputPin(pin, DEFAULT_PINSTATE);
623  }
624
625
626  /** provisions and returns a Gpio Outpout Pin. **/
627  private GpioPinDigitalOutput provisionOutputPin(short pin, PinState pinState)
628  {
629    GpioPinDigitalOutput gpioPin = null;
630    if( pin>=pins[0] && pin<=pins[pins.length-1])
631    {
632      gpioPin = gpio.provisionDigitalOutputPin(getRaspiPin(pin), DEFAULT_PINSTATE);
633    }
634    return gpioPin;
635  }
636
637
638  /** provisions ALL enabled pins and puts them in the class var gpioPins. **/
639  private GpioPinDigitalOutput[] provisionPins(){return provisionPins(false);}
640
641
642  /** provisions (according to passed flag) pins and puts them in the class var gpioPins.
643    *
644    * @param boolean controls if all pins are provisioned for only those that are enabled in enabledPins class var.
645    *
646    **/
647  private GpioPinDigitalOutput[] provisionPins(boolean doAll)
648  {
649    if(!allPinsProvisioned)
650    {
651      System.out.print("[");
652      for (short i=0; i< pins.length; i++)
653      {
654        if(doAll || enabledPins[i])
655        {
656          System.out.print(pins[i]+((i<pins.length-1)?",":""));
657          gpioPins[i] = provisionOutputPin(pins[i]);
658        }
659      }
660    }
661    System.out.println("]");
662    allPinsProvisioned = (allPinsProvisioned || doAll);
663    return gpioPins;
664  }
665
666
667  /** The main entrance to this class.
668    *<pre>
669    *--------------------------------------------------------------------------------
670    * Java Raspberry PI  - GpioCycler
671    * Copyright (C) 2015 - Tom B. Gutwin
672    *--------------------------------------------------------------------------------
673    *Syntax:
674    *java ca.bc.webarts.raspberry.GpioCycler [loopTime [dutyCycleTime [overlapTime]]]
675    *     where the 3 OPTIONAL parameters are:
676    *           loopTime      time in milliSeconds to run the looping (default=DEFAULT_LOOP_TIME_MS ms)
677    *                         (default=DEFAULT_LOOP_TIME_MS ms)
678    *           dutyCycleTime time in milliSeconds the GPIOs stays in the 'ON' state
679    *                         (default=DEFAULT_CYCLE_TIME_MS ms)
680    *           overlapTime   time in milliSeconds the next/following GPIO will turn
681    *                         'ON' before the previous GPIO turns 'OFF'
682    *                         (default=DEFAULT_OVERLAP_TIME_MS ms)
683    * </pre>
684    **/
685  public static void main(String [] args) throws InterruptedException
686  {
687    GpioCycler instance = new GpioCycler();
688    if (args==null || args.length == 0)
689    {
690      System.out.println("--------------------------------------------------------------------------------");
691      System.out.println(" Java Raspberry PI  - GpioCycler  ");
692      System.out.println(" Copyright (C) 2015 - Tom B. Gutwin  ");
693      System.out.println("--------------------------------------------------------------------------------");
694      System.out.println("Syntax:");
695      System.out.println("java ca.bc.webarts.raspberry.GpioCycler [loopTime [dutyCycleTime [overlapTime]]]");
696      System.out.println("     where the 3 OPTIONAL parameters are:");
697      System.out.println("           loopTime      time in milliSeconds to run the looping (default="+DEFAULT_LOOP_TIME_MS+"ms)");
698      System.out.println("                         (default="+DEFAULT_LOOP_TIME_MS+"ms)");
699      System.out.println("           dutyCycleTime time in milliSeconds the GPIOs stays in the 'ON' state ");
700      System.out.println("                         (default="+DEFAULT_CYCLE_TIME_MS+"ms)");
701      System.out.println("           overlapTime   time in milliSeconds the next/following GPIO will turn");
702      System.out.println("                         'ON' before the previous GPIO turns 'OFF' ");
703      System.out.println("                         (default="+DEFAULT_OVERLAP_TIME_MS+"ms)");
704      System.out.println("--------------------------------------------------------------------------------");
705    }
706    //else
707    {
708      instance.parseCommandlineParms(args);
709      System.out.println("<Provisioning All GPIO pins>");
710      instance.provisionPins(true);
711
712      System.out.println("<TESTING All GPIO pins>");
713      instance.flashAllPins();
714      System.out.println("<Cycling GPIO pins>");
715      instance.cycle();
716    }
717
718    instance.shutdown();
719
720  }
721
722  /**
723   *  A method to simply abstract the Try/Catch required to put the current
724   *  thread to sleep for the specified time in ms.
725   *
726   * @param  waitTime  the sleep time in milli seconds (ms).
727   * @return boolean value specifying if the sleep completed (true) or was interupted (false).
728   */
729  public static boolean sleep(long waitTime)
730  {
731    boolean retVal = true;
732    if (waitTime<0)
733      retVal=false;
734    else
735    {
736      /*
737       *  BLOCK for the spec'd time
738       */
739      try
740      {
741        Thread.sleep(waitTime);
742      }
743      catch (InterruptedException iex)
744      {
745        retVal = false;
746      }
747    }
748    return retVal;
749  }
750
751
752
753}