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