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 - 2021 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        GpioPin gpioPin;
545
546        // if the provider does not match the pin's provider then throw an error
547        if (!Objects.equals(provider.getName(), pin.getProvider())) {
548            throw new PinProviderException(provider, pin);
549        }
550
551        synchronized(this) {
552            // if an existing pin has been previously created, then throw an error
553            for (GpioPin p : pins) {
554                if (Objects.equals(p.getProvider(), provider) && Objects.equals(p.getPin(), pin)) {
555                    throw new GpioPinExistsException(pin);
556                }
557            }
558
559            // create new GPIO pin instance
560            gpioPin = new GpioPinImpl(this, provider, pin);
561
562            // set the gpio pin name
563            if (name != null) {
564                gpioPin.setName(name);
565            }
566
567            // export this pin
568            gpioPin.export(mode, defaultState);
569
570            // add this new pin instance to the managed collection
571            pins.add(gpioPin);
572        }
573
574        // return new new pin instance
575        return gpioPin;
576    }
577
578    @Override
579    public GpioPin provisionPin(Pin pin, String name, PinMode mode) {
580        return provisionPin(defaultProvider, pin, name, mode);
581    }
582
583    @Override
584    public GpioPin provisionPin(Pin pin, PinMode mode) {
585        return provisionPin(defaultProvider, pin, mode);
586    }
587
588    @Override
589    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, String name, PinMode mode) {
590        // return new new pin instance
591        return (GpioPinDigitalMultipurpose)provisionPin(provider, pin, name, mode);
592    }
593
594    @Override
595    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, PinMode mode) {
596        // return new new pin instance
597        return (GpioPinDigitalMultipurpose)provisionPin(provider, pin, mode);
598    }
599
600    @Override
601    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, String name, PinMode mode) {
602        return provisionDigitalMultipurposePin(defaultProvider, pin, name, mode);
603    }
604
605    @Override
606    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, PinMode mode) {
607        return provisionDigitalMultipurposePin(defaultProvider, pin, mode);
608    }
609
610    @Override
611    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, PinMode mode, PinPullResistance resistance) {
612        // create new GPIO pin instance
613        return provisionDigitalMultipurposePin(provider, pin, pin.getName(), mode, resistance);
614    }
615
616    @Override
617    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(GpioProvider provider, Pin pin, String name, PinMode mode, PinPullResistance resistance) {
618        // create new GPIO pin instance
619        GpioPinDigitalMultipurpose gpioPin = provisionDigitalMultipurposePin(provider, pin, name, mode);
620
621        // set the gpio pull resistor
622        if (resistance != null) {
623            gpioPin.setPullResistance(resistance);
624        }
625        // return new new pin instance
626        return gpioPin;
627    }
628
629    @Override
630    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, String name, PinMode mode, PinPullResistance resistance) {
631        return provisionDigitalMultipurposePin(defaultProvider, pin, name, mode, resistance);
632    }
633
634    @Override
635    public GpioPinDigitalMultipurpose provisionDigitalMultipurposePin(Pin pin, PinMode mode, PinPullResistance resistance) {
636        return provisionDigitalMultipurposePin(defaultProvider, pin, mode, resistance);
637    }
638
639
640    @Override
641    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, String name) {
642        // return new new pin instance
643        return (GpioPinDigitalInput)provisionPin(provider, pin, name, PinMode.DIGITAL_INPUT);
644    }
645
646    @Override
647    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin) {
648        // return new new pin instance
649        return (GpioPinDigitalInput)provisionPin(provider, pin, PinMode.DIGITAL_INPUT);
650    }
651
652    @Override
653    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, String name) {
654        return provisionDigitalInputPin(defaultProvider, pin, name);
655    }
656
657    @Override
658    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin) {
659        return provisionDigitalInputPin(defaultProvider, pin);
660    }
661
662    @Override
663    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, PinPullResistance resistance) {
664        // create new GPIO pin instance
665        return provisionDigitalInputPin(provider, pin, pin.getName(), resistance);
666    }
667
668    @Override
669    public GpioPinDigitalInput provisionDigitalInputPin(GpioProvider provider, Pin pin, String name, PinPullResistance resistance) {
670        // create new GPIO pin instance
671        GpioPinDigitalInput gpioPin = provisionDigitalInputPin(provider, pin, name);
672
673        // set the gpio pull resistor
674        if (resistance != null) {
675            gpioPin.setPullResistance(resistance);
676        }
677        // return new new pin instance
678        return gpioPin;
679    }
680
681    @Override
682    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, String name, PinPullResistance resistance) {
683        return provisionDigitalInputPin(defaultProvider, pin, name, resistance);
684    }
685
686    @Override
687    public GpioPinDigitalInput provisionDigitalInputPin(Pin pin, PinPullResistance resistance) {
688        return provisionDigitalInputPin(defaultProvider, pin, resistance);
689    }
690
691    @Override
692    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, String name) {
693        // return new new pin instance
694        return (GpioPinDigitalOutput)provisionPin(provider, pin, name, PinMode.DIGITAL_OUTPUT);
695    }
696
697    @Override
698    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin) {
699        // return new new pin instance
700        return (GpioPinDigitalOutput)provisionPin(provider, pin, PinMode.DIGITAL_OUTPUT);
701    }
702
703    @Override
704    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, String name) {
705        return provisionDigitalOutputPin(defaultProvider, pin, name);
706    }
707
708    @Override
709    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin) {
710        return provisionDigitalOutputPin(defaultProvider, pin);
711    }
712
713    @Override
714    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, PinState defaultState) {
715        return provisionDigitalOutputPin(provider, pin, pin.getName(), defaultState);
716    }
717
718    @Override
719    public GpioPinDigitalOutput provisionDigitalOutputPin(GpioProvider provider, Pin pin, String name, PinState defaultState) {
720        // create new GPIO pin instance
721        GpioPinDigitalOutput gpioPin = (GpioPinDigitalOutput)provisionPin(provider, pin, name, PinMode.DIGITAL_OUTPUT, defaultState);
722
723        // apply default state
724        if (defaultState != null) {
725            gpioPin.setState(defaultState);
726        }
727        // return new new pin instance
728        return gpioPin;
729    }
730
731    @Override
732    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, String name, PinState defaultState) {
733        return provisionDigitalOutputPin(defaultProvider, pin, name, defaultState);
734    }
735
736    @Override
737    public GpioPinDigitalOutput provisionDigitalOutputPin(Pin pin, PinState defaultState) {
738        return provisionDigitalOutputPin(defaultProvider, pin, defaultState);
739    }
740
741    @Override
742    public GpioPinAnalogInput provisionAnalogInputPin(GpioProvider provider, Pin pin, String name) {
743        // return new new pin instance
744        return (GpioPinAnalogInput)provisionPin(provider, pin, name, PinMode.ANALOG_INPUT);
745    }
746
747    @Override
748    public GpioPinAnalogInput provisionAnalogInputPin(GpioProvider provider, Pin pin) {
749        // return new new pin instance
750        return (GpioPinAnalogInput)provisionPin(provider, pin, PinMode.ANALOG_INPUT);
751    }
752
753    @Override
754    public GpioPinAnalogInput provisionAnalogInputPin(Pin pin, String name) {
755        return provisionAnalogInputPin(defaultProvider, pin, name);
756    }
757
758    @Override
759    public GpioPinAnalogInput provisionAnalogInputPin(Pin pin) {
760        return provisionAnalogInputPin(defaultProvider, pin);
761    }
762
763    @Override
764    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, String name) {
765        // return new new pin instance
766        return (GpioPinAnalogOutput)provisionPin(provider, pin, name, PinMode.ANALOG_OUTPUT);
767    }
768
769    @Override
770    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin) {
771        // return new new pin instance
772        return (GpioPinAnalogOutput)provisionPin(provider, pin, PinMode.ANALOG_OUTPUT);
773    }
774
775    @Override
776    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, String name) {
777        return provisionAnalogOutputPin(defaultProvider, pin, name);
778    }
779
780    @Override
781    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin) {
782        return provisionAnalogOutputPin(defaultProvider, pin);
783    }
784
785    @Override
786    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, double defaultValue) {
787        return provisionAnalogOutputPin(provider, pin, pin.getName(), defaultValue);
788    }
789
790    @Override
791    public GpioPinAnalogOutput provisionAnalogOutputPin(GpioProvider provider, Pin pin, String name, double defaultValue) {
792        // create new GPIO pin instance
793        GpioPinAnalogOutput gpioPin = provisionAnalogOutputPin(provider, pin, name);
794
795        // apply default value
796        gpioPin.setValue(defaultValue);
797
798        // return new new pin instance
799        return gpioPin;
800    }
801
802    @Override
803    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, String name, double defaultValue) {
804        return provisionAnalogOutputPin(defaultProvider, pin, name, defaultValue);
805    }
806
807    @Override
808    public GpioPinAnalogOutput provisionAnalogOutputPin(Pin pin, double defaultValue) {
809        return provisionAnalogOutputPin(defaultProvider, pin, defaultValue);
810    }
811
812    @Override
813    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, String name) {
814        // return new new pin instance
815        return (GpioPinPwmOutput)provisionPin(provider, pin, name, PinMode.PWM_OUTPUT);
816    }
817
818    @Override
819    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin) {
820        // return new new pin instance
821        return (GpioPinPwmOutput)provisionPin(provider, pin, PinMode.PWM_OUTPUT);
822    }
823
824    @Override
825    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, String name) {
826        return provisionPwmOutputPin(defaultProvider, pin, name);
827    }
828
829    @Override
830    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin) {
831        return provisionPwmOutputPin(defaultProvider, pin);
832    }
833
834    @Override
835    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, int defaultValue) {
836        return provisionPwmOutputPin(provider, pin, pin.getName(), defaultValue);
837    }
838
839    @Override
840    public GpioPinPwmOutput provisionPwmOutputPin(GpioProvider provider, Pin pin, String name, int defaultValue) {
841        // create new GPIO pin instance
842        GpioPinPwmOutput gpioPin = provisionPwmOutputPin(provider, pin, name);
843
844        // apply default value
845        gpioPin.setPwm(defaultValue);
846
847        // return new new pin instance
848        return gpioPin;
849    }
850
851    @Override
852    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, String name, int defaultValue) {
853        return provisionPwmOutputPin(defaultProvider, pin, name, defaultValue);
854    }
855
856    @Override
857    public GpioPinPwmOutput provisionPwmOutputPin(Pin pin, int defaultValue) {
858        return provisionPwmOutputPin(defaultProvider, pin, defaultValue);
859    }
860
861    @Override
862    public GpioPinPwmOutput provisionSoftPwmOutputPin(GpioProvider provider, Pin pin, String name) {
863        // return new new pin instance
864        return (GpioPinPwmOutput)provisionPin(provider, pin, name, PinMode.SOFT_PWM_OUTPUT);
865    }
866
867    @Override
868    public GpioPinPwmOutput provisionSoftPwmOutputPin(GpioProvider provider, Pin pin) {
869        // return new new pin instance
870        return (GpioPinPwmOutput)provisionPin(provider, pin, PinMode.SOFT_PWM_OUTPUT);
871    }
872
873    @Override
874    public GpioPinPwmOutput provisionSoftPwmOutputPin(Pin pin, String name) {
875        return provisionSoftPwmOutputPin(defaultProvider, pin, name);
876    }
877
878    @Override
879    public GpioPinPwmOutput provisionSoftPwmOutputPin(Pin pin) {
880        return provisionSoftPwmOutputPin(defaultProvider, pin);
881    }
882
883    @Override
884    public GpioPinPwmOutput provisionSoftPwmOutputPin(GpioProvider provider, Pin pin, int defaultValue) {
885        return provisionSoftPwmOutputPin(provider, pin, pin.getName(), defaultValue);
886    }
887
888    @Override
889    public GpioPinPwmOutput provisionSoftPwmOutputPin(GpioProvider provider, Pin pin, String name, int defaultValue)  {
890        // create new GPIO pin instance
891        GpioPinPwmOutput gpioPin = provisionSoftPwmOutputPin(provider, pin, name);
892
893        // apply default value
894        gpioPin.setPwm(defaultValue);
895
896        // return new new pin instance
897        return gpioPin;
898    }
899
900    @Override
901    public GpioPinPwmOutput provisionSoftPwmOutputPin(Pin pin, String name, int defaultValue) {
902        return provisionSoftPwmOutputPin(defaultProvider, pin, name, defaultValue);
903    }
904
905    @Override
906    public GpioPinPwmOutput provisionSoftPwmOutputPin(Pin pin, int defaultValue) {
907        return provisionSoftPwmOutputPin(defaultProvider, pin, defaultValue);
908    }
909
910    @Override
911    public void unprovisionPin(GpioPin... pin) {
912        if (pin == null || pin.length == 0) {
913            throw new IllegalArgumentException("Missing pin argument.");
914        }
915        for (int index = (pin.length-1); index >= 0; index--) {
916            GpioPin p  = pin[index];
917
918            // ensure the requested pin has been provisioned
919            if (!pins.contains(p)) {
920                throw new GpioPinNotProvisionedException(p.getPin());
921            }
922
923            synchronized (this) {
924                // remove all listeners and triggers
925                if (p instanceof GpioPinInput) {
926                    ((GpioPinInput) p).removeAllListeners();
927                    ((GpioPinInput) p).removeAllTriggers();
928                }
929
930                // remove this pin instance from the managed collection
931                pins.remove(p);
932            }
933        }
934    }
935
936    public void setShutdownOptions(GpioPinShutdown options, GpioPin... pin) {
937        for (GpioPin p : pin) {
938            if (!pins.contains(p)) {
939                throw new GpioPinNotProvisionedException(p.getPin());
940            }
941            p.setShutdownOptions(options);
942        }
943    }
944
945    public void setShutdownOptions(Boolean unexport, GpioPin... pin) {
946        for (GpioPin p : pin) {
947            if (!pins.contains(p)) {
948                throw new GpioPinNotProvisionedException(p.getPin());
949            }
950            p.setShutdownOptions(unexport);
951        }
952    }
953
954    public void setShutdownOptions(Boolean unexport, PinState state, GpioPin... pin) {
955        for (GpioPin p : pin) {
956            if (!pins.contains(p)) {
957                throw new GpioPinNotProvisionedException(p.getPin());
958            }
959            p.setShutdownOptions(unexport, state);
960        }
961    }
962
963    public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance, GpioPin... pin) {
964        for (GpioPin p : pin) {
965            if (!pins.contains(p)) {
966                throw new GpioPinNotProvisionedException(p.getPin());
967            }
968            p.setShutdownOptions(unexport, state, resistance);
969        }
970    }
971
972    public void setShutdownOptions(Boolean unexport, PinState state, PinPullResistance resistance, PinMode mode, GpioPin... pin) {
973        for (GpioPin p : pin) {
974            if (!pins.contains(p)) {
975                throw new GpioPinNotProvisionedException(p.getPin());
976            }
977            p.setShutdownOptions(unexport, state, resistance, mode);
978        }
979    }
980
981
982    /**
983     * This class is used to perform any configured shutdown actions
984     * on the provisioned GPIO pins
985     *
986     * @author Robert Savage
987     *
988     */
989    private class ShutdownHook extends Thread {
990        public void run() {
991            // perform shutdown
992            shutdown();
993        }
994    }
995
996    /**
997     * This method returns TRUE if the GPIO controller has been shutdown.
998     *
999     * @return shutdown state
1000     */
1001    @Override
1002    public boolean isShutdown(){
1003        return isshutdown;
1004    }
1005
1006
1007    /**
1008     * This method can be called to forcefully shutdown all GPIO controller
1009     * monitoring, listening, and task threads/executors.
1010     */
1011    @Override
1012    public synchronized void shutdown()
1013    {
1014        // prevent reentrant invocation
1015        if(isShutdown())
1016            return;
1017
1018        // create a temporary set of providers to shutdown after completing all the pin instance shutdowns
1019        Set<GpioProvider> gpioProvidersToShutdown = new HashSet<>();
1020
1021        // shutdown explicit configured GPIO pins
1022        for (GpioPin pin : pins) {
1023
1024            // add each GPIO provider to the shutdown set
1025            if(!gpioProvidersToShutdown.contains(pin.getProvider())){
1026                gpioProvidersToShutdown.add(pin.getProvider());
1027            }
1028
1029            // perform the shutdown options if configured for the pin
1030            GpioPinShutdown shutdownOptions = pin.getShutdownOptions();
1031            if (shutdownOptions != null) {
1032                // get shutdown option configuration
1033                PinState state = shutdownOptions.getState();
1034                PinMode mode = shutdownOptions.getMode();
1035                PinPullResistance resistance = shutdownOptions.getPullResistor();
1036                Boolean unexport = shutdownOptions.getUnexport();
1037
1038                // perform shutdown actions
1039                if ((state != null) && pin.isMode(PinMode.DIGITAL_OUTPUT)) {
1040                    ((GpioPinDigitalOutput)pin).setState(state);
1041                }
1042                if (resistance != null) {
1043                    pin.setPullResistance(resistance);
1044                }
1045                if (mode != null) {
1046                    pin.setMode(mode);
1047                }
1048                if (unexport != null && unexport == Boolean.TRUE) {
1049                    pin.unexport();
1050                }
1051            }
1052        }
1053
1054        // perform a shutdown on each GPIO provider
1055        for(GpioProvider gpioProvider : gpioProvidersToShutdown){
1056            if(!gpioProvider.isShutdown()){
1057                gpioProvider.shutdown();
1058            }
1059        }
1060
1061        // shutdown all executor services
1062        //
1063        // NOTE: we are not permitted to access the shutdown() method of the individual
1064        // executor services, we must perform the shutdown with the factory
1065        GpioFactory.getExecutorServiceFactory().shutdown();
1066
1067        // set is shutdown tracking variable
1068        isshutdown = true;
1069    }
1070}