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