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