001package com.pi4j.io.gpio.impl;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  GpioControllerImpl.java  
009 * 
010 * This file is part of the Pi4J project. More information about 
011 * this project can be found here:  http://www.pi4j.com/
012 * **********************************************************************
013 * %%
014 * Copyright (C) 2012 - 2015 Pi4J
015 * %%
016 * This program is free software: you can redistribute it and/or modify
017 * it under the terms of the GNU Lesser General Public License as
018 * published by the Free Software Foundation, either version 3 of the
019 * License, or (at your option) any later version.
020 * 
021 * This program is distributed in the hope that it will be useful,
022 * but WITHOUT ANY WARRANTY; without even the implied warranty of
023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
024 * GNU General Lesser Public License for more details.
025 * 
026 * You should have received a copy of the GNU General Lesser Public
027 * License along with this program.  If not, see
028 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
029 * #L%
030 */
031
032import com.pi4j.io.gpio.*;
033import com.pi4j.io.gpio.event.GpioPinListener;
034import com.pi4j.io.gpio.exception.GpioPinExistsException;
035import com.pi4j.io.gpio.exception.GpioPinNotProvisionedException;
036import com.pi4j.io.gpio.trigger.GpioTrigger;
037
038import java.util.ArrayList;
039import java.util.Collection;
040import java.util.Collections;
041import java.util.List;
042
043public class GpioControllerImpl implements GpioController {
044
045    private final List<GpioPin> pins = Collections.synchronizedList(new ArrayList<GpioPin>());
046    private final GpioProvider defaultProvider;
047    private boolean isshutdown = false;
048    
049    /**
050     * Default Constructor
051     */
052    public GpioControllerImpl() {
053        // set the local default provider reference
054        this(GpioFactory.getDefaultProvider());                
055    }
056
057    /**
058     * Default Constructor
059     */
060    public GpioControllerImpl(GpioProvider provider) {
061        // set the local default provider reference
062        defaultProvider = provider;                
063
064        // register shutdown callback hook class
065        Runtime.getRuntime().addShutdownHook(new ShutdownHook());        
066    }
067    
068    @Override
069    public Collection<GpioPin> getProvisionedPins() {
070        return pins;
071    }
072    
073    @Override
074    public void unexportAll() {
075        // un-export all GPIO pins that are currently exported
076        for (GpioPin pin : pins) { 
077            if (pin.isExported()) {
078                pin.unexport();
079            }
080        }
081    }
082
083    @Override
084    public void export(PinMode mode, GpioPin... pin) {
085        export(mode, null, pin);
086    }
087
088    @Override
089    public void export(PinMode mode, PinState defaultState, GpioPin... pin){
090        if (pin == null || pin.length == 0) {
091            throw new IllegalArgumentException("Missing pin argument.");
092        }
093        for (GpioPin p : pin) {
094            // ensure the requested pin has been provisioned
095            if (!pins.contains(p)) {
096                throw new GpioPinNotProvisionedException(p.getPin());
097            }
098            // export the pin
099            p.export(mode, defaultState);
100        }
101    }
102
103    /**
104     * 
105     * @param pin
106     * @return <p>
107     *         A value of 'true' is returned if the requested pin is exported.
108     *         </p>
109     */
110    @Override
111    public boolean isExported(GpioPin... pin) {
112        if (pin == null || pin.length == 0) {
113            throw new IllegalArgumentException("Missing pin argument.");
114        }
115        for (GpioPin p : pin) {
116            // ensure the requested pin has been provisioned
117            if (!pins.contains(pin)) {
118                throw new GpioPinNotProvisionedException(p.getPin());
119            }
120            if (!p.isExported()) {
121                return false;
122            }
123        }
124
125        // return the pin exported state
126        return true;
127    }
128
129    @Override
130    public void unexport(GpioPin... pin) {
131        if (pin == null || pin.length == 0) {
132            throw new IllegalArgumentException("Missing pin argument.");
133        }
134        for (GpioPin p : pin) {
135            // ensure the requested pin has been provisioned
136            if (!pins.contains(p)) {
137                throw new GpioPinNotProvisionedException(p.getPin());
138            }
139            // unexport the pin
140            p.unexport();            
141        }
142    }
143
144    @Override
145    public PinMode getMode(GpioPin pin) {
146        // ensure the requested pin has been provisioned
147        if (!pins.contains(pin)) {
148            throw new GpioPinNotProvisionedException(pin.getPin());
149        }
150        // return pin edge setting
151        return pin.getMode();    
152    }
153
154    @Override
155    public boolean isMode(PinMode mode, GpioPin... pin) {
156        if (pin == null || pin.length == 0) {
157            throw new IllegalArgumentException("Missing pin argument.");
158        }
159        for (GpioPin p : pin) {
160            if (!p.isMode(mode)) {
161                return false;
162            }
163        }
164        return true;  
165    }
166
167    @Override
168    public void setMode(PinMode mode, GpioPin... pin) {
169        if (pin == null || pin.length == 0) {
170            throw new IllegalArgumentException("Missing pin argument.");
171        }
172        for (GpioPin p : pin) {
173            // ensure the requested pin has been provisioned
174            if (!pins.contains(pin)) {
175                throw new GpioPinNotProvisionedException(p.getPin());
176            }
177            // set pin mode
178            p.setMode(mode);        
179        }
180    }
181
182    @Override
183    public void setPullResistance(PinPullResistance resistance, GpioPin... pin) {
184        if (pin == null || pin.length == 0) {
185            throw new IllegalArgumentException("Missing pin argument.");
186        }
187        for (GpioPin p : pin) {
188            // ensure the requested pin has been provisioned
189            if (!pins.contains(p)) {
190                throw new GpioPinNotProvisionedException(p.getPin());
191            }
192            // set pin pull resistance
193            p.setPullResistance(resistance);
194        }
195    }
196
197    @Override
198    public PinPullResistance getPullResistance(GpioPin pin) {
199        // ensure the requested pin has been provisioned
200        if (!pins.contains(pin)) {
201            throw new GpioPinNotProvisionedException(pin.getPin());
202        }
203        // get pin pull resistance
204        return pin.getPullResistance();
205    }
206
207    @Override
208    public boolean isPullResistance(PinPullResistance resistance, GpioPin... pin) {
209        if (pin == null || pin.length == 0) {
210            throw new IllegalArgumentException("Missing pin argument.");
211        }
212        for (GpioPin p : pin) {
213            // ensure the requested pin has been provisioned
214            if (!pins.contains(p)) {
215                throw new GpioPinNotProvisionedException(p.getPin());
216            }
217            // set pin pull resistance
218            if(!p.isPullResistance(resistance))
219                return false;
220        }
221
222        return true;
223    }
224    
225    @Override
226    public void high(GpioPinDigitalOutput... pin) {
227        if (pin == null || pin.length == 0) {
228            throw new IllegalArgumentException("Missing pin argument.");
229        }
230        // ensure the requested pin has been provisioned
231        for (GpioPinDigitalOutput p : pin) {
232            if (!pins.contains(pin)) {
233                throw new GpioPinNotProvisionedException(p.getPin());
234            }
235            // set pin state high
236            p.high();        
237        }
238    }
239
240    @Override
241    public void low(GpioPinDigitalOutput... pin) {
242        if (pin == null || pin.length == 0) {
243            throw new IllegalArgumentException("Missing pin argument.");
244        }
245        // ensure the requested pin has been provisioned
246        for (GpioPinDigitalOutput p : pin) {
247            if (!pins.contains(p)) {
248                throw new GpioPinNotProvisionedException(p.getPin());
249            }
250            // set pin state low
251            p.low();            
252        }
253    }
254
255    @Override
256    public boolean isHigh(GpioPinDigital... pin) {
257        if (pin == null || pin.length == 0) {
258            throw new IllegalArgumentException("Missing pin argument.");
259        }
260        for (GpioPinDigital p : pin) {
261            if (p.isLow()) {
262                return false;
263            }
264        }
265        return true;        
266    }
267
268    @Override
269    public boolean isLow(GpioPinDigital... pin) {
270        if (pin == null || pin.length == 0) {
271            throw new IllegalArgumentException("Missing pin argument.");
272        }
273        for (GpioPinDigital p : pin) {
274            if (p.isHigh()) {
275                return false;
276            }
277        }
278        return true;                
279    }
280
281    @Override
282    public void toggle(GpioPinDigitalOutput... pin) {
283        if (pin == null || pin.length == 0) {
284            throw new IllegalArgumentException("Missing pin argument.");
285        }
286        for (GpioPinDigitalOutput p : pin) {
287            // ensure the requested pin has been provisioned
288            if (!pins.contains(p)) {
289                throw new GpioPinNotProvisionedException(p.getPin());
290            }
291            // toggle pin state
292            p.toggle();
293        }
294    }
295
296    @Override
297    public void pulse(long milliseconds, GpioPinDigitalOutput... pin) {
298        if (pin == null || pin.length == 0) {
299            throw new IllegalArgumentException("Missing pin argument.");
300        }
301        for (GpioPinDigitalOutput p : pin) {
302            // ensure the requested pin has been provisioned
303            if (!pins.contains(p)) {
304                throw new GpioPinNotProvisionedException(p.getPin());
305            }    
306            // toggle pin state
307            p.pulse(milliseconds);
308        }
309    }
310
311    @Override
312    public void setState(PinState state, GpioPinDigitalOutput... pin) {
313        if (pin == null || pin.length == 0) {
314            throw new IllegalArgumentException("Missing pin argument.");
315        }
316        for (GpioPinDigitalOutput p : pin) {
317            // ensure the requested pin has been provisioned
318            if (!pins.contains(p)) {
319                throw new GpioPinNotProvisionedException(p.getPin());
320            }
321            // set pin state
322            p.setState(state);
323        }
324    }
325
326    @Override
327    public void setState(boolean state, GpioPinDigitalOutput... pin) {
328        setState((state) ? PinState.HIGH : PinState.LOW, pin);
329    }
330
331    @Override
332    public PinState getState(GpioPinDigital pin) {
333        // ensure the requested pin has been provisioned
334        if (!pins.contains(pin)) {
335            throw new GpioPinNotProvisionedException(pin.getPin());
336        }
337        // return pin state
338        return pin.getState();
339    }    
340
341    @Override
342    public boolean isState(PinState state, GpioPinDigital... pin) {
343        if (pin == null || pin.length == 0) {
344            throw new IllegalArgumentException("Missing pin argument.");
345        }
346        for (GpioPinDigital p : pin) {
347            if (!p.isState(state)) {
348                return false;
349            }
350        }
351        return true;     
352    }
353    
354    @Override
355    public void setValue(double value, GpioPinAnalogOutput... pin) {
356        if (pin == null || pin.length == 0) {
357            throw new IllegalArgumentException("Missing pin argument.");
358        }
359        for (GpioPinAnalogOutput p : pin) {
360            // ensure the requested pin has been provisioned
361            if (!pins.contains(p)) {
362                throw new GpioPinNotProvisionedException(p.getPin());
363            }
364            // set pin PWM value
365            p.setValue(value);
366        }        
367    }
368
369    @Override
370    public double getValue(GpioPinAnalog pin) {
371        return pin.getValue();
372    }    
373
374     @Override
375    public synchronized void addListener(GpioPinListener listener, GpioPinInput... pin) {
376        if (pin == null || pin.length == 0) {
377            throw new IllegalArgumentException("Missing pin argument.");
378        }
379        for (GpioPinInput p : pin) {
380            // ensure the requested pin has been provisioned
381            if (!pins.contains(p)) {
382                throw new GpioPinNotProvisionedException(p.getPin());        
383            }
384            p.addListener(listener);
385        }
386    }
387
388    @Override
389    public synchronized void addListener(GpioPinListener[] listeners, GpioPinInput... pin) {
390        if (pin == null || pin.length == 0) {
391            throw new IllegalArgumentException("Missing pin argument.");
392        }
393        for (GpioPinListener listener: listeners) {
394            addListener(listener, pin);
395        }
396    }
397
398
399    @Override
400    public synchronized void removeListener(GpioPinListener listener, GpioPinInput... pin) {
401        if (pin == null || pin.length == 0) {
402            throw new IllegalArgumentException("Missing pin argument.");
403        }
404        for (GpioPinInput p : pin) {
405            // ensure the requested pin has been provisioned
406            if (!pins.contains(p)) {
407                throw new GpioPinNotProvisionedException(p.getPin());
408            }
409            p.removeListener(listener);
410        }
411    }
412
413    @Override
414    public synchronized void removeListener(GpioPinListener[] listeners, GpioPinInput... pin) {
415        if(pin == null || pin.length == 0) {
416            throw new IllegalArgumentException("Missing pin argument.");
417        }
418        for (GpioPinListener listener : listeners) {
419            removeListener(listener, pin);
420        }
421    }
422
423    @Override
424    public synchronized void removeAllListeners() {
425        for (GpioPin pin : this.pins) {
426            if (pin instanceof GpioPinInput) {
427                ((GpioPinInput)pin).removeAllListeners();
428            }
429        }
430    }
431
432    @Override
433    public synchronized void addTrigger(GpioTrigger trigger, GpioPinInput... pin) {
434        if (pin == null || pin.length == 0) {
435            throw new IllegalArgumentException("Missing pin argument.");
436        }
437        for (GpioPinInput p : pin) {
438            // ensure the requested pin has been provisioned
439            if (!pins.contains(p)) {
440                throw new GpioPinNotProvisionedException(p.getPin());
441            }
442            p.addTrigger(trigger);
443        }        
444    }
445
446    @Override
447    public synchronized void addTrigger(GpioTrigger[] triggers, GpioPinInput... pin) {
448        if (pin == null || pin.length == 0) {
449            throw new IllegalArgumentException("Missing pin argument.");
450        }
451        for (GpioTrigger trigger : triggers) {
452            addTrigger(trigger, pin);
453        }
454    }
455    
456    @Override
457    public synchronized void removeTrigger(GpioTrigger trigger, GpioPinInput... pin) {
458        if (pin == null || pin.length == 0) {
459            throw new IllegalArgumentException("Missing pin argument.");
460        }
461        for (GpioPinInput p : pin) {
462            // ensure the requested pin has been provisioned
463            if (!pins.contains(p)) {
464                throw new GpioPinNotProvisionedException(p.getPin());
465            }
466            p.removeTrigger(trigger);
467        }
468    }
469
470    @Override
471    public synchronized void removeTrigger(GpioTrigger[] triggers, GpioPinInput... pin) {
472        if (pin == null || pin.length == 0) {
473            throw new IllegalArgumentException("Missing pin argument.");
474        }
475        for (GpioTrigger trigger : triggers) {
476            removeTrigger(trigger, pin);
477        }
478    }
479
480    @Override
481    public synchronized void removeAllTriggers() {
482        for (GpioPin pin : this.pins) {
483            if (pin instanceof GpioPinInput) {
484                ((GpioPinInput)pin).removeAllTriggers();            
485            }
486        }
487    }
488    
489    @Override
490    public GpioPin provisionPin(GpioProvider provider, Pin pin, PinMode mode) {
491        return provisionPin(provider, pin, pin.getName(), mode);
492    }
493
494    @Override
495    public GpioPin provisionPin(GpioProvider provider, Pin pin, String name, PinMode mode) {
496        return provisionPin(provider, pin, name, mode, null);
497    }
498
499    @Override
500    public GpioPin provisionPin(GpioProvider provider, Pin pin, String name, PinMode mode, PinState defaultState) {
501        // if an existing pin has been previously created, then throw an error
502        for(GpioPin p : pins) {
503            if (p.getProvider().equals(provider) && p.getPin().equals(pin)) {
504                throw new GpioPinExistsException(pin);
505            }
506        }
507
508        // create new GPIO pin instance
509        GpioPin gpioPin = new GpioPinImpl(this, provider, pin);
510
511        // set the gpio pin name
512        if (name != null) {
513            gpioPin.setName(name);
514        }
515
516        // export this pin 
517        gpioPin.export(mode, defaultState);
518
519        // add this new pin instance to the managed collection
520        pins.add(gpioPin);
521
522        // return new new pin instance
523        return gpioPin;
524    }
525
526    @Override
527    public GpioPin provisionPin(Pin pin, String name, PinMode mode) {
528        return provisionPin(defaultProvider, pin, name, mode);
529    }
530
531    @Override
532    public GpioPin provisionPin(Pin pin, PinMode mode) {
533        return provisionPin(defaultProvider, pin, mode);
534    }
535    
536    @Override
537    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, String name, PinMode mode) {
538        // return new new pin instance
539        return (GpioPinDigitalMultipurpose)provisionPin(provider, pin, name, mode);
540    }
541
542    @Override
543    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, PinMode mode) {
544        // return new new pin instance
545        return (GpioPinDigitalMultipurpose)provisionPin(provider, pin, mode);
546    }
547    
548    @Override
549    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, String name, PinMode mode) {
550        return provisionDigitalMultipurposePin(defaultProvider, pin, name, mode);
551    }
552    
553    @Override
554    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, PinMode mode) {
555        return provisionDigitalMultipurposePin(defaultProvider, pin, mode);
556    }
557
558    @Override
559    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, PinMode mode, PinPullResistance resistance) {
560        // create new GPIO pin instance
561        return provisionDigitalMultipurposePin(provider, pin, pin.getName(), mode, resistance);
562    }
563    
564    @Override
565    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, String name, PinMode mode, PinPullResistance resistance) {
566        // create new GPIO pin instance
567        GpioPinDigitalMultipurpose gpioPin = provisionDigitalMultipurposePin(provider, pin, name, mode);
568
569        // set the gpio pull resistor
570        if (resistance != null) {
571            gpioPin.setPullResistance(resistance);
572        }
573        // return new new pin instance
574        return gpioPin;
575    }
576
577    @Override
578    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, String name, PinMode mode, PinPullResistance resistance) {
579        return provisionDigitalMultipurposePin(defaultProvider, pin, name, mode, resistance);
580    }
581
582    @Override
583    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, PinMode mode, PinPullResistance resistance) {
584        return provisionDigitalMultipurposePin(defaultProvider, pin, mode, resistance);
585    }
586    
587    
588    @Override
589    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, String name) {
590        // return new new pin instance
591        return (GpioPinDigitalInput)provisionPin(provider, pin, name, PinMode.DIGITAL_INPUT);
592    }
593
594    @Override
595    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin) {
596        // return new new pin instance
597        return (GpioPinDigitalInput)provisionPin(provider, pin, PinMode.DIGITAL_INPUT);
598    }
599    
600    @Override
601    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, String name) {
602        return provisionDigitalInputPin(defaultProvider, pin, name);
603    }
604    
605    @Override
606    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin) {
607        return provisionDigitalInputPin(defaultProvider, pin);
608    }
609
610    @Override
611    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, PinPullResistance resistance) {
612        // create new GPIO pin instance
613        return provisionDigitalInputPin(provider, pin, pin.getName(), resistance);
614    }
615    
616    @Override
617    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, String name, PinPullResistance resistance) {
618        // create new GPIO pin instance
619        GpioPinDigitalInput gpioPin = provisionDigitalInputPin(provider, pin, name);
620
621        // set the gpio pull resistor
622        if (resistance != null) {
623            gpioPin.setPullResistance(resistance);
624        }
625        // return new new pin instance
626        return gpioPin;
627    }
628
629    @Override
630    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, String name, PinPullResistance resistance) {
631        return provisionDigitalInputPin(defaultProvider, pin, name, resistance);
632    }
633
634    @Override
635    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, PinPullResistance resistance) {
636        return provisionDigitalInputPin(defaultProvider, pin, resistance);
637    }
638    
639    @Override
640    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, String name) {
641        // return new new pin instance
642        return (GpioPinDigitalOutput)provisionPin(provider, pin, name, PinMode.DIGITAL_OUTPUT);
643    }
644
645    @Override
646    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin) {
647        // return new new pin instance
648        return (GpioPinDigitalOutput)provisionPin(provider, pin, PinMode.DIGITAL_OUTPUT);
649    }
650    
651    @Override
652    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, String name) {
653        return provisionDigitalOutputPin(defaultProvider, pin, name);
654    }
655
656    @Override
657    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin) {
658        return provisionDigitalOutputPin(defaultProvider, pin);
659    }
660
661    @Override
662    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, PinState defaultState) {
663        return provisionDigitalOutputPin(provider, pin, pin.getName(), defaultState);
664    }
665    
666    @Override
667    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, String name, PinState defaultState) {
668        // create new GPIO pin instance
669        GpioPinDigitalOutput gpioPin = (GpioPinDigitalOutput)provisionPin(provider, pin, name, PinMode.DIGITAL_OUTPUT, defaultState);
670
671        // apply default state
672        if (defaultState != null) {
673            gpioPin.setState(defaultState);
674        }
675        // return new new pin instance
676        return gpioPin;
677    }
678
679    @Override
680    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, String name, PinState defaultState) {
681        return provisionDigitalOutputPin(defaultProvider, pin, name, defaultState);
682    }
683
684    @Override
685    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, PinState defaultState) {
686        return provisionDigitalOutputPin(defaultProvider, pin, defaultState);
687    }
688    
689    @Override
690    public GpioPinAnalogInput provisionAnalogInputPin(GpioProvider provider, Pin pin, String name) {
691        // return new new pin instance
692        return (GpioPinAnalogInput)provisionPin(provider, pin, name, PinMode.ANALOG_INPUT);
693    }
694
695    @Override
696    public GpioPinAnalogInput provisionAnalogInputPin(GpioProvider provider, Pin pin) {
697        // return new new pin instance
698        return (GpioPinAnalogInput)provisionPin(provider, pin, PinMode.ANALOG_INPUT);
699    }
700    
701    @Override
702    public GpioPinAnalogInput provisionAnalogInputPin(Pin pin, String name) {
703        return provisionAnalogInputPin(defaultProvider, pin, name);
704    }
705
706    @Override
707    public GpioPinAnalogInput provisionAnalogInputPin(Pin pin) {
708        return provisionAnalogInputPin(defaultProvider, pin);
709    }
710    
711    @Override
712    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, String name) {
713        // return new new pin instance
714        return (GpioPinAnalogOutput)provisionPin(provider, pin, name, PinMode.ANALOG_OUTPUT);
715    }
716
717    @Override
718    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin) {
719        // return new new pin instance
720        return (GpioPinAnalogOutput)provisionPin(provider, pin, PinMode.ANALOG_OUTPUT);
721    }
722    
723    @Override
724    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, String name) {
725        return provisionAnalogOutputPin(defaultProvider, pin, name);
726    }
727
728    @Override
729    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin) {
730        return provisionAnalogOutputPin(defaultProvider, pin);
731    }
732
733    @Override
734    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, double defaultValue) {
735        return provisionAnalogOutputPin(provider, pin, pin.getName(), defaultValue);
736    }
737    
738    @Override
739    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, String name, double defaultValue) {
740        // create new GPIO pin instance
741        GpioPinAnalogOutput gpioPin = provisionAnalogOutputPin(provider, pin, name);
742
743        // apply default value
744        gpioPin.setValue(defaultValue);
745
746        // return new new pin instance
747        return gpioPin;
748    }
749
750    @Override
751    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, String name, double defaultValue) {
752        return provisionAnalogOutputPin(defaultProvider, pin, name, defaultValue);
753    }
754
755    @Override
756    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, double defaultValue) {
757        return provisionAnalogOutputPin(defaultProvider, pin, defaultValue);
758    }
759    
760    @Override
761    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, String name) {
762        // return new new pin instance
763        return (GpioPinPwmOutput)provisionPin(provider, pin, name, PinMode.PWM_OUTPUT);
764    }
765
766    @Override
767    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin) {
768        // return new new pin instance
769        return (GpioPinPwmOutput)provisionPin(provider, pin, PinMode.PWM_OUTPUT);
770    }
771    
772    @Override
773    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, String name) {
774        return provisionPwmOutputPin(defaultProvider, pin, name);
775    }
776
777    @Override
778    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin) {
779        return provisionPwmOutputPin(defaultProvider, pin);
780    }
781
782    @Override
783    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, int defaultValue) {
784        return provisionPwmOutputPin(provider, pin, pin.getName(), defaultValue);
785    }
786    
787    @Override
788    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, String name, int defaultValue) {
789        // create new GPIO pin instance
790        GpioPinPwmOutput gpioPin = provisionPwmOutputPin(provider, pin, name);
791
792        // apply default value
793        gpioPin.setPwm(defaultValue);
794
795        // return new new pin instance
796        return gpioPin;
797    }
798    
799    @Override
800    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, String name, int defaultValue) {
801        return provisionPwmOutputPin(defaultProvider, pin, name, defaultValue);
802    }
803
804    @Override
805    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, int defaultValue) {
806        return provisionPwmOutputPin(defaultProvider, pin, defaultValue);
807    }
808    
809    @Override
810    public void unprovisionPin(GpioPin... pin) {
811        if (pin == null || pin.length == 0) {
812            throw new IllegalArgumentException("Missing pin argument.");
813        }
814        for (int index = (pin.length-1); index >= 0; index--) {
815            GpioPin p  = pin[index];
816            
817            // ensure the requested pin has been provisioned
818            if (!pins.contains(p)) {
819                throw new GpioPinNotProvisionedException(p.getPin());
820            }
821            // remove all listeners and triggers
822            if (p instanceof GpioPinInput) {
823                ((GpioPinInput)p).removeAllListeners();
824                ((GpioPinInput)p).removeAllTriggers();
825            }
826            
827            // remove this pin instance from the managed collection
828            pins.remove(p);
829        }        
830    }
831    
832    public void setShutdownOptions(GpioPinShutdown options, GpioPin... pin) {
833        for (GpioPin p : pin) {
834            if (!pins.contains(p)) {
835                throw new GpioPinNotProvisionedException(p.getPin());
836            }
837            p.setShutdownOptions(options);
838        }  
839    }
840    
841    public void setShutdownOptions(Boolean unexport, GpioPin... pin) {
842        for (GpioPin p : pin) {
843            if (!pins.contains(p)) {
844                throw new GpioPinNotProvisionedException(p.getPin());
845            }
846            p.setShutdownOptions(unexport);
847        }          
848    }
849    
850    public void setShutdownOptions(Boolean unexport, PinState state, GpioPin... pin) {
851        for (GpioPin p : pin) {
852            if (!pins.contains(p)) {
853                throw new GpioPinNotProvisionedException(p.getPin());
854            }
855            p.setShutdownOptions(unexport, state);
856        }          
857    }
858    
859    public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance, GpioPin... pin) {
860        for (GpioPin p : pin) {
861            if (!pins.contains(p)) {
862                throw new GpioPinNotProvisionedException(p.getPin());
863            }
864            p.setShutdownOptions(unexport, state, resistance);
865        }          
866    }
867    
868    public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance, PinMode mode, GpioPin... pin) {
869        for (GpioPin p : pin) {
870            if (!pins.contains(p)) {
871                throw new GpioPinNotProvisionedException(p.getPin());
872            }
873            p.setShutdownOptions(unexport, state, resistance, mode);
874        }                  
875    }
876
877    
878    /**
879     * This class is used to perform any configured shutdown actions
880     * on the provisioned GPIO pins
881     * 
882     * @author Robert Savage
883     *
884     */
885    private class ShutdownHook extends Thread { 
886        public void run() {
887            // perform shutdown
888            shutdown();
889        }
890    }
891    
892    /**
893     * This method returns TRUE if the GPIO controller has been shutdown.
894     * 
895     * @return shutdown state
896     */
897    @Override
898    public boolean isShutdown(){
899        return isshutdown;
900    }
901
902    
903    /**
904     * This method can be called to forcefully shutdown all GPIO controller
905     * monitoring, listening, and task threads/executors.
906     */
907    @Override
908    public synchronized void shutdown()
909    {
910        // prevent reentrant invocation
911        if(isShutdown())
912            return;
913        
914        // shutdown all executor services
915        //
916        // NOTE: we are not permitted to access the shutdown() method of the individual 
917        // executor services, we must perform the shutdown with the factory
918        GpioFactory.getExecutorServiceFactory().shutdown();
919        
920        // shutdown explicit configured GPIO pins
921        for (GpioPin pin : pins) {
922            
923            // perform a shutdown on the GPIO provider for this pin
924            if(!pin.getProvider().isShutdown()){
925                pin.getProvider().shutdown();
926            }
927            
928            // perform the shutdown options if configured for the pin
929            GpioPinShutdown shutdownOptions = pin.getShutdownOptions(); 
930            if (shutdownOptions != null) {
931                // get shutdown option configuration 
932                PinState state = shutdownOptions.getState();
933                PinMode mode = shutdownOptions.getMode();
934                PinPullResistance resistance = shutdownOptions.getPullResistor();
935                Boolean unexport = shutdownOptions.getUnexport();
936                
937                // perform shutdown actions
938                if ((state != null) && (pin instanceof GpioPinDigitalOutput)) {
939                    ((GpioPinDigitalOutput)pin).setState(state);
940                }
941                if (resistance != null) {
942                    pin.setPullResistance(resistance);
943                }
944                if (mode != null) {
945                    pin.setMode(mode);
946                }
947                if (unexport != null && unexport == Boolean.TRUE) {
948                    pin.unexport();
949                }
950            }
951        }
952        
953        // set is shutdown tracking variable
954        isshutdown = true;
955    }
956}