diff --git a/INSTALL b/INSTALL index 8e0c43c..4e1df2e 100644 --- a/INSTALL +++ b/INSTALL @@ -19,13 +19,6 @@ then run the ldconfig command. sudo ldconfig -If you want to install a static library, you may need to do this manually: - - cd wiringPi - make static - sudo make install-static - - To un-install wiringPi: ./build uninstall diff --git a/README.TXT b/README.TXT index 7789b2e..894a31b 100644 --- a/README.TXT +++ b/README.TXT @@ -1,3 +1,13 @@ +Note +==== + +This is an unofficial mirror of WiringPi to support ports (Python/Ruby/etc). + +Please do not email Gordon if you have issues, he will not be able to help. + +Pull-requests are not currently accepted, since this is a mirror. + +For support, comments, questions, etc please join the WiringPi Discord channel: https://discord.gg/SM4WUVG wiringPi README =============== diff --git a/VERSION b/VERSION index 0f34dc7..e72716a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.32 +2.46 diff --git a/build b/build index 368e8f4..6844946 100755 --- a/build +++ b/build @@ -6,7 +6,7 @@ # Copyright (c) 2012-2015 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -64,6 +64,9 @@ if [ x$1 = "xclean" ]; then echo -n "PiGlow: " ; make clean cd ../scrollPhat echo -n "scrollPhat: " ; make clean + cd ../.. + echo -n "Deb: " ; rm -f debian-template/wiringpi*.deb + echo exit fi @@ -161,6 +164,14 @@ fi check_make_ok # echo +# echo "wiringPi Daemon" +# cd ../wiringPiD +# make -j5 +# check_make_ok +# $sudo make install +# check_make_ok + +# echo # echo "Examples" # cd ../examples # make diff --git a/debian-template/wiringPi/DEBIAN/control b/debian-template/wiringPi/DEBIAN/control index 230da07..72b3bc8 100644 --- a/debian-template/wiringPi/DEBIAN/control +++ b/debian-template/wiringPi/DEBIAN/control @@ -1,5 +1,5 @@ Package: wiringpi -Version: 2.32 +Version: 2.46 Section: libraries Priority: optional Architecture: armhf @@ -7,4 +7,4 @@ Depends: libc6 Maintainer: Gordon Henderson Description: The wiringPi libraries, headers and gpio command Libraries to allow GPIO access on a Raspberry Pi from C and C++ - programs as well as from the command-line + and BASIC programs as well as from the command-line diff --git a/devLib/Makefile b/devLib/Makefile new file mode 100644 index 0000000..cf665d6 --- /dev/null +++ b/devLib/Makefile @@ -0,0 +1,140 @@ +# +# Makefile: +# wiringPi device - A "wiring" library for the Raspberry Pi +# +# Copyright (c) 2012-2016 Gordon Henderson +################################################################################# +# This file is part of wiringPi: +# https://projects.drogon.net/raspberry-pi/wiringpi/ +# +# wiringPi is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# wiringPi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with wiringPi. If not, see . +################################################################################# + +VERSION=$(shell cat ../VERSION) +DESTDIR?=/usr +PREFIX?=/local + +LDCONFIG?=ldconfig + +ifneq ($V,1) +Q ?= @ +endif + +STATIC=libwiringPiDev.a +DYNAMIC=libwiringPiDev.so.$(VERSION) + +#DEBUG = -g -O0 +DEBUG = -O2 +CC = gcc +INCLUDE = -I. +DEFS = -D_GNU_SOURCE +CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Winline $(INCLUDE) -pipe -fPIC + +LIBS = + +############################################################################### + +SRC = ds1302.c maxdetect.c piNes.c \ + gertboard.c piFace.c \ + lcd128x64.c lcd.c \ + scrollPhat.c \ + piGlow.c + +OBJ = $(SRC:.c=.o) + +HEADERS = ds1302.h gertboard.h lcd128x64.h lcd.h maxdetect.h piFace.h piGlow.h piNes.h\ + scrollPhat.h + +all: $(DYNAMIC) + +static: $(STATIC) + +$(STATIC): $(OBJ) + $Q echo "[Link (Static)]" + $Q ar rcs $(STATIC) $(OBJ) + $Q ranlib $(STATIC) +# @size $(STATIC) + +$(DYNAMIC): $(OBJ) + $Q echo "[Link (Dynamic)]" + $Q $(CC) -shared -Wl,-soname,libwiringPiDev.so$(WIRINGPI_SONAME_SUFFIX) -o libwiringPiDev.so.$(VERSION) -lpthread $(OBJ) + +.c.o: + $Q echo [Compile] $< + $Q $(CC) -c $(CFLAGS) $< -o $@ + +.PHONY: clean +clean: + $Q echo "[Clean]" + $Q rm -f $(OBJ) $(OBJ_I2C) *~ core tags Makefile.bak libwiringPiDev.* + +.PHONY: tags +tags: $(SRC) + $Q echo [ctags] + $Q ctags $(SRC) + + +.PHONY: install +install: $(DYNAMIC) + $Q echo "[Install Headers]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/include + $Q install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include + $Q echo "[Install Dynamic Lib]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/lib + $Q install -m 0755 libwiringPiDev.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libwiringPiDev.so.$(VERSION) + $Q ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPiDev.so.$(VERSION) $(DESTDIR)/lib/libwiringPiDev.so + $Q $(LDCONFIG) + +.PHONY: install-static +install-static: $(STATIC) + $Q echo "[Install Headers]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/include + $Q install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include + $Q echo "[Install Static Lib]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/lib + $Q install -m 0755 libwiringPiDev.a $(DESTDIR)$(PREFIX)/lib + +.PHONY: install-deb +install-deb: $(DYNAMIC) + $Q echo "[Install Headers: deb]" + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/include + $Q install -m 0644 $(HEADERS) ~/wiringPi/debian-template/wiringPi/usr/include + $Q echo "[Install Dynamic Lib: deb]" + install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/lib + install -m 0755 libwiringPiDev.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPiDev.so.$(VERSION) + ln -sf ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPiDev.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPiDev.so + +.PHONY: uninstall +uninstall: + $Q echo "[UnInstall]" + $Q cd $(DESTDIR)$(PREFIX)/include/ && rm -f $(HEADERS) + $Q cd $(DESTDIR)$(PREFIX)/lib/ && rm -f libwiringPiDev.* + $Q $(LDCONFIG) + + +.PHONY: depend +depend: + makedepend -Y $(SRC) + +# DO NOT DELETE + +ds1302.o: ds1302.h +maxdetect.o: maxdetect.h +piNes.o: piNes.h +gertboard.o: gertboard.h +piFace.o: piFace.h +lcd128x64.o: font.h lcd128x64.h +lcd.o: lcd.h +scrollPhat.o: scrollPhatFont.h scrollPhat.h +piGlow.o: piGlow.h diff --git a/devLib/gertboard.c b/devLib/gertboard.c index 5aeaef7..6a84415 100644 --- a/devLib/gertboard.c +++ b/devLib/gertboard.c @@ -101,7 +101,7 @@ int gertboardAnalogRead (const int chan) wiringPiSPIDataRW (SPI_A2D, spiData, 2) ; - return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ; + return ((spiData [0] << 8) | (spiData [1] >> 1)) & 0x3FF ; } diff --git a/devLib/piFaceOld.c b/devLib/piFaceOld.c index 1b1c0dd..cadbfe8 100644 --- a/devLib/piFaceOld.c +++ b/devLib/piFaceOld.c @@ -1,7 +1,6 @@ /* * piFace.: - * Arduino compatable (ish) Wiring library for the Raspberry Pi - * Copyright (c) 2012-2013 Gordon Henderson + * Copyright (c) 2012-2016 Gordon Henderson * * This file to interface with the PiFace peripheral device which * has an MCP23S17 GPIO device connected via the SPI bus. diff --git a/examples/Makefile b/examples/Makefile index 4278b6d..6d87885 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,6 +1,6 @@ # # Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi +# wiringPi - A "wiring" library for the Raspberry Pi # https://projects.drogon.net/wiring-pi # # Copyright (c) 2012-2015 Gordon Henderson @@ -33,7 +33,7 @@ INCLUDE = -I/usr/local/include CFLAGS = $(DEBUG) -Wall $(INCLUDE) -Winline -pipe LDFLAGS = -L/usr/local/lib -LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm +LDLIBS = -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt # Should not alter anything below this line ############################################################################### diff --git a/examples/PiFace/Makefile b/examples/PiFace/Makefile index 4685adc..f937c14 100644 --- a/examples/PiFace/Makefile +++ b/examples/PiFace/Makefile @@ -1,12 +1,12 @@ # # Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi +# wiringPi - A "wiring" library for the Raspberry Pi # https://projects.drogon.net/wiring-pi # # Copyright (c) 2012 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/examples/PiGlow/Makefile b/examples/PiGlow/Makefile index acd4818..f182db7 100644 --- a/examples/PiGlow/Makefile +++ b/examples/PiGlow/Makefile @@ -1,12 +1,12 @@ # # Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi +# wiringPi - A "wiring" library for the Raspberry Pi # https://projects.drogon.net/wiring-pi # # Copyright (c) 2012-2015 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/examples/blink-thread.c b/examples/blink-thread.c new file mode 100644 index 0000000..a53fbf3 --- /dev/null +++ b/examples/blink-thread.c @@ -0,0 +1,61 @@ +/* + * blink-thread.c: + * Standard "blink" program in wiringPi. Blinks an LED connected + * to the first GPIO pin. + * + * Copyright (c) 2012-2013 Gordon Henderson. + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include + +// LED Pin - wiringPi pin 0 is BCM_GPIO 17. + +#define LED 0 + +PI_THREAD (blinky) +{ + for (;;) + { + digitalWrite (LED, HIGH) ; // On + delay (500) ; // mS + digitalWrite (LED, LOW) ; // Off + delay (500) ; + } +} + + +int main (void) +{ + printf ("Raspberry Pi blink\n") ; + + wiringPiSetup () ; + pinMode (LED, OUTPUT) ; + + piThreadCreate (blinky) ; + + for (;;) + { + printf ("Hello, world\n") ; + delay (600) ; + } + + return 0 ; +} diff --git a/examples/blink8-drcn.c b/examples/blink8-drcn.c new file mode 100644 index 0000000..96c775b --- /dev/null +++ b/examples/blink8-drcn.c @@ -0,0 +1,61 @@ +/* + * blink8-drcn.c: + * Simple sequence over the first 8 GPIO pins - LEDs + * Aimed at the Ladder board, but it's fairly generic. + * + * Copyright (c) 2012-2013 Gordon Henderson. + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include + +int main (void) +{ + int i, led ; + + printf ("Raspberry Pi - 8-LED Sequencer\n") ; + printf ("==============================\n") ; + printf ("\n") ; + printf ("Connect LEDs to the first 8 GPIO pins and watch ...\n") ; + + int pinBase = 100 ; + +// wiringPiSetup () ; + drcSetupNet (pinBase, 100, "192.168.254.21", "6124", "123456") ; + + for (i = 0 ; i < 8 ; ++i) + pinMode (i + pinBase, OUTPUT) ; + + for (;;) + { + for (led = 0 ; led < 8 ; ++led) + { + digitalWrite (led + pinBase, 1) ; + delay (10) ; + } + + for (led = 0 ; led < 8 ; ++led) + { + digitalWrite (led + pinBase, 0) ; + delay (10) ; + } + } +} diff --git a/examples/delayTest.c b/examples/delayTest.c index 4c8b6ca..d772cf9 100644 --- a/examples/delayTest.c +++ b/examples/delayTest.c @@ -25,7 +25,6 @@ #include #include -#include #include @@ -34,17 +33,13 @@ int main() { int x ; - struct timeval t1, t2 ; + struct timeval t1, t2, t3 ; int t ; int max, min ; int del ; - int underRuns, overRuns, exactRuns, total ; + int underRuns, overRuns, exactRuns, bogusRuns, total ; int descheds ; - if (wiringPiSetup () == -1) - return 1 ; - - piHiPri (10) ; sleep (1) ; // Baseline test @@ -58,21 +53,22 @@ int main() { underRuns = overRuns = exactRuns = total = 0 ; descheds = 0 ; - max = del ; - min = del ; + max = 0 ; + min = 999 ; for (x = 0 ; x < CYCLES ; ++x) { for (;;) // Repeat this if we get a delay over 999uS { // -> High probability Linux has deschedulled us gettimeofday (&t1, NULL) ; - delayMicroseconds (del) ; + usleep (del) ; +// delayMicroseconds (del) ; gettimeofday (&t2, NULL) ; - if (t2.tv_usec < t1.tv_usec) // Counter wrapped - t = (1000000 + t2.tv_usec) - t1.tv_usec; - else - t = t2.tv_usec - t1.tv_usec ; + timersub (&t2, &t1, &t3) ; + + t = t3.tv_usec ; + if (t > 999) { ++descheds ; @@ -82,25 +78,24 @@ int main() break ; } + if (t == del) + ++exactRuns ; + else if (t < del) + ++underRuns ; + else if (t > del) + ++overRuns ; + if (t > max) - { max = t ; - ++overRuns ; - } else if (t < min) - { min = t ; - ++underRuns ; - } - else - ++exactRuns ; total += t ; } printf ("Delay: %3d. Min: %3d, Max: %3d, Unders: %3d, Overs: %3d, Exacts: %3d, Average: %3d, Descheds: %2d\n", del, min, max, underRuns, overRuns, exactRuns, total / CYCLES, descheds) ; fflush (stdout) ; - delay (1) ; + usleep (1000) ; } return 0 ; diff --git a/examples/q2w/Makefile b/examples/q2w/Makefile index 6f50fa0..8f773bf 100644 --- a/examples/q2w/Makefile +++ b/examples/q2w/Makefile @@ -1,12 +1,12 @@ # # Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi +# wiringPi - A "wiring" library for the Raspberry Pi # https://projects.drogon.net/wiring-pi # # Copyright (c) 2012-2013 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/examples/scrollPhat/Makefile b/examples/scrollPhat/Makefile index c0b7241..2471f69 100644 --- a/examples/scrollPhat/Makefile +++ b/examples/scrollPhat/Makefile @@ -1,12 +1,12 @@ # # Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi +# wiringPi - A "wiring" library for the Raspberry Pi # https://projects.drogon.net/wiring-pi # # Copyright (c) 2012-2015 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/gpio/Makefile b/gpio/Makefile new file mode 100644 index 0000000..9ec160d --- /dev/null +++ b/gpio/Makefile @@ -0,0 +1,103 @@ +# +# Makefile: +# The gpio command: +# A swiss-army knige of GPIO shenanigans. +# https://projects.drogon.net/wiring-pi +# +# Copyright (c) 2012-2016 Gordon Henderson +################################################################################# +# This file is part of wiringPi: +# A "wiring" library for the Raspberry Pi +# +# wiringPi is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# wiringPi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with wiringPi. If not, see . +################################################################################# + +DESTDIR?=/usr +PREFIX?=/local + +ifneq ($V,1) +Q ?= @ +endif + +#DEBUG = -g -O0 +DEBUG = -O2 +CC = gcc +INCLUDE = -I$(DESTDIR)$(PREFIX)/include +CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe + +LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib +LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt + +# May not need to alter anything below this line +############################################################################### + +SRC = gpio.c readall.c + +OBJ = $(SRC:.c=.o) + +all: gpio + +version.h: ../VERSION + $Q echo Need to run newVersion above. + +gpio: $(OBJ) + $Q echo [Link] + $Q $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS) + +.c.o: + $Q echo [Compile] $< + $Q $(CC) -c $(CFLAGS) $< -o $@ + +.PHONY: clean +clean: + $Q echo "[Clean]" + $Q rm -f $(OBJ) gpio *~ core tags *.bak + +.PHONY: tags +tags: $(SRC) + $Q echo [ctags] + $Q ctags $(SRC) + +.PHONY: install +install: gpio + $Q echo "[Install]" + $Q cp gpio $(DESTDIR)$(PREFIX)/bin +ifneq ($(WIRINGPI_SUID),0) + $Q chown root.root $(DESTDIR)$(PREFIX)/bin/gpio + $Q chmod 4755 $(DESTDIR)$(PREFIX)/bin/gpio +endif + $Q mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1 + $Q cp gpio.1 $(DESTDIR)$(PREFIX)/share/man/man1 + +.PHONY: install-deb +install-deb: gpio + $Q echo "[Install: deb]" + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/bin + $Q install -m 0755 gpio ~/wiringPi/debian-template/wiringPi/usr/bin + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/share/man/man1 + $Q install -m 0644 gpio.1 ~/wiringPi/debian-template/wiringPi/usr/share/man/man1 + +.PHONY: uninstall +uninstall: + $Q echo "[UnInstall]" + $Q rm -f $(DESTDIR)$(PREFIX)/bin/gpio + $Q rm -f $(DESTDIR)$(PREFIX)/share/man/man1/gpio.1 + +.PHONY: depend +depend: + makedepend -Y $(SRC) + +# DO NOT DELETE + +gpio.o: ../version.h diff --git a/gpio/gpio.1 b/gpio/gpio.1 index e5fe181..a71aaae 100644 --- a/gpio/gpio.1 +++ b/gpio/gpio.1 @@ -1,4 +1,4 @@ -.TH GPIO 1 "September 2015" wiringPi "Command-Line access to Raspberry Pi's GPIO" +.TH GPIO 1 "March 2018" wiringPi "Command-Line access to Raspberry Pi's GPIO" .SH NAME gpio \- Command-line access to Raspberry Pi's GPIO @@ -9,15 +9,20 @@ gpio \- Command-line access to Raspberry Pi's GPIO .PP .B gpio .B [ \-g | \-1 ] -.B mode/read/write/aread/awrite/wb/pwm/clock ... +.B mode/read/write/aread/awrite/wb/pwm/pwnTone/clock/toggle/blink ... .PP .B gpio .B [ \-x extension:params ] -.B mode/read/write/aread/awrite/pwm/pwmTone ... +.B mode/read/write/aread/awrite/pwm/toggle/blink ... .PP .B gpio .B [ \-p ] -.B read/write/toggle/wb +.B read/write/toggle/blink +.B ... +.PP +.B gpio +.B [ \-p ] +.B pwnTone pin frequency .B ... .PP .B gpio @@ -119,10 +124,22 @@ Write the given value (0 or 1) to the pin. You need to set the pin to output mode first. .TP +.B toggle +Changes the state of a GPIO pin; 0 to 1, or 1 to 0. + +Note unlike the blink command, the pin must be in output mode first. + +.TP +.B blink +Blinks the given pin on/off. Press Control-C to exit. + +Note: This command explicitly sets the pin to output mode. + +.TP .B aread -Read the analog value of the given pin. This needs to be uses in +Read the analog value of the given pin. This needs to be used in conjunction with a -x flag to add in an extension that handles analog -inputs. respective logic levels. +inputs. e.g. gpio -x mcp3002:200:0 aread 200 @@ -132,7 +149,7 @@ will read the first analog input on an mcp3002 SPI ADC chip. .B awrite Write the analog value to the given pin. This needs to be used in conjunction with a -x flag to add in an extension that handles analog -inputs. respective logic levels. +inputs. e.g. gpio -x mcp4802:200:0 awrite 200 128 @@ -234,7 +251,7 @@ absolutely sure you know what you're doing. high | low Change the USB current limiter to high (1.2 amps) or low (the default, 600mA) -This is only applicable to the model B+ +This is only applicable to the Model B+ and the Model B, v2. .TP .B pwm-bal/pwm-ms @@ -245,32 +262,6 @@ Change the PWM mode to balanced (the default) or mark:space ratio (traditional) Change the PWM range register. The default is 1024. .TP -.B load i2c [baudrate] -This loads the i2c or drivers into the kernel and changes the permissions -on the associated /dev/ entries so that the current user has access to -them. Optionally it will set the I2C baudrate to that supplied in Kb/sec -(or as close as the Pi can manage) The default speed is 100Kb/sec. - -Note: On recent kernels with the device tree enabled you should use the -raspi-config program to load/unload the I2C device at boot time. -(or disable the device tree to continue to use this method) - -.TP -.B load spi -This loads the spi drivers into the kernel and changes the permissions -on the associated /dev/ entries so that the current user has access to -them. It used to have the ability to change the buffer size from the -default of 4096 bytes to an arbitrary value, however for some time the -Pi Foundation have compiled the SPI device driver into the kernel and -this has fixed the buffer size. The way to change it now is to edit -the /boot/cmdline.txt file and add on spdev.bufsiz=8192 to set it to -e.g. 8192 bytes then reboot. - -Note: On recent kernels with the device tree enabled you should use the -raspi-config program to load/unload the SPI device at boot time. -(or disable the device tree to continue to use this method) - -.TP .B gbr channel @@ -350,7 +341,7 @@ Please report bugs to .SH COPYRIGHT -Copyright (c) 2012-2015 Gordon Henderson +Copyright (c) 2012-2018 Gordon Henderson This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/gpio/gpio.c b/gpio/gpio.c index 6162090..714e790 100644 --- a/gpio/gpio.c +++ b/gpio/gpio.c @@ -2,7 +2,7 @@ * gpio.c: * Swiss-Army-Knife, Set-UID command-line interface to the Raspberry * Pi's GPIO. - * Copyright (c) 2012-2015 Gordon Henderson + * Copyright (c) 2012-2018 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -40,7 +40,7 @@ #include #include -#include "version.h" +#include "../version.h" extern int wiringPiDebug ; @@ -48,7 +48,7 @@ extern int wiringPiDebug ; extern void doReadall (void) ; extern void doAllReadall (void) ; -extern void doPins (void) ; +extern void doQmode (int argc, char *argv []) ; #ifndef TRUE # define TRUE (1==1) @@ -56,16 +56,21 @@ extern void doPins (void) ; #endif #define PI_USB_POWER_CONTROL 38 -#define I2CDETECT "/usr/sbin/i2cdetect" +#define I2CDETECT "i2cdetect" +#define MODPROBE "modprobe" +#define RMMOD "rmmod" int wpMode ; char *usage = "Usage: gpio -v\n" " gpio -h\n" - " gpio [-g|-1] [-x extension:params] ...\n" + " gpio [-g|-1] ...\n" + " gpio [-d] ...\n" + " [-x extension:params] [[ -x ...]] ...\n" " gpio [-p] ...\n" - " gpio ...\n" - " gpio readall/reset\n" + " gpio ...\n" + " gpio \n" + " gpio readall\n" " gpio unexportall/exports\n" " gpio export/edge/unexport ...\n" " gpio wfi \n" @@ -76,6 +81,8 @@ char *usage = "Usage: gpio -v\n" " gpio load spi/i2c\n" " gpio unload spi/i2c\n" " gpio i2cd/i2cdetect\n" + " gpio rbx/rbd\n" + " gpio wb \n" " gpio usbp high/low\n" " gpio gbr \n" " gpio gbw " ; // No trailing newline needed here. @@ -103,6 +110,45 @@ static int decodePin (const char *str) /* + * findExecutable: + * Code to locate the path to the given executable. We have a fixed list + * of locations to try which completely overrides any $PATH environment. + * This may be detrimental, however it avoids the reliance on $PATH + * which may be a security issue when this program is run a set-uid-root. + ********************************************************************************* + */ + +static const char *searchPath [] = +{ + "/sbin", + "/usr/sbin", + "/bin", + "/usr/bin", + NULL, +} ; + +static char *findExecutable (const char *progName) +{ + static char *path = NULL ; + int len = strlen (progName) ; + int i = 0 ; + struct stat statBuf ; + + for (i = 0 ; searchPath [i] != NULL ; ++i) + { + path = malloc (strlen (searchPath [i]) + len + 2) ; + sprintf (path, "%s/%s", searchPath [i], progName) ; + + if (stat (path, &statBuf) == 0) + return path ; + free (path) ; + } + + return NULL ; +} + + +/* * changeOwner: * Change the ownership of the file to the real userId of the calling * program so we can access it. @@ -175,9 +221,7 @@ static void checkDevTree (char *argv []) fprintf (stderr, "%s: Unable to load/unload modules as this Pi has the device tree enabled.\n" " You need to run the raspi-config program (as root) and select the\n" -" modules (SPI or I2C) that you wish to load/unload there and reboot.\n" -" There is more information here:\n" -" https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=97314\n", argv [0]) ; +" modules (SPI or I2C) that you wish to load/unload there and reboot.\n", argv [0]) ; exit (1) ; } } @@ -230,15 +274,18 @@ static void doLoad (int argc, char *argv []) else _doLoadUsage (argv) ; + if (findExecutable ("modprobe") == NULL) + printf ("No found\n") ; + if (!moduleLoaded (module1)) { - sprintf (cmd, "/sbin/modprobe %s%s", module1, args1) ; + sprintf (cmd, "%s %s%s", findExecutable (MODPROBE), module1, args1) ; system (cmd) ; } if (!moduleLoaded (module2)) { - sprintf (cmd, "/sbin/modprobe %s%s", module2, args2) ; + sprintf (cmd, "%s %s%s", findExecutable (MODPROBE), module2, args2) ; system (cmd) ; } @@ -292,13 +339,13 @@ static void doUnLoad (int argc, char *argv []) if (moduleLoaded (module1)) { - sprintf (cmd, "/sbin/rmmod %s", module1) ; + sprintf (cmd, "%s %s", findExecutable (RMMOD), module1) ; system (cmd) ; } if (moduleLoaded (module2)) { - sprintf (cmd, "/sbin/rmmod %s", module2) ; + sprintf (cmd, "%s %s", findExecutable (RMMOD), module2) ; system (cmd) ; } } @@ -310,13 +357,12 @@ static void doUnLoad (int argc, char *argv []) ********************************************************************************* */ -static void doI2Cdetect (int argc, char *argv []) +static void doI2Cdetect (UNU int argc, char *argv []) { - int port = piBoardRev () == 1 ? 0 : 1 ; - char command [128] ; - struct stat statBuf ; + int port = piGpioLayout () == 1 ? 0 : 1 ; + char *c, *command ; - if (stat (I2CDETECT, &statBuf) < 0) + if ((c = findExecutable (I2CDETECT)) == NULL) { fprintf (stderr, "%s: Unable to find i2cdetect command: %s\n", argv [0], strerror (errno)) ; return ; @@ -328,7 +374,8 @@ static void doI2Cdetect (int argc, char *argv []) return ; } - sprintf (command, "%s -y %d", I2CDETECT, port) ; + command = malloc (strlen (c) + 16) ; + sprintf (command, "%s -y %d", c, port) ; if (system (command) < 0) fprintf (stderr, "%s: Unable to run i2cdetect: %s\n", argv [0], strerror (errno)) ; @@ -341,7 +388,7 @@ static void doI2Cdetect (int argc, char *argv []) ********************************************************************************* */ -static void doExports (int argc, char *argv []) +static void doExports (UNU int argc, UNU char *argv []) { int fd ; int i, l, first ; @@ -667,7 +714,7 @@ void doUnexportall (char *progName) ********************************************************************************* */ -static void doReset (char *progName) +static void doReset (UNU char *progName) { printf ("GPIO Reset is dangerous and has been removed from the gpio command.\n") ; printf (" - Please write a shell-script to reset the GPIO pins into the state\n") ; @@ -943,7 +990,7 @@ static void doAwrite (int argc, char *argv []) /* * doWriteByte: - * gpio write value + * gpio wb value ********************************************************************************* */ @@ -964,6 +1011,30 @@ static void doWriteByte (int argc, char *argv []) /* + * doReadByte: + * gpio rbx|rbd value + ********************************************************************************* + */ + +static void doReadByte (int argc, char *argv [], int printHex) +{ + int val ; + + if (argc != 2) + { + fprintf (stderr, "Usage: %s rbx|rbd\n", argv [0]) ; + exit (1) ; + } + + val = digitalReadByte () ; + if (printHex) + printf ("%02X\n", val) ; + else + printf ("%d\n", val) ; +} + + +/* * doRead: * Read a pin and return the value ********************************************************************************* @@ -1027,6 +1098,34 @@ void doToggle (int argc, char *argv []) /* + * doBlink: + * Blink an IO pin + ********************************************************************************* + */ + +void doBlink (int argc, char *argv []) +{ + int pin ; + + if (argc != 3) + { + fprintf (stderr, "Usage: %s blink pin\n", argv [0]) ; + exit (1) ; + } + + pin = atoi (argv [2]) ; + + pinMode (pin, OUTPUT) ; + for (;;) + { + digitalWrite (pin, !digitalRead (pin)) ; + delay (500) ; + } + +} + + +/* * doPwmTone: * Output a tone in a PWM pin ********************************************************************************* @@ -1162,9 +1261,14 @@ static void doVersion (char *argv []) { int model, rev, mem, maker, warranty ; struct stat statBuf ; + char name [80] ; + FILE *fd ; + + int vMaj, vMin ; - printf ("gpio version: %s\n", VERSION) ; - printf ("Copyright (c) 2012-2015 Gordon Henderson\n") ; + wiringPiVersion (&vMaj, &vMin) ; + printf ("gpio version: %d.%d\n", vMaj, vMin) ; + printf ("Copyright (c) 2012-2018 Gordon Henderson\n") ; printf ("This is free software with ABSOLUTELY NO WARRANTY.\n") ; printf ("For details type: %s -warranty\n", argv [0]) ; printf ("\n") ; @@ -1179,12 +1283,18 @@ static void doVersion (char *argv []) if (stat ("/proc/device-tree", &statBuf) == 0) // We're on a devtree system ... printf (" * Device tree is enabled.\n") ; - if (stat ("/dev/gpiomem", &statBuf) == 0) // User level GPIO is GO + if (stat ("/proc/device-tree/model", &statBuf) == 0) // Output Kernel idea of board type { - printf (" * This Raspberry Pi supports user-level GPIO access.\n") ; - printf (" -> See the man-page for more details\n") ; - printf (" -> ie. export WIRINGPI_GPIOMEM=1\n") ; + if ((fd = fopen ("/proc/device-tree/model", "r")) != NULL) + { + fgets (name, 80, fd) ; + fclose (fd) ; + printf (" *--> %s\n", name) ; + } } + + if (stat ("/dev/gpiomem", &statBuf) == 0) // User level GPIO is GO + printf (" * This Raspberry Pi supports user-level GPIO access.\n") ; else printf (" * Root or sudo required for GPIO access.\n") ; } @@ -1208,8 +1318,11 @@ int main (int argc, char *argv []) if (argc == 1) { - fprintf (stderr, "%s\n", usage) ; - return 1 ; + fprintf (stderr, +"%s: At your service!\n" +" Type: gpio -h for full details and\n" +" gpio readall for a quick printout of your connector details\n", argv [0]) ; + exit (EXIT_FAILURE) ; } // Help @@ -1217,7 +1330,7 @@ int main (int argc, char *argv []) if (strcasecmp (argv [1], "-h") == 0) { printf ("%s: %s\n", argv [0], usage) ; - return 0 ; + exit (EXIT_SUCCESS) ; } // Version & Warranty @@ -1225,8 +1338,8 @@ int main (int argc, char *argv []) if ((strcmp (argv [1], "-R") == 0) || (strcmp (argv [1], "-V") == 0)) { - printf ("%d\n", piBoardRev ()) ; - return 0 ; + printf ("%d\n", piGpioLayout ()) ; + exit (EXIT_SUCCESS) ; } // Version and information @@ -1234,13 +1347,13 @@ int main (int argc, char *argv []) if (strcmp (argv [1], "-v") == 0) { doVersion (argv) ; - return 0 ; + exit (EXIT_SUCCESS) ; } if (strcasecmp (argv [1], "-warranty") == 0) { printf ("gpio version: %s\n", VERSION) ; - printf ("Copyright (c) 2012-2015 Gordon Henderson\n") ; + printf ("Copyright (c) 2012-2018 Gordon Henderson\n") ; printf ("\n") ; printf (" This program is free software; you can redistribute it and/or modify\n") ; printf (" it under the terms of the GNU Leser General Public License as published\n") ; @@ -1255,13 +1368,13 @@ int main (int argc, char *argv []) printf (" You should have received a copy of the GNU Lesser General Public License\n") ; printf (" along with this program. If not, see .\n") ; printf ("\n") ; - return 0 ; + exit (EXIT_SUCCESS) ; } if (geteuid () != 0) { fprintf (stderr, "%s: Must be root to run. Program should be suid root. This is an error.\n", argv [0]) ; - return 1 ; + exit (EXIT_FAILURE) ; } // Initial test for /sys/class/gpio operations: @@ -1331,6 +1444,16 @@ int main (int argc, char *argv []) wpMode = WPI_MODE_PIFACE ; } +// Check for -z argument so we don't actually initialise wiringPi + + else if (strcasecmp (argv [1], "-z") == 0) + { + for (i = 2 ; i < argc ; ++i) + argv [i - 1] = argv [i] ; + --argc ; + wpMode = WPI_MODE_UNINITIALISED ; + } + // Default to wiringPi mode else @@ -1340,17 +1463,25 @@ int main (int argc, char *argv []) } // Check for -x argument to load in a new extension +// -x extension:base:args +// Can load many modules, but unless daemon mode we can only send one +// command at a time. - if (strcasecmp (argv [1], "-x") == 0) + while (strcasecmp (argv [1], "-x") == 0) { if (argc < 3) { - fprintf (stderr, "%s: -x missing extension specification.\n", argv [0]) ; + fprintf (stderr, "%s: -x missing extension command.\n", argv [0]) ; exit (EXIT_FAILURE) ; } - if (!loadWPiExtension (argv [0], argv [2], TRUE)) // Prints its own error messages + if (!loadWPiExtension (argv [0], argv [2], TRUE)) + { + fprintf (stderr, "%s: Extension load failed: %s\n", argv [0], strerror (errno)) ; exit (EXIT_FAILURE) ; + } + +// Shift args down by 2 for (i = 3 ; i < argc ; ++i) argv [i - 2] = argv [i] ; @@ -1375,6 +1506,7 @@ int main (int argc, char *argv []) // GPIO Nicies else if (strcasecmp (argv [1], "toggle" ) == 0) doToggle (argc, argv) ; + else if (strcasecmp (argv [1], "blink" ) == 0) doBlink (argc, argv) ; // Pi Specifics @@ -1386,11 +1518,14 @@ int main (int argc, char *argv []) else if (strcasecmp (argv [1], "drive" ) == 0) doPadDrive (argc, argv) ; else if (strcasecmp (argv [1], "readall" ) == 0) doReadall () ; else if (strcasecmp (argv [1], "nreadall" ) == 0) doReadall () ; - else if (strcasecmp (argv [1], "pins" ) == 0) doPins () ; + else if (strcasecmp (argv [1], "pins" ) == 0) doReadall () ; + else if (strcasecmp (argv [1], "qmode" ) == 0) doQmode (argc, argv) ; else if (strcasecmp (argv [1], "i2cdetect") == 0) doI2Cdetect (argc, argv) ; else if (strcasecmp (argv [1], "i2cd" ) == 0) doI2Cdetect (argc, argv) ; else if (strcasecmp (argv [1], "reset" ) == 0) doReset (argv [0]) ; else if (strcasecmp (argv [1], "wb" ) == 0) doWriteByte (argc, argv) ; + else if (strcasecmp (argv [1], "rbx" ) == 0) doReadByte (argc, argv, TRUE) ; + else if (strcasecmp (argv [1], "rbd" ) == 0) doReadByte (argc, argv, FALSE) ; else if (strcasecmp (argv [1], "clock" ) == 0) doClock (argc, argv) ; else if (strcasecmp (argv [1], "wfi" ) == 0) doWfi (argc, argv) ; else @@ -1398,5 +1533,6 @@ int main (int argc, char *argv []) fprintf (stderr, "%s: Unknown command: %s.\n", argv [0], argv [1]) ; exit (EXIT_FAILURE) ; } + return 0 ; } diff --git a/gpio/pintest b/gpio/pintest index 4da3d94..b574361 100644 --- a/gpio/pintest +++ b/gpio/pintest @@ -5,7 +5,7 @@ # Copyright (c) 2013-2015 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/gpio/readall.c b/gpio/readall.c index cb7e18f..9396c6d 100644 --- a/gpio/readall.c +++ b/gpio/readall.c @@ -1,7 +1,7 @@ /* * readall.c: * The readall functions - getting a bit big, so split them out. - * Copyright (c) 2012-2015 Gordon Henderson + * Copyright (c) 2012-2018 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -118,7 +118,7 @@ static char *physNames [64] = NULL, " 3.3v", "5v ", - " SDA.1", "5V ", + " SDA.1", "5v ", " SCL.1", "0v ", "GPIO. 7", "TxD ", " 0v", "RxD ", @@ -287,22 +287,26 @@ void abReadall (int model, int rev) /* * piPlusReadall: - * Read all the pins on the model A+ or the B+ + * Read all the pins on the model A+ or the B+ or actually, all 40-pin Pi's ********************************************************************************* */ static void plus2header (int model) { /**/ if (model == PI_MODEL_AP) - printf (" +-----+-----+---------+------+---+--A Plus--+---+------+---------+-----+-----+\n") ; + printf (" +-----+-----+---------+------+---+---Pi A+--+---+------+---------+-----+-----+\n") ; else if (model == PI_MODEL_BP) - printf (" +-----+-----+---------+------+---+--B Plus--+---+------+---------+-----+-----+\n") ; + printf (" +-----+-----+---------+------+---+---Pi B+--+---+------+---------+-----+-----+\n") ; else if (model == PI_MODEL_ZERO) printf (" +-----+-----+---------+------+---+-Pi Zero--+---+------+---------+-----+-----+\n") ; + else if (model == PI_MODEL_ZERO_W) + printf (" +-----+-----+---------+------+---+-Pi ZeroW-+---+------+---------+-----+-----+\n") ; else if (model == PI_MODEL_2) printf (" +-----+-----+---------+------+---+---Pi 2---+---+------+---------+-----+-----+\n") ; else if (model == PI_MODEL_3) printf (" +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+\n") ; + else if (model == PI_MODEL_3P) + printf (" +-----+-----+---------+------+---+---Pi 3+--+---+------+---------+-----+-----+\n") ; else printf (" +-----+-----+---------+------+---+---Pi ?---+---+------+---------+-----+-----+\n") ; } @@ -346,14 +350,18 @@ void doReadall (void) /**/ if ((model == PI_MODEL_A) || (model == PI_MODEL_B)) abReadall (model, rev) ; - else if ((model == PI_MODEL_BP) || (model == PI_MODEL_AP) || (model == PI_MODEL_2) || (model == PI_MODEL_3) || (model == PI_MODEL_ZERO)) + else if ((model == PI_MODEL_BP) || (model == PI_MODEL_AP) || + (model == PI_MODEL_2) || + (model == PI_MODEL_3) || (model == PI_MODEL_3P) || + (model == PI_MODEL_ZERO) || (model == PI_MODEL_ZERO_W)) piPlusReadall (model) ; - else if (model == PI_MODEL_CM) + else if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) allReadall () ; else printf ("Oops - unable to determine board type... model: %d\n", model) ; } + /* * doAllReadall: * Force reading of all pins regardless of Pi model @@ -364,3 +372,24 @@ void doAllReadall (void) { allReadall () ; } + + +/* + * doQmode: + * Query mode on a pin + ********************************************************************************* + */ + +void doQmode (int argc, char *argv []) +{ + int pin ; + + if (argc != 3) + { + fprintf (stderr, "Usage: %s qmode pin\n", argv [0]) ; + exit (EXIT_FAILURE) ; + } + + pin = atoi (argv [2]) ; + printf ("%s\n", alts [getAlt (pin)]) ; +} diff --git a/gpio/test.sh b/gpio/test.sh index a7c2bb2..708f1d3 100755 --- a/gpio/test.sh +++ b/gpio/test.sh @@ -5,7 +5,7 @@ # in-turn. ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by diff --git a/gpio/version.h b/gpio/version.h deleted file mode 100644 index 5b92dc9..0000000 --- a/gpio/version.h +++ /dev/null @@ -1 +0,0 @@ -#define VERSION "2.32" diff --git a/newVersion b/newVersion index bab6dc5..ed4b438 100644 --- a/newVersion +++ b/newVersion @@ -7,7 +7,7 @@ # Copyright (c) 2012-2015 Gordon Henderson ################################################################################# # This file is part of wiringPi: -# Wiring Compatable library for the Raspberry Pi +# A "wiring" library for the Raspberry Pi # # wiringPi is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -25,8 +25,12 @@ echo Updating to version: `cat VERSION` -rm -f gpio/version.h -echo "#define VERSION \"`cat VERSION`\"" > gpio/version.h +rm -f version.h +vMaj=`cut -d. -f1 VERSION` +vMin=`cut -d. -f2 VERSION` +echo "#define VERSION \"`cat VERSION`\"" > version.h +echo "#define VERSION_MAJOR $vMaj" >> version.h +echo "#define VERSION_MINOR $vMin" >> version.h rm -f debian-template/wiringPi/DEBIAN/control cat > debian-template/wiringPi/DEBIAN/control < Description: The wiringPi libraries, headers and gpio command Libraries to allow GPIO access on a Raspberry Pi from C and C++ - programs as well as from the command-line + and BASIC programs as well as from the command-line EOF diff --git a/update b/update new file mode 100755 index 0000000..0f72243 --- /dev/null +++ b/update @@ -0,0 +1,5 @@ +#!/bin/sh + +# update - update source files from master on yakko + +rsync -aHx --exclude='*.o' --exclude='*~' -v --delete gordon@yakko:rpi/git/wiringPi/ . diff --git a/version.h b/version.h new file mode 100644 index 0000000..242c62b --- /dev/null +++ b/version.h @@ -0,0 +1,3 @@ +#define VERSION "2.46" +#define VERSION_MAJOR 2 +#define VERSION_MINOR 46 diff --git a/wiringPi/Makefile b/wiringPi/Makefile new file mode 100644 index 0000000..287fa58 --- /dev/null +++ b/wiringPi/Makefile @@ -0,0 +1,165 @@ +# +# Makefile: +# wiringPi - Wiring Compatable library for the Raspberry Pi +# +# Copyright (c) 2012-2015 Gordon Henderson +################################################################################# +# This file is part of wiringPi: +# https://projects.drogon.net/raspberry-pi/wiringpi/ +# +# wiringPi is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# wiringPi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with wiringPi. If not, see . +################################################################################# + +VERSION=$(shell cat ../VERSION) +DESTDIR?=/usr +PREFIX?=/local + +LDCONFIG?=ldconfig + +ifneq ($V,1) +Q ?= @ +endif + +STATIC=libwiringPi.a +DYNAMIC=libwiringPi.so.$(VERSION) + +#DEBUG = -g -O0 +DEBUG = -O2 +CC = gcc +INCLUDE = -I. +DEFS = -D_GNU_SOURCE +CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Wextra -Winline $(INCLUDE) -pipe -fPIC +#CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Wextra -Wconversion -Winline $(INCLUDE) -pipe -fPIC + +LIBS = -lm -lpthread -lrt -lcrypt + +############################################################################### + +SRC = wiringPi.c \ + wiringSerial.c wiringShift.c \ + piHiPri.c piThread.c \ + wiringPiSPI.c wiringPiI2C.c \ + softPwm.c softTone.c \ + mcp23008.c mcp23016.c mcp23017.c \ + mcp23s08.c mcp23s17.c \ + sr595.c \ + pcf8574.c pcf8591.c \ + mcp3002.c mcp3004.c mcp4802.c mcp3422.c \ + max31855.c max5322.c ads1115.c \ + sn3218.c \ + bmp180.c htu21d.c ds18b20.c rht03.c \ + drcSerial.c drcNet.c \ + pseudoPins.c \ + wpiExtensions.c + +HEADERS = $(shell ls *.h) + +OBJ = $(SRC:.c=.o) + +all: $(DYNAMIC) + +.PHONY: static +static: + $Q cat noMoreStatic + +$(DYNAMIC): $(OBJ) + $Q echo "[Link (Dynamic)]" + $Q $(CC) -shared -Wl,-soname,libwiringPi.so$(WIRINGPI_SONAME_SUFFIX) -o libwiringPi.so.$(VERSION) $(LIBS) $(OBJ) + +.c.o: + $Q echo [Compile] $< + $Q $(CC) -c $(CFLAGS) $< -o $@ + + +.PHONY: clean +clean: + $Q echo "[Clean]" + $Q rm -f $(OBJ) $(OBJ_I2C) *~ core tags Makefile.bak libwiringPi.* + +.PHONY: tags +tags: $(SRC) + $Q echo [ctags] + $Q ctags $(SRC) + + +.PHONY: install +install: $(DYNAMIC) + $Q echo "[Install Headers]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/include + $Q install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include + $Q echo "[Install Dynamic Lib]" + $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/lib + $Q install -m 0755 libwiringPi.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) + $Q ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so + $Q $(LDCONFIG) + +.PHONY: install-deb +install-deb: $(DYNAMIC) + $Q echo "[Install Headers: deb]" + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/include + $Q install -m 0644 $(HEADERS) ~/wiringPi/debian-template/wiringPi/usr/include + $Q echo "[Install Dynamic Lib: deb]" + install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/lib + install -m 0755 libwiringPi.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so.$(VERSION) + ln -sf ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so + +.PHONY: uninstall +uninstall: + $Q echo "[UnInstall]" + $Q cd $(DESTDIR)$(PREFIX)/include/ && rm -f $(HEADERS) + $Q cd $(DESTDIR)$(PREFIX)/lib/ && rm -f libwiringPi.* + $Q $(LDCONFIG) + + +.PHONY: depend +depend: + makedepend -Y $(SRC) $(SRC_I2C) + +# DO NOT DELETE + +wiringPi.o: softPwm.h softTone.h wiringPi.h ../version.h +wiringSerial.o: wiringSerial.h +wiringShift.o: wiringPi.h wiringShift.h +piHiPri.o: wiringPi.h +piThread.o: wiringPi.h +wiringPiSPI.o: wiringPi.h wiringPiSPI.h +wiringPiI2C.o: wiringPi.h wiringPiI2C.h +softPwm.o: wiringPi.h softPwm.h +softTone.o: wiringPi.h softTone.h +mcp23008.o: wiringPi.h wiringPiI2C.h mcp23x0817.h mcp23008.h +mcp23016.o: wiringPi.h wiringPiI2C.h mcp23016.h mcp23016reg.h +mcp23017.o: wiringPi.h wiringPiI2C.h mcp23x0817.h mcp23017.h +mcp23s08.o: wiringPi.h wiringPiSPI.h mcp23x0817.h mcp23s08.h +mcp23s17.o: wiringPi.h wiringPiSPI.h mcp23x0817.h mcp23s17.h +sr595.o: wiringPi.h sr595.h +pcf8574.o: wiringPi.h wiringPiI2C.h pcf8574.h +pcf8591.o: wiringPi.h wiringPiI2C.h pcf8591.h +mcp3002.o: wiringPi.h wiringPiSPI.h mcp3002.h +mcp3004.o: wiringPi.h wiringPiSPI.h mcp3004.h +mcp4802.o: wiringPi.h wiringPiSPI.h mcp4802.h +mcp3422.o: wiringPi.h wiringPiI2C.h mcp3422.h +max31855.o: wiringPi.h wiringPiSPI.h max31855.h +max5322.o: wiringPi.h wiringPiSPI.h max5322.h +ads1115.o: wiringPi.h wiringPiI2C.h ads1115.h +sn3218.o: wiringPi.h wiringPiI2C.h sn3218.h +bmp180.o: wiringPi.h wiringPiI2C.h bmp180.h +htu21d.o: wiringPi.h wiringPiI2C.h htu21d.h +ds18b20.o: wiringPi.h ds18b20.h +drcSerial.o: wiringPi.h wiringSerial.h drcSerial.h +pseudoPins.o: wiringPi.h pseudoPins.h +wpiExtensions.o: wiringPi.h mcp23008.h mcp23016.h mcp23017.h mcp23s08.h +wpiExtensions.o: mcp23s17.h sr595.h pcf8574.h pcf8591.h mcp3002.h mcp3004.h +wpiExtensions.o: mcp4802.h mcp3422.h max31855.h max5322.h ads1115.h sn3218.h +wpiExtensions.o: drcSerial.h pseudoPins.h bmp180.h htu21d.h ds18b20.h +wpiExtensions.o: wpiExtensions.h diff --git a/wiringPi/ads1115.c b/wiringPi/ads1115.c index 62b92f8..648e612 100644 --- a/wiringPi/ads1115.c +++ b/wiringPi/ads1115.c @@ -228,7 +228,7 @@ static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int data) { if ( (data < 0) || (data > 7) ) // Use default if out of range data = 4 ; - node->data0 = dataRates [data] ; + node->data1 = dataRates [data] ; // Bugfix 0-1 by "Eric de jong (gm)" - Thanks. } } diff --git a/wiringPi/bmp180.c b/wiringPi/bmp180.c new file mode 100644 index 0000000..bad4bb3 --- /dev/null +++ b/wiringPi/bmp180.c @@ -0,0 +1,237 @@ +/* + * bmp180.c: + * Extend wiringPi with the BMP180 I2C Pressure and Temperature + * sensor. This is used in the Pi Weather Station + * Copyright (c) 2016 Gordon Henderson + * + * Information from the document held at: + * http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf + * was very useful when building this code. + * + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include + +#include "wiringPi.h" +#include "wiringPiI2C.h" + +#include "bmp180.h" + +#undef DEBUG + +#define I2C_ADDRESS 0x77 +#define BMP180_OSS 0 + + +// Static calibration data +// The down-side of this is that there can only be one BMP180 in +// a system - which is practice isn't an issue as it's I2C +// address is fixed. + +static int16_t AC1, AC2, AC3 ; +static uint16_t AC4, AC5, AC6 ; +static int16_t VB1, VB2 ; +static int16_t MB, MC, MD ; + +static double c5, c6, mc, md, x0, x1, x2, yy0, yy1, yy2, p0, p1, p2 ; + +// Pressure & Temp variables + +uint32_t cPress, cTemp ; + +static int altitude ; + +/* + * read16: + * Quick hack to read the 16-bit data with the correct endian + ********************************************************************************* + */ + +uint16_t read16 (int fd, int reg) +{ + return (wiringPiI2CReadReg8 (fd, reg) << 8) | wiringPiI2CReadReg8 (fd, reg + 1) ; + +} + + +/* + * bmp180ReadTempPress: + * Does the hard work of reading the sensor + ********************************************************************************* + */ + +static void bmp180ReadTempPress (int fd) +{ + double fTemp, fPress ; + double tu, a ; + double pu, s, x, y, z ; + + uint8_t data [4] ; + +// Start a temperature sensor reading + + wiringPiI2CWriteReg8 (fd, 0xF4, 0x2E) ; + delay (5) ; + +// Read the raw data + + data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ; + data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ; + +// And calculate... + + tu = (data [0] * 256.0) + data [1] ; + + a = c5 * (tu - c6) ; + fTemp = a + (mc / (a + md)) ; + cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ; + +#ifdef DEBUG + printf ("fTemp: %f, cTemp: %6d\n", fTemp, cTemp) ; +#endif + +// Start a pressure snsor reading + + wiringPiI2CWriteReg8 (fd, 0xF4, 0x34 | (BMP180_OSS << 6)) ; + delay (5) ; + +// Read the raw data + + data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ; + data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ; + data [2] = wiringPiI2CReadReg8 (fd, 0xF8) ; + +// And calculate... + + pu = ((double)data [0] * 256.0) + (double)data [1] + ((double)data [2] / 256.0) ; + s = fTemp - 25.0 ; + x = (x2 * pow (s, 2.0)) + (x1 * s) + x0 ; + y = (yy2 * pow (s, 2.0)) + (yy1 * s) + yy0 ; + z = (pu - x) / y ; + fPress = (p2 * pow (z, 2.0)) + (p1 * z) + p0 ; + cPress = (int)rint (((100.0 * fPress) + 0.5) / 10.0) ; + +#ifdef DEBUG + printf ("fPress: %f, cPress: %6d\n", fPress, cPress) ; +#endif +} + + +/* + * myAnalogWrite: + * Write to a fake register to represent the height above sea level + * so that the peudo millibar register can read the pressure in mB + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int chan = pin - node->pinBase ; + + if (chan == 0) + altitude = value ; +} + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int chan = pin - node->pinBase ; + + bmp180ReadTempPress (node->fd) ; + + /**/ if (chan == 0) // Read Temperature + return cTemp ; + else if (chan == 1) // Pressure + return cPress ; + else if (chan == 2) // Pressure in mB + return cPress / pow (1 - ((double)altitude / 44330.0), 5.255) ; + else + return -9999 ; + +} + + +/* + * bmp180Setup: + * Create a new instance of a PCF8591 I2C GPIO interface. We know it + * has 4 pins, (4 analog inputs and 1 analog output which we'll shadow + * input 0) so all we need to know here is the I2C address and the + * user-defined pin base. + ********************************************************************************* + */ + +int bmp180Setup (const int pinBase) +{ + double c3, c4, b1 ; + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 4) ; + + node->fd = fd ; + node->analogRead = myAnalogRead ; + node->analogWrite = myAnalogWrite ; + +// Read calibration data + + AC1 = read16 (fd, 0xAA) ; + AC2 = read16 (fd, 0xAC) ; + AC3 = read16 (fd, 0xAE) ; + AC4 = read16 (fd, 0xB0) ; + AC5 = read16 (fd, 0xB2) ; + AC6 = read16 (fd, 0xB4) ; + VB1 = read16 (fd, 0xB6) ; + VB2 = read16 (fd, 0xB8) ; + MB = read16 (fd, 0xBA) ; + MC = read16 (fd, 0xBC) ; + MD = read16 (fd, 0xBE) ; + +// Calculate coefficients + + c3 = 160.0 * pow (2.0, -15.0) * AC3 ; + c4 = pow (10.0, -3.0) * pow(2.0,-15.0) * AC4 ; + b1 = pow (160.0, 2.0) * pow(2.0,-30.0) * VB1 ; + c5 = (pow (2.0, -15.0) / 160.0) * AC5 ; + c6 = AC6 ; + mc = (pow (2.0, 11.0) / pow(160.0,2.0)) * MC ; + md = MD / 160.0 ; + x0 = AC1 ; + x1 = 160.0 * pow (2.0, -13.0) * AC2 ; + x2 = pow (160.0, 2.0) * pow(2.0,-25.0) * VB2 ; + yy0 = c4 * pow (2.0, 15.0) ; + yy1 = c4 * c3 ; + yy2 = c4 * b1 ; + p0 = (3791.0 - 8.0) / 1600.0 ; + p1 = 1.0 - 7357.0 * pow (2.0, -20.0) ; + p2 = 3038.0 * 100.0 * pow (2.0, -36.0) ; + + return TRUE ; +} diff --git a/wiringPi/bmp180.h b/wiringPi/bmp180.h new file mode 100644 index 0000000..4a6d13a --- /dev/null +++ b/wiringPi/bmp180.h @@ -0,0 +1,34 @@ +/* + * bmp180.h: + * Extend wiringPi with the BMP180 I2C Pressure and Temperature + * sensor. + * Copyright (c) 2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int bmp180Setup (const int pinBase) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/drcNet.c b/wiringPi/drcNet.c new file mode 100644 index 0000000..0964ff7 --- /dev/null +++ b/wiringPi/drcNet.c @@ -0,0 +1,405 @@ +/* + * drcNet.h: + * Extend wiringPi with the DRC Network protocol (e.g. to another Pi) + * Copyright (c) 2016-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "wiringPi.h" +#include "drcNet.h" +#include "../wiringPiD/drcNetCmd.h" + + +/* + * remoteReadline: + * Read in a line of data from the remote server, ending with a newline + * character which is not stored. Returns the length or < 0 on + * any sort of failure. + ********************************************************************************* + */ + +static int remoteReadline (int fd, char *buf, int max) +{ + int len = 0 ; + char c ; + + for (;;) + { + if (read (fd, &c, 1) < 1) + return -1 ; + + if (c == '\n') + return len ; + + *buf++ = c ; + if (++len == max) + return len ; + } +} + + +/* + * getChallenge: + * Read in lines from the remote site until we get one identified + * as the challenge. This line contains the password salt. + ********************************************************************************* + */ + +static char *getChallenge (int fd) +{ + static char buf [1024] ; + int num ; + + for (;;) + { + if ((num = remoteReadline (fd, buf, 1023)) < 0) + return NULL ; + buf [num] = 0 ; + + if (strncmp (buf, "Challenge ", 10) == 0) + return &buf [10] ; + } +} + + +/* + * authenticate: + * Read in the challenge from the server, use it to encrypt our password + * and send it back to the server. Wait for a reply back from the server + * to say that we're good to go. + * The server will simply disconnect on a bad response. No 3 chances here. + ********************************************************************************* + */ + +static int authenticate (int fd, const char *pass) +{ + char *challenge ; + char *encrypted ; + char salted [1024] ; + + if ((challenge = getChallenge (fd)) == NULL) + return -1 ; + + sprintf (salted, "$6$%s$", challenge) ; + encrypted = crypt (pass, salted) ; + +// This is an assertion, or sanity check on my part... +// The '20' comes from the $6$ then the 16 characters of the salt, +// then the terminating $. + + if (strncmp (encrypted, salted, 20) != 0) + { + errno = EBADE ; + return -1 ; + } + +// 86 characters is the length of the SHA-256 hash + + if (write (fd, encrypted + 20, 86) == 86) + return 0 ; + else + return -1 ; +} + + +/* + * _drcSetupNet: + * Do the hard work of establishing a network connection and authenticating + * the password. + ********************************************************************************* + */ + +int _drcSetupNet (const char *ipAddress, const char *port, const char *password) +{ + struct addrinfo hints; + struct addrinfo *result, *rp ; + struct in6_addr serveraddr ; + int remoteFd ; + +// Start by seeing if we've been given a (textual) numeric IP address +// which will save lookups in getaddrinfo() + + memset (&hints, 0, sizeof (hints)) ; + hints.ai_flags = AI_NUMERICSERV ; + hints.ai_family = AF_UNSPEC ; + hints.ai_socktype = SOCK_STREAM ; + hints.ai_protocol = 0 ; + + if (inet_pton (AF_INET, ipAddress, &serveraddr) == 1) // Valid IPv4 + { + hints.ai_family = AF_INET ; + hints.ai_flags |= AI_NUMERICHOST ; + } + else + { + if (inet_pton (AF_INET6, ipAddress, &serveraddr) == 1) // Valid IPv6 + { + hints.ai_family = AF_INET6 ; + hints.ai_flags |= AI_NUMERICHOST ; + } + } + +// Now use getaddrinfo() with the newly supplied hints + + if (getaddrinfo (ipAddress, port, &hints, &result) != 0) + return -1 ; + +// Now try each address in-turn until we get one that connects... + + for (rp = result; rp != NULL; rp = rp->ai_next) + { + if ((remoteFd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) + continue ; + + if (connect (remoteFd, rp->ai_addr, rp->ai_addrlen) < 0) + continue ; + + if (authenticate (remoteFd, password) < 0) + { + close (remoteFd) ; + errno = EACCES ; // Permission denied + return -1 ; + } + else + return remoteFd ; + } + + errno = EHOSTUNREACH ; // Host unreachable - may not be right, but good enough + return -1 ; // Nothing connected +} + + +/* + * myPinMode: + * Change the pin mode on the remote DRC device + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_PIN_MODE ; + cmd.data = mode ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + + +/* + * myPullUpDnControl: + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_PULL_UP_DN ; + cmd.data = mode ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_DIGITAL_WRITE ; + cmd.data = value ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + + +/* + * myDigitalWrite8: + ********************************************************************************* + +static void myDigitalWrite8 (struct wiringPiNodeStruct *node, int pin, int value) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_DIGITAL_WRITE8 ; + cmd.data = value ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + */ + + +/* + * myAnalogWrite: + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_ANALOG_WRITE ; + cmd.data = value ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + + +/* + * myPwmWrite: + ********************************************************************************* + */ + +static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_PWM_WRITE ; + cmd.data = value ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; +} + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_ANALOG_READ ; + cmd.data = 0 ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; + + return cmd.data ; +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_DIGITAL_READ ; + cmd.data = 0 ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; + + return cmd.data ; +} + + +/* + * myDigitalRead8: + ********************************************************************************* + +static unsigned int myDigitalRead8 (struct wiringPiNodeStruct *node, int pin) +{ + struct drcNetComStruct cmd ; + + cmd.pin = pin - node->pinBase ; + cmd.cmd = DRCN_DIGITAL_READ8 ; + cmd.data = 0 ; + + (void)send (node->fd, &cmd, sizeof (cmd), 0) ; + (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; + + return cmd.data ; +} + */ + + +/* + * drcNet: + * Create a new instance of an DRC GPIO interface. + * Could be a variable nunber of pins here - we might not know in advance. + ********************************************************************************* + */ + +int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) +{ + int fd, len ; + struct wiringPiNodeStruct *node ; + + if ((fd = _drcSetupNet (ipAddress, port, password)) < 0) + return FALSE ; + + len = sizeof (struct drcNetComStruct) ; + + if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, numPins) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->analogRead = myAnalogRead ; + node->analogRead = myAnalogRead ; + node->analogWrite = myAnalogWrite ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; +//node->digitalRead8 = myDigitalRead8 ; +//node->digitalWrite8 = myDigitalWrite8 ; + node->pwmWrite = myPwmWrite ; + + return TRUE ; +} diff --git a/wiringPi/drcNet.h b/wiringPi/drcNet.h new file mode 100644 index 0000000..00f9b05 --- /dev/null +++ b/wiringPi/drcNet.h @@ -0,0 +1,42 @@ +/* + * drcNet.h: + * Extend wiringPi with the DRC Network protocol (e.g. to another Pi) + * Copyright (c) 2016-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +/********* +struct drcNetStruct +{ + uint32_t pin ; + uint32_t cmd ; + uint32_t data ; +} ; +**************/ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/ds18b20.c b/wiringPi/ds18b20.c new file mode 100644 index 0000000..533398e --- /dev/null +++ b/wiringPi/ds18b20.c @@ -0,0 +1,146 @@ +/* + * ds18b20.c: + * Extend wiringPi with the DS18B20 1-Wire temperature sensor. + * This is used in the Pi Weather Station and many other places. + * Copyright (c) 2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "wiringPi.h" + +#include "ds18b20.h" + +#define W1_PREFIX "/sys/bus/w1/devices/28-" +#define W1_POSTFIX "/w1_slave" + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int chan = pin - node->pinBase ; + int fd = node->fd ; + char buffer [4096] ; + char *p ; + int temp, sign ; + + if (chan != 0) + return -9999 ; + +// Rewind the file - we're keeping it open to keep things going +// smoothly + + lseek (fd, 0, SEEK_SET) ; + +// Read the file - we know it's only a couple of lines, so this ought to be +// more than enough + + if (read (fd, buffer, 4096) <= 0) // Read nothing, or it failed in some odd way + return -9998 ; + +// Look for YES, then t= + + if (strstr (buffer, "YES") == NULL) + return -9997 ; + + if ((p = strstr (buffer, "t=")) == NULL) + return -9996 ; + +// p points to the 't', so we skip over it... + + p += 2 ; + +// and extract the number +// (without caring about overflow) + + + if (*p == '-') // Negative number? + { + sign = -1 ; + ++p ; + } + else + sign = 1 ; + + temp = 0 ; + while (isdigit (*p)) + { + temp = temp * 10 + (*p - '0') ; + ++p ; + } + +// We know it returns temp * 1000, but we only really want temp * 10, so +// do a bit of rounding... + + temp = (temp + 50) / 100 ; + return temp * sign ; +} + + +/* + * ds18b20Setup: + * Create a new instance of a DS18B20 temperature sensor. + ********************************************************************************* + */ + +int ds18b20Setup (const int pinBase, const char *deviceId) +{ + int fd ; + struct wiringPiNodeStruct *node ; + char *fileName ; + +// Allocate space for the filename + + if ((fileName = malloc (strlen (W1_PREFIX) + strlen (W1_POSTFIX) + strlen (deviceId) + 1)) == NULL) + return FALSE ; + + sprintf (fileName, "%s%s%s", W1_PREFIX, deviceId, W1_POSTFIX) ; + + fd = open (fileName, O_RDONLY) ; + + free (fileName) ; + + if (fd < 0) + return FALSE ; + +// We'll keep the file open, to make access a little faster +// although it's very slow reading these things anyway )-: + + node = wiringPiNewNode (pinBase, 1) ; + + node->fd = fd ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/wiringPi/ds18b20.h b/wiringPi/ds18b20.h new file mode 100644 index 0000000..a9ea291 --- /dev/null +++ b/wiringPi/ds18b20.h @@ -0,0 +1,34 @@ +/* + * bmp180.h: + * Extend wiringPi with the BMP180 I2C Pressure and Temperature + * sensor. + * Copyright (c) 2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ds18b20Setup (const int pinBase, const char *serialNum) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/htu21d.c b/wiringPi/htu21d.c new file mode 100644 index 0000000..46c0fcb --- /dev/null +++ b/wiringPi/htu21d.c @@ -0,0 +1,150 @@ +/* + * htu21d.c: + * Extend wiringPi with the HTU21D I2C humidity and Temperature + * sensor. This is used in the Pi Weather station. + * Copyright (c) 2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include + +#include "wiringPi.h" +#include "wiringPiI2C.h" + +#include "htu21d.h" + +#define DEBUG +#undef FAKE_SENSOR + +#define I2C_ADDRESS 0x40 + +int checksum (UNU uint8_t data [4]) +{ + return TRUE ; +} + + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int chan = pin - node->pinBase ; + int fd = node->fd ; + uint8_t data [4] ; + uint32_t sTemp, sHumid ; + double fTemp, fHumid ; + int cTemp, cHumid ; + + /**/ if (chan == 0) // Read Temperature + { + +// Send read temperature command: + + data [0] = 0xF3 ; + if (write (fd, data, 1) != 1) + return -9999 ; + +// Wait then read the data + + delay (50) ; + if (read (fd, data, 3) != 3) + return -9998 ; + + if (!checksum (data)) + return -9997 ; + +// Do the calculation + + sTemp = (data [0] << 8) | data [1] ; + fTemp = -48.85 + 175.72 * (double)sTemp / 63356.0 ; + cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ; + return cTemp ; + } + else if (chan == 1) // humidity + { +// Send read humidity command: + + data [0] = 0xF5 ; + if (write (fd, data, 1) != 1) + return -9999 ; + +// Wait then read the data + + delay (50) ; + if (read (fd, data, 3) != 3) + return -9998 ; + + if (!checksum (data)) + return -9997 ; + + sHumid = (data [0] << 8) | data [1] ; + fHumid = -6.0 + 125.0 * (double)sHumid / 65536.0 ; + cHumid = (int)rint (((100.0 * fHumid) + 0.5) / 10.0) ; + return cHumid ; + } + else + return -9999 ; +} + + +/* + * htu21dSetup: + * Create a new instance of a HTU21D I2C GPIO interface. + * This chip has a fixed I2C address, so we are not providing any + * allowance to change this. + ********************************************************************************* + */ + +int htu21dSetup (const int pinBase) +{ + int fd ; + struct wiringPiNodeStruct *node ; + uint8_t data ; + int status ; + + if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 2) ; + + node->fd = fd ; + node->analogRead = myAnalogRead ; + +// Send a reset code to it: + + data = 0xFE ; + if (write (fd, &data, 1) != 1) + return FALSE ; + + delay (15) ; + +// Read the status register to check it's really there + + status = wiringPiI2CReadReg8 (fd, 0xE7) ; + + return (status == 0x02) ? TRUE : FALSE ; +} diff --git a/wiringPi/htu21d.h b/wiringPi/htu21d.h new file mode 100644 index 0000000..3965c54 --- /dev/null +++ b/wiringPi/htu21d.h @@ -0,0 +1,34 @@ +/* + * htu21d.h: + * Extend wiringPi with the HTU21D I2C Humidity and Temperature + * sensor. + * Copyright (c) 2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int htu21dSetup (const int pinBase) ; + +#ifdef __cplusplus +} +#endif diff --git a/wiringPi/mcp3002.c b/wiringPi/mcp3002.c index 8e191b6..9ebf3e4 100644 --- a/wiringPi/mcp3002.c +++ b/wiringPi/mcp3002.c @@ -49,7 +49,7 @@ static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) wiringPiSPIDataRW (node->fd, spiData, 2) ; - return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ; + return ((spiData [0] << 8) | (spiData [1] >> 1)) & 0x3FF ; } diff --git a/wiringPi/noMoreStatic b/wiringPi/noMoreStatic new file mode 100644 index 0000000..1d25942 --- /dev/null +++ b/wiringPi/noMoreStatic @@ -0,0 +1,20 @@ + +wiringPi is no-longer shipped with the ability to statically link it. + +Many reasons but the biggest issue is people who have statically linked +wiringPi into their product - for example a Pi UPS device or a Tetris-like +game and not subsequently shipped their modified sources. These people are +no better than common thieves with complete disregard to the conditions +of the LGPL that wiringPi ships with. + +Additionally, many think it's a good idea to statically link wiringPi +into their favourite language - like Node, and Java and other itsy bitsy +little things. These people have a complete and utter disregard to what +happens underneath when e.g. the Linux kernel changes on the Pi then +wiringPi stops as it depends on some Pi kernel features, then the poor +user get in-touch with me and I've had over 10,000 emails so-far and +it's now beyond a joke. + +DO NOT STATICALLY LINK WIRINGPI. + +Gordon Henderson, March 2018. diff --git a/wiringPi/pcf8591.c b/wiringPi/pcf8591.c index 0c43d26..66c6255 100644 --- a/wiringPi/pcf8591.c +++ b/wiringPi/pcf8591.c @@ -36,7 +36,7 @@ ********************************************************************************* */ -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +static void myAnalogWrite (struct wiringPiNodeStruct *node, UNU int pin, int value) { unsigned char b [2] ; b [0] = 0x40 ; diff --git a/wiringPi/pseudoPins.c b/wiringPi/pseudoPins.c new file mode 100644 index 0000000..c2bf5e0 --- /dev/null +++ b/wiringPi/pseudoPins.c @@ -0,0 +1,95 @@ +/* + * pseudoPins.c: + * Extend wiringPi with a number of pseudo pins which can be + * digitally or analog written/read. + * + * Note: + * Just one set of pseudo pins can exist per Raspberry Pi. + * These pins are shared between all programs running on + * that Raspberry Pi. The values are also persistant as + * they live in shared RAM. This gives you a means for + * temporary variable storing/sharing between programs, + * or for other cunning things I've not thought of yet.. + * + * Copyright (c) 2012-2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#define SHARED_NAME "wiringPiPseudoPins" +#define PSEUDO_PINS 64 + +#include +#include +#include +#include +#include + +#include + +#include "pseudoPins.h" + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int *ptr = (int *)node->data0 ; + int myPin = pin - node->pinBase ; + + return *(ptr + myPin) ; +} + + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int *ptr = (int *)node->data0 ; + int myPin = pin - node->pinBase ; + + *(ptr + myPin) = value ; +} + + +/* + * pseudoPinsSetup: + * Create a new wiringPi device node for the pseudoPins driver + ********************************************************************************* + */ + +int pseudoPinsSetup (const int pinBase) +{ + struct wiringPiNodeStruct *node ; + void *ptr ; + + node = wiringPiNewNode (pinBase, PSEUDO_PINS) ; + + node->fd = shm_open (SHARED_NAME, O_CREAT | O_RDWR, 0666) ; + + if (node->fd < 0) + return FALSE ; + + if (ftruncate (node->fd, PSEUDO_PINS * sizeof (int)) < 0) + return FALSE ; + + ptr = mmap (NULL, PSEUDO_PINS * sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, 0) ; + + node->data0 = (unsigned int)ptr ; + + node->analogRead = myAnalogRead ; + node->analogWrite = myAnalogWrite ; + + return TRUE ; +} diff --git a/wiringPi/pseudoPins.h b/wiringPi/pseudoPins.h new file mode 100644 index 0000000..bef4660 --- /dev/null +++ b/wiringPi/pseudoPins.h @@ -0,0 +1,26 @@ +/* + * pseudoPins.h: + * Extend wiringPi with a number of pseudo pins which can be + * digitally or analog written/read. + * Copyright (c) 2012-2016 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +extern int pseudoPinsSetup (const int pinBase) ; diff --git a/wiringPi/rht03.c b/wiringPi/rht03.c new file mode 100644 index 0000000..1129cfd --- /dev/null +++ b/wiringPi/rht03.c @@ -0,0 +1,252 @@ +/* + * rht03.c: + * Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. + * Copyright (c) 2016-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include + +#include "wiringPi.h" +#include "rht03.h" + +/* + * maxDetectLowHighWait: + * Wait for a transition from low to high on the bus + ********************************************************************************* + */ + +static int maxDetectLowHighWait (const int pin) +{ + struct timeval now, timeOut, timeUp ; + +// If already high then wait for pin to go low + + gettimeofday (&now, NULL) ; + timerclear (&timeOut) ; + timeOut.tv_usec = 1000 ; + timeradd (&now, &timeOut, &timeUp) ; + + while (digitalRead (pin) == HIGH) + { + gettimeofday (&now, NULL) ; + if (timercmp (&now, &timeUp, >)) + return FALSE ; + } + +// Wait for it to go HIGH + + gettimeofday (&now, NULL) ; + timerclear (&timeOut) ; + timeOut.tv_usec = 1000 ; + timeradd (&now, &timeOut, &timeUp) ; + + while (digitalRead (pin) == LOW) + { + gettimeofday (&now, NULL) ; + if (timercmp (&now, &timeUp, >)) + return FALSE ; + } + + return TRUE ; +} + + +/* + * maxDetectClockByte: + * Read in a single byte from the MaxDetect bus + ********************************************************************************* + */ + +static unsigned int maxDetectClockByte (const int pin) +{ + unsigned int byte = 0 ; + int bit ; + + for (bit = 0 ; bit < 8 ; ++bit) + { + if (!maxDetectLowHighWait (pin)) + return 0 ; + +// bit starting now - we need to time it. + + delayMicroseconds (30) ; + byte <<= 1 ; + if (digitalRead (pin) == HIGH) // It's a 1 + byte |= 1 ; + } + + return byte ; +} + + +/* + * maxDetectRead: + * Read in and return the 4 data bytes from the MaxDetect sensor. + * Return TRUE/FALSE depending on the checksum validity + ********************************************************************************* + */ + +static int maxDetectRead (const int pin, unsigned char buffer [4]) +{ + int i ; + unsigned int checksum ; + unsigned char localBuf [5] ; + struct timeval now, then, took ; + +// See how long we took + + gettimeofday (&then, NULL) ; + +// Wake up the RHT03 by pulling the data line low, then high +// Low for 10mS, high for 40uS. + + pinMode (pin, OUTPUT) ; + digitalWrite (pin, 0) ; delay (10) ; + digitalWrite (pin, 1) ; delayMicroseconds (40) ; + pinMode (pin, INPUT) ; + +// Now wait for sensor to pull pin low + + if (!maxDetectLowHighWait (pin)) + return FALSE ; + +// and read in 5 bytes (40 bits) + + for (i = 0 ; i < 5 ; ++i) + localBuf [i] = maxDetectClockByte (pin) ; + + checksum = 0 ; + for (i = 0 ; i < 4 ; ++i) + { + buffer [i] = localBuf [i] ; + checksum += localBuf [i] ; + } + checksum &= 0xFF ; + +// See how long we took + + gettimeofday (&now, NULL) ; + timersub (&now, &then, &took) ; + +// Total time to do this should be: +// 10mS + 40µS - reset +// + 80µS + 80µS - sensor doing its low -> high thing +// + 40 * (50µS + 27µS (0) or 70µS (1) ) +// = 15010µS +// so if we take more than that, we've had a scheduling interruption and the +// reading is probably bogus. + + if ((took.tv_sec != 0) || (took.tv_usec > 16000)) + return FALSE ; + + return checksum == localBuf [4] ; +} + + +/* + * myReadRHT03: + * Read the Temperature & Humidity from an RHT03 sensor + * Values returned are *10, so 123 is 12.3. + ********************************************************************************* + */ + +static int myReadRHT03 (const int pin, int *temp, int *rh) +{ + int result ; + unsigned char buffer [4] ; + +// Read ... + + result = maxDetectRead (pin, buffer) ; + + if (!result) + return FALSE ; + + *rh = (buffer [0] * 256 + buffer [1]) ; + *temp = (buffer [2] * 256 + buffer [3]) ; + + if ((*temp & 0x8000) != 0) // Negative + { + *temp &= 0x7FFF ; + *temp = -*temp ; + } + +// Discard obviously bogus readings - the checksum can't detect a 2-bit error +// (which does seem to happen - no realtime here) + + if ((*rh > 999) || (*temp > 800) || (*temp < -400)) + return FALSE ; + + return TRUE ; +} + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int piPin = node->fd ; + int chan = pin - node->pinBase ; + int temp = -9997 ; + int rh = -9997 ; + int try ; + + if (chan > 1) + return -9999 ; // Bad parameters + + for (try = 0 ; try < 10 ; ++try) + { + if (myReadRHT03 (piPin, &temp, &rh)) + return chan == 0 ? temp : rh ; + } + + return -9998 ; +} + + +/* + * rht03Setup: + * Create a new instance of an RHT03 temperature sensor. + ********************************************************************************* + */ + +int rht03Setup (const int pinBase, const int piPin) +{ + struct wiringPiNodeStruct *node ; + + if ((piPin & PI_GPIO_MASK) != 0) // Must be an on-board pin + return FALSE ; + +// 2 pins - temperature and humidity + + node = wiringPiNewNode (pinBase, 2) ; + + node->fd = piPin ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/wiringPi/rht03.h b/wiringPi/rht03.h new file mode 100644 index 0000000..9523fbf --- /dev/null +++ b/wiringPi/rht03.h @@ -0,0 +1,25 @@ +/* + * rht03.h: + * Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. + * Copyright (c) 2016-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with wiringPi. + * If not, see . + *********************************************************************** + */ + +extern int rht03Setup (const int pinBase, const int devicePin) ; diff --git a/wiringPi/softPwm.c b/wiringPi/softPwm.c index 98b408f..d99fa00 100644 --- a/wiringPi/softPwm.c +++ b/wiringPi/softPwm.c @@ -1,7 +1,7 @@ /* * softPwm.c: - * Provide 2 channels of software driven PWM. - * Copyright (c) 2012-2014 Gordon Henderson + * Provide many channels of software driven PWM. + * Copyright (c) 2012-2017 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -23,17 +23,18 @@ */ #include +#include #include #include "wiringPi.h" #include "softPwm.h" // MAX_PINS: -// This is more than the number of Pi pins because we can actually softPwm -// pins that are on GPIO expanders. It's not that efficient and more than 1 or -// 2 pins on e.g. (SPI) mcp23s17 won't really be that effective, however... +// This is more than the number of Pi pins because we can actually softPwm. +// Once upon a time I let pins on gpio expanders be softPwm'd, but it's really +// really not a good thing. -#define MAX_PINS 1024 +#define MAX_PINS 64 // The PWM Frequency is derived from the "pulse time" below. Essentially, // the frequency is a function of the range and this pulse time. @@ -44,7 +45,7 @@ // It's possible to get a higher frequency by lowering the pulse time, // however CPU uage will skyrocket as wiringPi uses a hard-loop to time // periods under 100µS - this is because the Linux timer calls are just -// accurate at all, and have an overhead. +// not accurate at all, and have an overhead. // // Another way to increase the frequency is to reduce the range - however // that reduces the overall output accuracy... @@ -63,7 +64,7 @@ static volatile int newPin = -1 ; ********************************************************************************* */ -static PI_THREAD (softPwmThread) +static void *softPwmThread (void *arg) { int pin, mark, space ; struct sched_param param ; @@ -71,6 +72,9 @@ static PI_THREAD (softPwmThread) param.sched_priority = sched_get_priority_max (SCHED_RR) ; pthread_setschedparam (pthread_self (), SCHED_RR, ¶m) ; + pin = *((int *)arg) ; + free (arg) ; + pin = newPin ; newPin = -1 ; @@ -102,14 +106,15 @@ static PI_THREAD (softPwmThread) void softPwmWrite (int pin, int value) { - pin &= (MAX_PINS - 1) ; - - /**/ if (value < 0) - value = 0 ; - else if (value > range [pin]) - value = range [pin] ; + if (pin < MAX_PINS) + { + /**/ if (value < 0) + value = 0 ; + else if (value > range [pin]) + value = range [pin] ; - marks [pin] = value ; + marks [pin] = value ; + } } @@ -123,21 +128,30 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) { int res ; pthread_t myThread ; + int *passPin ; + + if (pin >= MAX_PINS) + return -1 ; if (range [pin] != 0) // Already running on this pin return -1 ; - if (range <= 0) + if (pwmRange <= 0) + return -1 ; + + passPin = malloc (sizeof (*passPin)) ; + if (passPin == NULL) return -1 ; - pinMode (pin, OUTPUT) ; digitalWrite (pin, LOW) ; + pinMode (pin, OUTPUT) ; marks [pin] = initialValue ; range [pin] = pwmRange ; - newPin = pin ; - res = pthread_create (&myThread, NULL, softPwmThread, NULL) ; + *passPin = pin ; + newPin = pin ; + res = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ; while (newPin != -1) delay (1) ; @@ -156,11 +170,14 @@ int softPwmCreate (int pin, int initialValue, int pwmRange) void softPwmStop (int pin) { - if (range [pin] != 0) + if (pin < MAX_PINS) { - pthread_cancel (threads [pin]) ; - pthread_join (threads [pin], NULL) ; - range [pin] = 0 ; - digitalWrite (pin, LOW) ; + if (range [pin] != 0) + { + pthread_cancel (threads [pin]) ; + pthread_join (threads [pin], NULL) ; + range [pin] = 0 ; + digitalWrite (pin, LOW) ; + } } } diff --git a/wiringPi/wiringPi.c b/wiringPi/wiringPi.c index dfd5de4..586b148 100644 --- a/wiringPi/wiringPi.c +++ b/wiringPi/wiringPi.c @@ -1,7 +1,7 @@ /* * wiringPi: * Arduino look-a-like Wiring library for the Raspberry Pi - * Copyright (c) 2012-2015 Gordon Henderson + * Copyright (c) 2012-2017 Gordon Henderson * Additional code for pwmSetClock by Chris Hall * * Thanks to code samples from Gert Jan van Loo and the @@ -75,6 +75,7 @@ #include "softTone.h" #include "wiringPi.h" +#include "../version.h" // Environment Variables @@ -83,10 +84,8 @@ #define ENV_GPIOMEM "WIRINGPI_GPIOMEM" -// Mask for the bottom 64 pins which belong to the Raspberry Pi -// The others are available for the other devices - -#define PI_GPIO_MASK (0xFFFFFFC0) +// Extend wiringPi with other pin-based devices and keep track of +// them in this structure struct wiringPiNodeStruct *wiringPiNodes = NULL ; @@ -129,9 +128,8 @@ struct wiringPiNodeStruct *wiringPiNodes = NULL ; // that I can find )-: // // Updates in September 2015 - all now static variables (and apologies for the caps) -// due to the Pi v2 and the new /dev/gpiomem interface +// due to the Pi v2, v3, etc. and the new /dev/gpiomem interface -static volatile unsigned int RASPBERRY_PI_PERI_BASE ; static volatile unsigned int GPIO_PADS ; static volatile unsigned int GPIO_CLOCK_BASE ; static volatile unsigned int GPIO_BASE ; @@ -141,6 +139,9 @@ static volatile unsigned int GPIO_PWM ; #define PAGE_SIZE (4*1024) #define BLOCK_SIZE (4*1024) +static unsigned int usingGpioMem = FALSE ; +static int wiringPiSetuped = FALSE ; + // PWM // Word offsets into the PWM control region @@ -187,15 +188,21 @@ static volatile unsigned int GPIO_PWM ; // Locals to hold pointers to the hardware -static volatile uint32_t *gpio ; -static volatile uint32_t *pwm ; -static volatile uint32_t *clk ; -static volatile uint32_t *pads ; +static volatile unsigned int *gpio ; +static volatile unsigned int *pwm ; +static volatile unsigned int *clk ; +static volatile unsigned int *pads ; +static volatile unsigned int *timer ; +static volatile unsigned int *timerIrqRaw ; -#ifdef USE_TIMER -static volatile uint32_t *timer ; -static volatile uint32_t *timerIrqRaw ; -#endif +// Export variables for the hardware pointers + +volatile unsigned int *_wiringPiGpio ; +volatile unsigned int *_wiringPiPwm ; +volatile unsigned int *_wiringPiClk ; +volatile unsigned int *_wiringPiPads ; +volatile unsigned int *_wiringPiTimer ; +volatile unsigned int *_wiringPiTimerIrqRaw ; // Data for use with the boardId functions. @@ -203,7 +210,13 @@ static volatile uint32_t *timerIrqRaw ; // and PI_VERSION_X defines in wiringPi.h // Only intended for the gpio command - use at your own risk! -static int piModel2 = FALSE ; +// piGpioBase: +// The base address of the GPIO memory mapped hardware IO + +#define GPIO_PERI_BASE_OLD 0x20000000 +#define GPIO_PERI_BASE_NEW 0x3F000000 + +static volatile unsigned int piGpioBase = 0 ; const char *piModelNames [16] = { @@ -217,10 +230,10 @@ const char *piModelNames [16] = "Unknown07", // 07 "Pi 3", // 08 "Pi Zero", // 09 - "Unknown10", // 10 + "CM3", // 10 "Unknown11", // 11 - "Unknown12", // 12 - "Unknown13", // 13 + "Pi Zero-W", // 12 + "Pi 3+", // 13 "Unknown14", // 14 "Unknown15", // 15 } ; @@ -649,7 +662,42 @@ int wiringPiFailure (int fatal, const char *message, ...) /* - * piBoardRev: + * setupCheck + * Another sanity check because some users forget to call the setup + * function. Mosty because they need feeding C drip by drip )-: + ********************************************************************************* + */ + +static void setupCheck (const char *fName) +{ + if (!wiringPiSetuped) + { + fprintf (stderr, "%s: You have not called one of the wiringPiSetup\n" + " functions, so I'm aborting your program before it crashes anyway.\n", fName) ; + exit (EXIT_FAILURE) ; + } +} + +/* + * gpioMemCheck: + * See if we're using the /dev/gpiomem interface, if-so then some operations + * can't be done and will crash the Pi. + ********************************************************************************* + */ + +static void usingGpioMemCheck (const char *what) +{ + if (usingGpioMem) + { + fprintf (stderr, "%s: Unable to do this when using /dev/gpiomem. Try sudo?\n", what) ; + exit (EXIT_FAILURE) ; + } +} + + + +/* + * piGpioLayout: * Return a number representing the hardware revision of the board. * This is not strictly the board revision but is used to check the * layout of the GPIO connector - and there are 2 types that we are @@ -666,30 +714,34 @@ int wiringPiFailure (int fatal, const char *message, ...) * 3 GPIO pins on the (original) 26-way header - BCM_GPIO 22 was dropped and * replaced with 27, and 0 + 1 - I2C bus 0 was changed to 2 + 3; I2C bus 1. * + * Additionally, here we set the piModel2 flag too. This is again, nothing to + * do with the actual model, but the major version numbers - the GPIO base + * hardware address changed at model 2 and above (not the Zero though) + * ********************************************************************************* */ -static void piBoardRevOops (const char *why) +static void piGpioLayoutOops (const char *why) { - fprintf (stderr, "piBoardRev: Unable to determine board revision from /proc/cpuinfo\n") ; + fprintf (stderr, "Oops: Unable to determine board revision from /proc/cpuinfo\n") ; fprintf (stderr, " -> %s\n", why) ; - fprintf (stderr, " -> You may want to check:\n") ; - fprintf (stderr, " -> http://www.raspberrypi.org/phpBB3/viewtopic.php?p=184410#p184410\n") ; + fprintf (stderr, " -> You'd best google the error to find out why.\n") ; +//fprintf (stderr, " -> http://www.raspberrypi.org/phpBB3/viewtopic.php?p=184410#p184410\n") ; exit (EXIT_FAILURE) ; } -int piBoardRev (void) +int piGpioLayout (void) { FILE *cpuFd ; char line [120] ; char *c ; - static int boardRev = -1 ; + static int gpioLayout = -1 ; - if (boardRev != -1) // No point checking twice - return boardRev ; + if (gpioLayout != -1) // No point checking twice + return gpioLayout ; if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) - piBoardRevOops ("Unable to open /proc/cpuinfo") ; + piGpioLayoutOops ("Unable to open /proc/cpuinfo") ; // Start by looking for the Architecture to make sure we're really running // on a Pi. I'm getting fed-up with people whinging at me because @@ -700,32 +752,51 @@ int piBoardRev (void) break ; if (strncmp (line, "Hardware", 8) != 0) - piBoardRevOops ("No hardware line") ; + piGpioLayoutOops ("No \"Hardware\" line") ; if (wiringPiDebug) - printf ("piboardRev: Hardware: %s\n", line) ; + printf ("piGpioLayout: Hardware: %s\n", line) ; -// See if it's BCM2708 or BCM2709 +// See if it's BCM2708 or BCM2709 or the new BCM2835. - if (strstr (line, "BCM2709") != NULL) // Pi v2 - no point doing anything more at this point - { - piModel2 = TRUE ; - fclose (cpuFd) ; - return boardRev = 2 ; - } - else if (strstr (line, "BCM2708") == NULL) +// OK. As of Kernel 4.8, we have BCM2835 only, regardless of model. +// However I still want to check because it will trap the cheapskates and rip- +// off merchants who want to use wiringPi on non-Raspberry Pi platforms - which +// I do not support so don't email me your bleating whinges about anything +// other than a genuine Raspberry Pi. + +#ifdef DONT_CARE_ANYMORE + if (! (strstr (line, "BCM2708") || strstr (line, "BCM2709") || strstr (line, "BCM2835"))) { fprintf (stderr, "Unable to determine hardware version. I see: %s,\n", line) ; - fprintf (stderr, " - expecting BCM2708 or BCM2709.\n") ; + fprintf (stderr, " - expecting BCM2708, BCM2709 or BCM2835.\n") ; fprintf (stderr, "If this is a genuine Raspberry Pi then please report this\n") ; fprintf (stderr, "to projects@drogon.net. If this is not a Raspberry Pi then you\n") ; fprintf (stderr, "are on your own as wiringPi is designed to support the\n") ; fprintf (stderr, "Raspberry Pi ONLY.\n") ; exit (EXIT_FAILURE) ; } +#endif + +// Actually... That has caused me more than 10,000 emails so-far. Mosty by +// people who think they know better by creating a statically linked +// version that will not run with a new 4.9 kernel. I utterly hate and +// despise those people. +// +// I also get bleats from people running other than Raspbian with another +// distros compiled kernel rather than a foundation compiled kernel, so +// this might actually help them. It might not - I only have the capacity +// to support Raspbian. +// +// However, I've decided to leave this check out and rely purely on the +// Revision: line for now. It will not work on a non-pi hardware or weird +// kernels that don't give you a suitable revision line. -// Now do the rest of it as before - we just need to see if it's an older -// Rev 1 as anything else is rev 2. +// So - we're Probably on a Raspberry Pi. Check the revision field for the real +// hardware type +// In-future, I ought to use the device tree as there are now Pi entries in +// /proc/device-tree/ ... +// but I'll leave that for the next revision. Or the next. // Isolate the Revision line @@ -737,7 +808,7 @@ int piBoardRev (void) fclose (cpuFd) ; if (strncmp (line, "Revision", 8) != 0) - piBoardRevOops ("No \"Revision\" line") ; + piGpioLayoutOops ("No \"Revision\" line") ; // Chomp trailing CR/NL @@ -745,7 +816,7 @@ int piBoardRev (void) *c = 0 ; if (wiringPiDebug) - printf ("piboardRev: Revision string: %s\n", line) ; + printf ("piGpioLayout: Revision string: %s\n", line) ; // Scan to the first character of the revision number @@ -754,7 +825,7 @@ int piBoardRev (void) break ; if (*c != ':') - piBoardRevOops ("Bogus \"Revision\" line (no colon)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; // Chomp spaces @@ -763,47 +834,44 @@ int piBoardRev (void) ++c ; if (!isxdigit (*c)) - piBoardRevOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; // Make sure its long enough if (strlen (c) < 4) - piBoardRevOops ("Bogus revision line (too small)") ; - -// If you have overvolted the Pi, then it appears that the revision -// has 100000 added to it! -// The actual condition for it being set is: -// (force_turbo || current_limit_override || temp_limit>85) && over_voltage>0 - + piGpioLayoutOops ("Bogus revision line (too small)") ; -// This test is not correct for the new encoding scheme, so we'll remove it here as -// we don't really need it at this point. - -/******************** - if (wiringPiDebug) - if (strlen (c) != 4) - printf ("piboardRev: This Pi has/is (force_turbo || current_limit_override || temp_limit>85) && over_voltage>0\n") ; -*******************/ - -// Isolate last 4 characters: +// Isolate last 4 characters: (in-case of overvolting or new encoding scheme) c = c + strlen (c) - 4 ; if (wiringPiDebug) - printf ("piboardRev: last4Chars are: \"%s\"\n", c) ; + printf ("piGpioLayout: last4Chars are: \"%s\"\n", c) ; if ( (strcmp (c, "0002") == 0) || (strcmp (c, "0003") == 0)) - boardRev = 1 ; + gpioLayout = 1 ; else - boardRev = 2 ; // Covers everything else from the B revision 2 to the B+, the Pi v2 and CM's. + gpioLayout = 2 ; // Covers everything else from the B revision 2 to the B+, the Pi v2, v3, zero and CM's. if (wiringPiDebug) - printf ("piBoardRev: Returning revision: %d\n", boardRev) ; + printf ("piGpioLayoutOops: Returning revision: %d\n", gpioLayout) ; + + return gpioLayout ; +} - return boardRev ; +/* + * piBoardRev: + * Deprecated, but does the same as piGpioLayout + ********************************************************************************* + */ + +int piBoardRev (void) +{ + return piGpioLayout () ; } + /* * piBoardId: * Return the real details of the board we have. @@ -822,20 +890,32 @@ int piBoardRev (void) * 0003 - Model B, Rev 1.1, 256MB, Egoman, Fuses/D14 removed. * * Newer Pi's with remapped GPIO: - * 0004 - Model B, Rev 2, 256MB, Sony - * 0005 - Model B, Rev 2, 256MB, Qisda - * 0006 - Model B, Rev 2, 256MB, Egoman - * 0007 - Model A, Rev 2, 256MB, Egoman - * 0008 - Model A, Rev 2, 256MB, Sony - * 0009 - Model A, Rev 2, 256MB, Qisda - * 000d - Model B, Rev 2, 512MB, Egoman (Red Pi, Blue Pi?) - * 000e - Model B, Rev 2, 512MB, Sony - * 000f - Model B, Rev 2, 512MB, Qisda + * 0004 - Model B, Rev 1.2, 256MB, Sony + * 0005 - Model B, Rev 1.2, 256MB, Egoman + * 0006 - Model B, Rev 1.2, 256MB, Egoman + * + * 0007 - Model A, Rev 1.2, 256MB, Egoman + * 0008 - Model A, Rev 1.2, 256MB, Sony + * 0009 - Model A, Rev 1.2, 256MB, Egoman + * + * 000d - Model B, Rev 1.2, 512MB, Egoman (Red Pi, Blue Pi?) + * 000e - Model B, Rev 1.2, 512MB, Sony + * 000f - Model B, Rev 1.2, 512MB, Egoman + * * 0010 - Model B+, Rev 1.2, 512MB, Sony - * 0011 - Pi CM, Rev 1.2, 512MB, Sony - * 0012 - Model A+ Rev 1.2, 256MB, Sony - * 0014 - Pi CM, Rev 1.1, 512MB, Sony (Actual Revision might be different) - * 0015 - Model A+ Rev 1.1, 256MB, Sony + * 0013 - Model B+ Rev 1.2, 512MB, Embest + * 0016 - Model B+ Rev 1.2, 512MB, Sony + * 0019 - Model B+ Rev 1.2, 512MB, Egoman + * + * 0011 - Pi CM, Rev 1.1, 512MB, Sony + * 0014 - Pi CM, Rev 1.1, 512MB, Embest + * 0017 - Pi CM, Rev 1.1, 512MB, Sony + * 001a - Pi CM, Rev 1.1, 512MB, Egoman + * + * 0012 - Model A+ Rev 1.1, 256MB, Sony + * 0015 - Model A+ Rev 1.1, 512MB, Embest + * 0018 - Model A+ Rev 1.1, 256MB, Sony + * 001b - Model A+ Rev 1.1, 256MB, Egoman * * A small thorn is the olde style overvolting - that will add in * 1000000 @@ -870,10 +950,10 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) // Will deal with the properly later on - for now, lets just get it going... // unsigned int modelNum ; - (void)piBoardRev () ; // Call this first to make sure all's OK. Don't care about the result. + (void)piGpioLayout () ; // Call this first to make sure all's OK. Don't care about the result. if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) - piBoardRevOops ("Unable to open /proc/cpuinfo") ; + piGpioLayoutOops ("Unable to open /proc/cpuinfo") ; while (fgets (line, 120, cpuFd) != NULL) if (strncmp (line, "Revision", 8) == 0) @@ -882,7 +962,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) fclose (cpuFd) ; if (strncmp (line, "Revision", 8) != 0) - piBoardRevOops ("No \"Revision\" line") ; + piGpioLayoutOops ("No \"Revision\" line") ; // Chomp trailing CR/NL @@ -901,7 +981,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) break ; if (*c != ':') - piBoardRevOops ("Bogus \"Revision\" line (no colon)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; // Chomp spaces @@ -910,7 +990,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) ++c ; if (!isxdigit (*c)) - piBoardRevOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; revision = (unsigned int)strtol (c, NULL, 16) ; // Hex number with no leading 0x @@ -919,7 +999,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) if ((revision & (1 << 23)) != 0) // New way { if (wiringPiDebug) - printf ("piBoardId: New Way: revision is: 0x%08X\n", revision) ; + printf ("piBoardId: New Way: revision is: %08X\n", revision) ; bRev = (revision & (0x0F << 0)) >> 0 ; bType = (revision & (0xFF << 4)) >> 4 ; @@ -935,7 +1015,7 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) *warranty = bWarranty ; if (wiringPiDebug) - printf ("piboardId: rev: %d, type: %d, proc: %d, mfg: %d, mem: %d, warranty: %d\n", + printf ("piBoardId: rev: %d, type: %d, proc: %d, mfg: %d, mem: %d, warranty: %d\n", bRev, bType, bProc, bMfg, bMem, bWarranty) ; } else // Old way @@ -944,12 +1024,12 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) printf ("piBoardId: Old Way: revision is: %s\n", c) ; if (!isdigit (*c)) - piBoardRevOops ("Bogus \"Revision\" line (no digit at start of revision)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (no digit at start of revision)") ; // Make sure its long enough if (strlen (c) < 4) - piBoardRevOops ("Bogus \"Revision\" line (not long enough)") ; + piGpioLayoutOops ("Bogus \"Revision\" line (not long enough)") ; // If longer than 4, we'll assume it's been overvolted @@ -963,21 +1043,34 @@ void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) /**/ if (strcmp (c, "0002") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } else if (strcmp (c, "0003") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_UNKNOWN ; } - else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; ; } - else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 0 ; *maker = PI_MAKER_UNKNOWN ; } - else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + + else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + + else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; ; } + else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + + else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + else if (strcmp (c, "0010") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0016") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0019") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + + else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0017") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "001a") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } + + else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } + else if (strcmp (c, "0018") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } + else if (strcmp (c, "001b") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } + else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } } } @@ -1022,9 +1115,6 @@ void setPadDrive (int group, int value) if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - if ((group < 0) || (group > 2)) return ; @@ -1098,9 +1188,6 @@ void pwmSetRange (unsigned int range) { if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; } @@ -1122,9 +1209,6 @@ void pwmSetClock (int divisor) if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - if (wiringPiDebug) printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; @@ -1160,7 +1244,7 @@ void pwmSetClock (int divisor) /* * gpioClockSet: - * Set the freuency on a GPIO clock pin + * Set the frequency on a GPIO clock pin ********************************************************************************* */ @@ -1177,9 +1261,6 @@ void gpioClockSet (int pin, int freq) else if (wiringPiMode != WPI_MODE_GPIO) return ; - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - divi = 19200000 / freq ; divr = 19200000 % freq ; divf = (int)((double)divr * 4096.0 / 19200000.0) ; @@ -1222,13 +1303,15 @@ struct wiringPiNodeStruct *wiringPiFindNode (int pin) ********************************************************************************* */ -static void pinModeDummy (struct wiringPiNodeStruct *node, int pin, int mode) { return ; } -static void pullUpDnControlDummy (struct wiringPiNodeStruct *node, int pin, int pud) { return ; } -static int digitalReadDummy (struct wiringPiNodeStruct *node, int pin) { return LOW ; } -static void digitalWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } -static void pwmWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } -static int analogReadDummy (struct wiringPiNodeStruct *node, int pin) { return 0 ; } -static void analogWriteDummy (struct wiringPiNodeStruct *node, int pin, int value) { return ; } +static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } +static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } +static unsigned int digitalRead8Dummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return 0 ; } +static void digitalWrite8Dummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } +static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } +static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } +static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) { @@ -1250,17 +1333,19 @@ struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) if (node == NULL) (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ; - node->pinBase = pinBase ; - node->pinMax = pinBase + numPins - 1 ; - node->pinMode = pinModeDummy ; - node->pullUpDnControl = pullUpDnControlDummy ; - node->digitalRead = digitalReadDummy ; - node->digitalWrite = digitalWriteDummy ; - node->pwmWrite = pwmWriteDummy ; - node->analogRead = analogReadDummy ; - node->analogWrite = analogWriteDummy ; - node->next = wiringPiNodes ; - wiringPiNodes = node ; + node->pinBase = pinBase ; + node->pinMax = pinBase + numPins - 1 ; + node->pinMode = pinModeDummy ; + node->pullUpDnControl = pullUpDnControlDummy ; + node->digitalRead = digitalReadDummy ; +//node->digitalRead8 = digitalRead8Dummy ; + node->digitalWrite = digitalWriteDummy ; +//node->digitalWrite8 = digitalWrite8Dummy ; + node->pwmWrite = pwmWriteDummy ; + node->analogRead = analogReadDummy ; + node->analogWrite = analogWriteDummy ; + node->next = wiringPiNodes ; + wiringPiNodes = node ; return node ; } @@ -1298,6 +1383,8 @@ void pinModeAlt (int pin, int mode) { int fSel, shift ; + setupCheck ("pinModeAlt") ; + if ((pin & PI_GPIO_MASK) == 0) // On-board pin { /**/ if (wiringPiMode == WPI_MODE_PINS) @@ -1327,6 +1414,8 @@ void pinMode (int pin, int mode) struct wiringPiNodeStruct *node = wiringPiNodes ; int origPin = pin ; + setupCheck ("pinMode") ; + if ((pin & PI_GPIO_MASK) == 0) // On-board pin { /**/ if (wiringPiMode == WPI_MODE_PINS) @@ -1352,20 +1441,16 @@ void pinMode (int pin, int mode) softToneCreate (origPin) ; else if (mode == PWM_TONE_OUTPUT) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - pinMode (origPin, PWM_OUTPUT) ; // Call myself to enable PWM mode pwmSetMode (PWM_MODE_MS) ; } else if (mode == PWM_OUTPUT) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - if ((alt = gpioToPwmALT [pin]) == 0) // Not a hardware capable PWM pin return ; + usingGpioMemCheck ("pinMode PWM") ; + // Set pin to PWM mode *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; @@ -1377,12 +1462,11 @@ void pinMode (int pin, int mode) } else if (mode == GPIO_CLOCK) { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - if ((alt = gpioToGpClkALT0 [pin]) == 0) // Not a GPIO_CLOCK pin return ; + usingGpioMemCheck ("pinMode CLOCK") ; + // Set pin to GPIO_CLOCK mode and set the clock frequency to 100KHz *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; @@ -1401,10 +1485,7 @@ void pinMode (int pin, int mode) /* * pullUpDownCtrl: - * Control the internal pull-up/down resistors on a GPIO pin - * The Arduino only has pull-ups and these are enabled by writing 1 - * to a port when in input mode - this paradigm doesn't quite apply - * here though. + * Control the internal pull-up/down resistors on a GPIO pin. ********************************************************************************* */ @@ -1412,6 +1493,8 @@ void pullUpDnControl (int pin, int pud) { struct wiringPiNodeStruct *node = wiringPiNodes ; + setupCheck ("pullUpDnControl") ; + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { /**/ if (wiringPiMode == WPI_MODE_PINS) @@ -1480,6 +1563,27 @@ int digitalRead (int pin) /* + * digitalRead8: + * Read 8-bits (a byte) from given start pin. + ********************************************************************************* + +unsigned int digitalRead8 (int pin) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + return 0 ; + else + { + if ((node = wiringPiFindNode (pin)) == NULL) + return LOW ; + return node->digitalRead8 (node, pin) ; + } +} + */ + + +/* * digitalWrite: * Set an output bit ********************************************************************************* @@ -1523,6 +1627,26 @@ void digitalWrite (int pin, int value) /* + * digitalWrite8: + * Set an output 8-bit byte on the device from the given pin number + ********************************************************************************* + +void digitalWrite8 (int pin, int value) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + return ; + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->digitalWrite8 (node, pin, value) ; + } +} + */ + + +/* * pwmWrite: * Set an output PWM value ********************************************************************************* @@ -1532,11 +1656,10 @@ void pwmWrite (int pin, int value) { struct wiringPiNodeStruct *node = wiringPiNodes ; + setupCheck ("pwmWrite") ; + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin { - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; - /**/ if (wiringPiMode == WPI_MODE_PINS) pin = pinToGpio [pin] ; else if (wiringPiMode == WPI_MODE_PHYS) @@ -1544,6 +1667,7 @@ void pwmWrite (int pin, int value) else if (wiringPiMode != WPI_MODE_GPIO) return ; + usingGpioMemCheck ("pwmWrite") ; *(pwm + gpioToPwmPort [pin]) = value ; } else @@ -1603,8 +1727,7 @@ void pwmToneWrite (int pin, int freq) { int range ; - if (RASPBERRY_PI_PERI_BASE == 0) // Ignore for now - return ; + setupCheck ("pwmToneWrite") ; if (freq == 0) pwmWrite (pin, 0) ; // Off @@ -1630,7 +1753,7 @@ void pwmToneWrite (int pin, int freq) * Reading is just bit fiddling. * These are wiringPi pin numbers 0..7, or BCM_GPIO pin numbers * 17, 18, 22, 23, 24, 24, 4 on a Pi v1 rev 0-3 - * 17, 18, 27, 23, 24, 24, 4 on a Pi v1 rev 3 onwards or B+, 2, zero + * 17, 18, 27, 23, 24, 24, 4 on a Pi v1 rev 3 onwards or B+, 2, 3, zero ********************************************************************************* */ @@ -1720,8 +1843,8 @@ void digitalWriteByte2 (const int value) } else { - *(gpio + gpioToGPCLR [0]) = 0x0FF00000 ; - *(gpio + gpioToGPSET [0]) = (value & 0xFF) << 20 ; + *(gpio + gpioToGPCLR [0]) = (~value & 0xFF) << 20 ; // 0x0FF00000; ILJ > CHANGE: Old causes glitch + *(gpio + gpioToGPSET [0]) = ( value & 0xFF) << 20 ; } } @@ -1772,18 +1895,20 @@ int waitForInterrupt (int pin, int mS) // Setup poll structure polls.fd = fd ; - polls.events = POLLPRI ; // Urgent data! + polls.events = POLLPRI | POLLERR ; // Wait for it ... x = poll (&polls, 1, mS) ; -// Do a dummy read to clear the interrupt +// If no error, do a dummy read to clear the interrupt // A one character read appars to be enough. -// Followed by a seek to reset it. - (void)read (fd, &c, 1) ; - lseek (fd, 0, SEEK_SET) ; + if (x > 0) + { + lseek (fd, 0, SEEK_SET) ; // Rewind + (void)read (fd, &c, 1) ; // Read & clear + } return x ; } @@ -1797,7 +1922,7 @@ int waitForInterrupt (int pin, int mS) ********************************************************************************* */ -static void *interruptHandler (void *arg) +static void *interruptHandler (UNU void *arg) { int myPin ; @@ -1922,11 +2047,19 @@ int wiringPiISR (int pin, int mode, void (*function)(void)) static void initialiseEpoch (void) { +#ifdef OLD_WAY struct timeval tv ; gettimeofday (&tv, NULL) ; epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; epochMicro = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)(tv.tv_usec) ; +#else + struct timespec ts ; + + clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; + epochMilli = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ; + epochMicro = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec / 1000L) ; +#endif } @@ -2000,17 +2133,27 @@ void delayMicroseconds (unsigned int howLong) /* * millis: * Return a number of milliseconds as an unsigned int. + * Wraps at 49 days. ********************************************************************************* */ unsigned int millis (void) { - struct timeval tv ; uint64_t now ; +#ifdef OLD_WAY + struct timeval tv ; + gettimeofday (&tv, NULL) ; now = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; +#else + struct timespec ts ; + + clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; + now = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ; +#endif + return (uint32_t)(now - epochMilli) ; } @@ -2018,20 +2161,41 @@ unsigned int millis (void) /* * micros: * Return a number of microseconds as an unsigned int. + * Wraps after 71 minutes. ********************************************************************************* */ unsigned int micros (void) { - struct timeval tv ; uint64_t now ; +#ifdef OLD_WAY + struct timeval tv ; gettimeofday (&tv, NULL) ; now = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)tv.tv_usec ; +#else + struct timespec ts ; + + clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; + now = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec / 1000) ; +#endif + return (uint32_t)(now - epochMicro) ; } +/* + * wiringPiVersion: + * Return our current version number + ********************************************************************************* + */ + +void wiringPiVersion (int *major, int *minor) +{ + *major = VERSION_MAJOR ; + *minor = VERSION_MINOR ; +} + /* * wiringPiSetup: @@ -2047,18 +2211,16 @@ unsigned int micros (void) int wiringPiSetup (void) { int fd ; - int boardRev ; int model, rev, mem, maker, overVolted ; - static int alreadyCalled = FALSE ; - -// This is here to trap the unwary - those who's program appears to work then fails some -// time later with a weird error message because you run out of file-handles. - if (alreadyCalled) - (void)wiringPiFailure (WPI_FATAL, "wiringPiSetup*: You must only call this once per program run. This is a fatal error. Please fix your code.\n") ; +// It's actually a fatal error to call any of the wiringPiSetup routines more than once, +// (you run out of file handles!) but I'm fed-up with the useless twats who email +// me bleating that there is a bug in my code, so screw-em. - alreadyCalled = TRUE ; + if (wiringPiSetuped) + return 0 ; + wiringPiSetuped = TRUE ; if (getenv (ENV_DEBUG) != NULL) wiringPiDebug = TRUE ; @@ -2066,101 +2228,106 @@ int wiringPiSetup (void) if (getenv (ENV_CODES) != NULL) wiringPiReturnCodes = TRUE ; - if (getenv (ENV_GPIOMEM) != NULL) - wiringPiTryGpioMem = TRUE ; - if (wiringPiDebug) - { printf ("wiringPi: wiringPiSetup called\n") ; - if (wiringPiTryGpioMem) - printf ("wiringPi: Using /dev/gpiomem\n") ; - } - boardRev = piBoardRev () ; +// Get the board ID information. We're not really using the information here, +// but it will give us information like the GPIO layout scheme (2 variants +// on the older 26-pin Pi's) and the GPIO peripheral base address. +// and if we're running on a compute module, then wiringPi pin numbers +// don't really many anything, so force native BCM mode anyway. + + piBoardId (&model, &rev, &mem, &maker, &overVolted) ; - /**/ if (boardRev == 1) // A, B, Rev 1, 1.1 + if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) + wiringPiMode = WPI_MODE_GPIO ; + else + wiringPiMode = WPI_MODE_PINS ; + + /**/ if (piGpioLayout () == 1) // A, B, Rev 1, 1.1 { pinToGpio = pinToGpioR1 ; physToGpio = physToGpioR1 ; } - else // A, B, Rev 2, B+, CM, Pi2, Zero + else // A2, B2, A+, B+, CM, Pi2, Pi3, Zero { pinToGpio = pinToGpioR2 ; physToGpio = physToGpioR2 ; } -// Note that a Zero is a model 1 - - if (piModel2) - RASPBERRY_PI_PERI_BASE = 0x3F000000 ; - else - RASPBERRY_PI_PERI_BASE = 0x20000000 ; - -// Open the master /dev/ memory control device +// ... -// See if /dev/gpiomem exists and we can open it... - - if (wiringPiTryGpioMem) + switch (model) { - if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/gpiomem: %s\n", strerror (errno)) ; - RASPBERRY_PI_PERI_BASE = 0 ; + case PI_MODEL_A: case PI_MODEL_B: + case PI_MODEL_AP: case PI_MODEL_BP: + case PI_ALPHA: case PI_MODEL_CM: + case PI_MODEL_ZERO: case PI_MODEL_ZERO_W: + piGpioBase = GPIO_PERI_BASE_OLD ; + break ; + + default: + piGpioBase = GPIO_PERI_BASE_NEW ; + break ; } -// ... otherwise fall back to the original /dev/mem which requires root level access +// Open the master /dev/ memory control device +// Device strategy: December 2016: +// Try /dev/mem. If that fails, then +// try /dev/gpiomem. If that fails then game over. - else + if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0) { - -// This check is here because people are too stupid to check for themselves or read -// error messages. - - if (geteuid () != 0) - (void)wiringPiFailure (WPI_FATAL, "wiringPiSetup: Must be root. (Did you forget sudo?)\n") ; - - if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem: %s\n", strerror (errno)) ; + if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) >= 0) // We're using gpiomem + { + piGpioBase = 0 ; + usingGpioMem = TRUE ; + } + else + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem or /dev/gpiomem: %s.\n" + " Aborting your program because if it can not access the GPIO\n" + " hardware then it most certianly won't work\n" + " Try running with sudo?\n", strerror (errno)) ; } // Set the offsets into the memory interface. - GPIO_PADS = RASPBERRY_PI_PERI_BASE + 0x00100000 ; - GPIO_CLOCK_BASE = RASPBERRY_PI_PERI_BASE + 0x00101000 ; - GPIO_BASE = RASPBERRY_PI_PERI_BASE + 0x00200000 ; - GPIO_TIMER = RASPBERRY_PI_PERI_BASE + 0x0000B000 ; - GPIO_PWM = RASPBERRY_PI_PERI_BASE + 0x0020C000 ; + GPIO_PADS = piGpioBase + 0x00100000 ; + GPIO_CLOCK_BASE = piGpioBase + 0x00101000 ; + GPIO_BASE = piGpioBase + 0x00200000 ; + GPIO_TIMER = piGpioBase + 0x0000B000 ; + GPIO_PWM = piGpioBase + 0x0020C000 ; // Map the individual hardware components // GPIO: gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ; - if ((int32_t)gpio == -1) + if (gpio == MAP_FAILED) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (GPIO) failed: %s\n", strerror (errno)) ; // PWM pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ; - if ((int32_t)pwm == -1) + if (pwm == MAP_FAILED) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror (errno)) ; // Clock control (needed for PWM) clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE) ; - if ((int32_t)clk == -1) + if (clk == MAP_FAILED) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (CLOCK) failed: %s\n", strerror (errno)) ; // The drive pads pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ; - if ((int32_t)pads == -1) + if (pads == MAP_FAILED) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PADS) failed: %s\n", strerror (errno)) ; -#ifdef USE_TIMER // The system timer timer = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_TIMER) ; - if ((int32_t)timer == -1) + if (timer == MAP_FAILED) return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (TIMER) failed: %s\n", strerror (errno)) ; // Set the timer to free-running, 1MHz. @@ -2170,17 +2337,16 @@ int wiringPiSetup (void) *(timer + TIMER_CONTROL) = 0x0000280 ; *(timer + TIMER_PRE_DIV) = 0x00000F9 ; timerIrqRaw = timer + TIMER_IRQ_RAW ; -#endif - initialiseEpoch () ; +// Export the base addresses for any external software that might need them -// If we're running on a compute module, then wiringPi pin numbers don't really many anything... + _wiringPiGpio = gpio ; + _wiringPiPwm = pwm ; + _wiringPiClk = clk ; + _wiringPiPads = pads ; + _wiringPiTimer = timer ; - piBoardId (&model, &rev, &mem, &maker, &overVolted) ; - if (model == PI_MODEL_CM) - wiringPiMode = WPI_MODE_GPIO ; - else - wiringPiMode = WPI_MODE_PINS ; + initialiseEpoch () ; return 0 ; } @@ -2241,18 +2407,13 @@ int wiringPiSetupPhys (void) int wiringPiSetupSys (void) { - int boardRev ; int pin ; char fName [128] ; - static int alreadyCalled = FALSE ; - -// This is here to trap the unwary - those who's program appears to work then fails some -// time later with a weird error message because you run out of file-handles. - if (alreadyCalled) - (void)wiringPiFailure (WPI_FATAL, "wiringPiSetupSys: You must only call this once per program run. This is a fatal error. Please fix your code.\n") ; + if (wiringPiSetuped) + return 0 ; - alreadyCalled = TRUE ; + wiringPiSetuped = TRUE ; if (getenv (ENV_DEBUG) != NULL) wiringPiDebug = TRUE ; @@ -2263,9 +2424,7 @@ int wiringPiSetupSys (void) if (wiringPiDebug) printf ("wiringPi: wiringPiSetupSys called\n") ; - boardRev = piBoardRev () ; - - if (boardRev == 1) + if (piGpioLayout () == 1) { pinToGpio = pinToGpioR1 ; physToGpio = physToGpioR1 ; diff --git a/wiringPi/wiringPi.h b/wiringPi/wiringPi.h index e11a0be..ae5d647 100644 --- a/wiringPi/wiringPi.h +++ b/wiringPi/wiringPi.h @@ -1,7 +1,7 @@ /* * wiringPi.h: * Arduino like Wiring library for the Raspberry Pi. - * Copyright (c) 2012-2016 Gordon Henderson + * Copyright (c) 2012-2017 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -26,12 +26,22 @@ // C doesn't have true/false by default and I can never remember which // way round they are, so ... +// (and yes, I know about stdbool.h but I like capitals for these and I'm old) #ifndef TRUE # define TRUE (1==1) # define FALSE (!TRUE) #endif +// GCC warning suppressor + +#define UNU __attribute__((unused)) + +// Mask for the bottom 64 pins which belong to the Raspberry Pi +// The others are available for the other devices + +#define PI_GPIO_MASK (0xFFFFFFC0) + // Handy defines // wiringPi modes @@ -77,16 +87,19 @@ // Pi model types and version numbers // Intended for the GPIO program Use at your own risk. -#define PI_MODEL_A 0 -#define PI_MODEL_B 1 -#define PI_MODEL_AP 2 -#define PI_MODEL_BP 3 -#define PI_MODEL_2 4 -#define PI_ALPHA 5 -#define PI_MODEL_CM 6 -#define PI_MODEL_07 7 -#define PI_MODEL_3 8 -#define PI_MODEL_ZERO 9 +#define PI_MODEL_A 0 +#define PI_MODEL_B 1 +#define PI_MODEL_AP 2 +#define PI_MODEL_BP 3 +#define PI_MODEL_2 4 +#define PI_ALPHA 5 +#define PI_MODEL_CM 6 +#define PI_MODEL_07 7 +#define PI_MODEL_3 8 +#define PI_MODEL_ZERO 9 +#define PI_MODEL_CM3 10 +#define PI_MODEL_ZERO_W 12 +#define PI_MODEL_3P 13 #define PI_VERSION_1 0 #define PI_VERSION_1_1 1 @@ -95,7 +108,7 @@ #define PI_MAKER_SONY 0 #define PI_MAKER_EGOMAN 1 -#define PI_MAKER_MBEST 2 +#define PI_MAKER_EMBEST 2 #define PI_MAKER_UNKNOWN 3 extern const char *piModelNames [16] ; @@ -108,7 +121,7 @@ extern const int piMemorySize [ 8] ; // Threads -#define PI_THREAD(X) void *X (void *dummy) +#define PI_THREAD(X) void *X (UNU void *dummy) // Failure modes @@ -135,19 +148,30 @@ struct wiringPiNodeStruct unsigned int data2 ; // ditto unsigned int data3 ; // ditto - void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; - void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; - int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; - void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; - void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; - int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; - void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; + void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; + void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; + int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; +//unsigned int (*digitalRead8) (struct wiringPiNodeStruct *node, int pin) ; + void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; +// void (*digitalWrite8) (struct wiringPiNodeStruct *node, int pin, int value) ; + void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; + int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; + void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; struct wiringPiNodeStruct *next ; } ; extern struct wiringPiNodeStruct *wiringPiNodes ; +// Export variables for the hardware pointers + +extern volatile unsigned int *_wiringPiGpio ; +extern volatile unsigned int *_wiringPiPwm ; +extern volatile unsigned int *_wiringPiClk ; +extern volatile unsigned int *_wiringPiPads ; +extern volatile unsigned int *_wiringPiTimer ; +extern volatile unsigned int *_wiringPiTimerIrqRaw ; + // Function prototypes // c++ wrappers thanks to a comment by Nick Lott @@ -168,19 +192,22 @@ extern int wiringPiFailure (int fatal, const char *message, ...) ; extern struct wiringPiNodeStruct *wiringPiFindNode (int pin) ; extern struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) ; +extern void wiringPiVersion (int *major, int *minor) ; extern int wiringPiSetup (void) ; extern int wiringPiSetupSys (void) ; extern int wiringPiSetupGpio (void) ; extern int wiringPiSetupPhys (void) ; -extern void pinModeAlt (int pin, int mode) ; -extern void pinMode (int pin, int mode) ; -extern void pullUpDnControl (int pin, int pud) ; -extern int digitalRead (int pin) ; -extern void digitalWrite (int pin, int value) ; -extern void pwmWrite (int pin, int value) ; -extern int analogRead (int pin) ; -extern void analogWrite (int pin, int value) ; +extern void pinModeAlt (int pin, int mode) ; +extern void pinMode (int pin, int mode) ; +extern void pullUpDnControl (int pin, int pud) ; +extern int digitalRead (int pin) ; +extern void digitalWrite (int pin, int value) ; +extern unsigned int digitalRead8 (int pin) ; +extern void digitalWrite8 (int pin, int value) ; +extern void pwmWrite (int pin, int value) ; +extern int analogRead (int pin) ; +extern void analogWrite (int pin, int value) ; // PiFace specifics // (Deprecated) @@ -190,19 +217,22 @@ extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio // On-Board Raspberry Pi hardware specific stuff -extern int piBoardRev (void) ; +extern int piGpioLayout (void) ; +extern int piBoardRev (void) ; // Deprecated extern void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) ; extern int wpiPinToGpio (int wpiPin) ; extern int physPinToGpio (int physPin) ; extern void setPadDrive (int group, int value) ; extern int getAlt (int pin) ; extern void pwmToneWrite (int pin, int freq) ; -extern void digitalWriteByte (int value) ; -extern unsigned int digitalReadByte (void) ; extern void pwmSetMode (int mode) ; extern void pwmSetRange (unsigned int range) ; extern void pwmSetClock (int divisor) ; extern void gpioClockSet (int pin, int freq) ; +extern unsigned int digitalReadByte (void) ; +extern unsigned int digitalReadByte2 (void) ; +extern void digitalWriteByte (int value) ; +extern void digitalWriteByte2 (int value) ; // Interrupts // (Also Pi hardware specific) diff --git a/wiringPi/wiringPiI2C.c b/wiringPi/wiringPiI2C.c index c787bce..b0ee5d3 100644 --- a/wiringPi/wiringPiI2C.c +++ b/wiringPi/wiringPiI2C.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "wiringPi.h" #include "wiringPiI2C.h" @@ -221,7 +222,7 @@ int wiringPiI2CSetup (const int devId) int rev ; const char *device ; - rev = piBoardRev () ; + rev = piGpioLayout () ; if (rev == 1) device = "/dev/i2c-0" ; diff --git a/wiringPi/wiringPiSPI.c b/wiringPi/wiringPiSPI.c index 453df31..022b99f 100644 --- a/wiringPi/wiringPiSPI.c +++ b/wiringPi/wiringPiSPI.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "wiringPi.h" @@ -38,10 +39,10 @@ // The SPI bus parameters // Variables as they need to be passed as pointers later on -const static char *spiDev0 = "/dev/spidev0.0" ; -const static char *spiDev1 = "/dev/spidev0.1" ; -const static uint8_t spiBPW = 8 ; -const static uint16_t spiDelay = 0 ; +static const char *spiDev0 = "/dev/spidev0.0" ; +static const char *spiDev1 = "/dev/spidev0.1" ; +static const uint8_t spiBPW = 8 ; +static const uint16_t spiDelay = 0 ; static uint32_t spiSpeeds [2] ; static int spiFds [2] ; diff --git a/wiringPi/wiringSerial.c b/wiringPi/wiringSerial.c index ca976a9..e1587ad 100644 --- a/wiringPi/wiringSerial.c +++ b/wiringPi/wiringSerial.c @@ -49,24 +49,36 @@ int serialOpen (const char *device, const int baud) switch (baud) { - case 50: myBaud = B50 ; break ; - case 75: myBaud = B75 ; break ; - case 110: myBaud = B110 ; break ; - case 134: myBaud = B134 ; break ; - case 150: myBaud = B150 ; break ; - case 200: myBaud = B200 ; break ; - case 300: myBaud = B300 ; break ; - case 600: myBaud = B600 ; break ; - case 1200: myBaud = B1200 ; break ; - case 1800: myBaud = B1800 ; break ; - case 2400: myBaud = B2400 ; break ; - case 4800: myBaud = B4800 ; break ; - case 9600: myBaud = B9600 ; break ; - case 19200: myBaud = B19200 ; break ; - case 38400: myBaud = B38400 ; break ; - case 57600: myBaud = B57600 ; break ; - case 115200: myBaud = B115200 ; break ; - case 230400: myBaud = B230400 ; break ; + case 50: myBaud = B50 ; break ; + case 75: myBaud = B75 ; break ; + case 110: myBaud = B110 ; break ; + case 134: myBaud = B134 ; break ; + case 150: myBaud = B150 ; break ; + case 200: myBaud = B200 ; break ; + case 300: myBaud = B300 ; break ; + case 600: myBaud = B600 ; break ; + case 1200: myBaud = B1200 ; break ; + case 1800: myBaud = B1800 ; break ; + case 2400: myBaud = B2400 ; break ; + case 4800: myBaud = B4800 ; break ; + case 9600: myBaud = B9600 ; break ; + case 19200: myBaud = B19200 ; break ; + case 38400: myBaud = B38400 ; break ; + case 57600: myBaud = B57600 ; break ; + case 115200: myBaud = B115200 ; break ; + case 230400: myBaud = B230400 ; break ; + case 460800: myBaud = B460800 ; break ; + case 500000: myBaud = B500000 ; break ; + case 576000: myBaud = B576000 ; break ; + case 921600: myBaud = B921600 ; break ; + case 1000000: myBaud = B1000000 ; break ; + case 1152000: myBaud = B1152000 ; break ; + case 1500000: myBaud = B1500000 ; break ; + case 2000000: myBaud = B2000000 ; break ; + case 2500000: myBaud = B2500000 ; break ; + case 3000000: myBaud = B3000000 ; break ; + case 3500000: myBaud = B3500000 ; break ; + case 4000000: myBaud = B4000000 ; break ; default: return -2 ; @@ -96,7 +108,7 @@ int serialOpen (const char *device, const int baud) options.c_cc [VMIN] = 0 ; options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) - tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ; + tcsetattr (fd, TCSANOW, &options) ; ioctl (fd, TIOCMGET, &status); diff --git a/wiringPi/wpiExtensions.c b/wiringPi/wpiExtensions.c index 62a92d7..bef126f 100644 --- a/wiringPi/wpiExtensions.c +++ b/wiringPi/wpiExtensions.c @@ -55,6 +55,13 @@ #include "ads1115.h" #include "sn3218.h" #include "drcSerial.h" +#include "drcNet.h" +#include "../wiringPiD/drcNetCmd.h" +#include "pseudoPins.h" +#include "bmp180.h" +#include "htu21d.h" +#include "ds18b20.h" +#include "rht03.h" #include "wpiExtensions.h" @@ -130,12 +137,16 @@ static char *extractInt (char *progName, char *p, int *num) /* * extractStr: * Check & return a string at the given location (prefixed by a :) + * Note: The string can be enclosed in []'s to escape colons. This is + * so we can handle IPv6 addresses which contain colons and the []'s is + * a common way to prepresent them. ********************************************************************************* */ static char *extractStr (char *progName, char *p, char **str) { char *q, *r ; + int quoted = FALSE ; if (*p != ':') { @@ -145,21 +156,38 @@ static char *extractStr (char *progName, char *p, char **str) ++p ; - if (!isprint (*p)) + if (*p == '[') + { + quoted = TRUE ; + ++p ; + } + + if (!isprint (*p)) // Is this needed? { verbError ("%s: character expected", progName) ; return NULL ; } q = p ; - while ((*q != 0) && (*q != ':')) - ++q ; + if (quoted) + { + while ((*q != 0) && (*q != ']')) + ++q ; + } + else + { + while ((*q != 0) && (*q != ':')) + ++q ; + } *str = r = calloc (q - p + 2, 1) ; // Zeros it while (p != q) *r++ = *p++ ; - + + if (quoted) // Skip over the ] to the : + ++p ; + return p ; } @@ -429,6 +457,87 @@ static int doExtensionPcf8591 (char *progName, int pinBase, char *params) /* + * doExtensionPseudoPins: + * 64 Memory resident pseudo pins + * pseudoPins:base + ********************************************************************************* + */ + +static int doExtensionPseudoPins (UNU char *progName, int pinBase, UNU char *params) +{ + pseudoPinsSetup (pinBase) ; + + return TRUE ; +} + + +/* + * doExtensionBmp180: + * Analog Temp + Pressure + * bmp180:base + ********************************************************************************* + */ + +static int doExtensionBmp180 (UNU char *progName, int pinBase, UNU char *params) +{ + bmp180Setup (pinBase) ; + + return TRUE ; +} + + +/* + * doExtensionHtu21d: + * Analog humidity + Pressure + * htu21d:base + ********************************************************************************* + */ + +static int doExtensionHtu21d (UNU char *progName, int pinBase, UNU char *params) +{ + htu21dSetup (pinBase) ; + + return TRUE ; +} + + +/* + * doExtensionDs18b20: + * 1-Wire Temperature + * htu21d:base:serialNum + ********************************************************************************* + */ + +static int doExtensionDs18b20 (char *progName, int pinBase, char *params) +{ + char *serialNum ; + + if ((params = extractStr (progName, params, &serialNum)) == NULL) + return FALSE ; + + return ds18b20Setup (pinBase, serialNum) ; +} + + +/* + * doExtensionRht03: + * Maxdetect 1-Wire Temperature & Humidity + * rht03:base:piPin + ********************************************************************************* + */ + +static int doExtensionRht03 (char *progName, int pinBase, char *params) +{ + int piPin ; + + if ((params = extractInt (progName, params, &piPin)) == NULL) + return FALSE ; + + return rht03Setup (pinBase, piPin) ; +} + + +/* * doExtensionMax31855: * Analog IO * max31855:base:spiChan @@ -565,7 +674,7 @@ static int doExtensionMcp4802 (char *progName, int pinBase, char *params) ********************************************************************************* */ -static int doExtensionSn3218 (char *progName, int pinBase, char *params) +static int doExtensionSn3218 (UNU char *progName, int pinBase, UNU char *params) { sn3218Setup (pinBase) ; return TRUE ; @@ -631,9 +740,9 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params) if ((params = extractInt (progName, params, &pins)) == NULL) return FALSE ; - if ((pins < 1) || (pins > 100)) + if ((pins < 1) || (pins > 1000)) { - verbError ("%s: pins (%d) out of range (2-100)", progName, pins) ; + verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; return FALSE ; } @@ -661,6 +770,59 @@ static int doExtensionDrcS (char *progName, int pinBase, char *params) } +/* + * doExtensionDrcNet: + * Interface to a DRC Network system + * drcn:base:pins:ipAddress:port:password + ********************************************************************************* + */ + +static int doExtensionDrcNet (char *progName, int pinBase, char *params) +{ + int pins ; + char *ipAddress, *port, *password ; + char pPort [1024] ; + + if ((params = extractInt (progName, params, &pins)) == NULL) + return FALSE ; + + if ((pins < 1) || (pins > 1000)) + { + verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; + return FALSE ; + } + + if ((params = extractStr (progName, params, &ipAddress)) == NULL) + return FALSE ; + + if (strlen (ipAddress) == 0) + { + verbError ("%s: ipAddress required", progName) ; + return FALSE ; + } + + if ((params = extractStr (progName, params, &port)) == NULL) + return FALSE ; + + if (strlen (port) == 0) + { + sprintf (pPort, "%d", DEFAULT_SERVER_PORT) ; + port = pPort ; + } + + if ((params = extractStr (progName, params, &password)) == NULL) + return FALSE ; + + if (strlen (password) == 0) + { + verbError ("%s: password required", progName) ; + return FALSE ; + } + + return drcSetupNet (pinBase, pins, ipAddress, port, password) ; +} + + /* * Function list @@ -677,6 +839,11 @@ static struct extensionFunctionStruct extensionFunctions [] = { "sr595", &doExtensionSr595 }, { "pcf8574", &doExtensionPcf8574 }, { "pcf8591", &doExtensionPcf8591 }, + { "bmp180", &doExtensionBmp180 }, + { "pseudoPins", &doExtensionPseudoPins }, + { "htu21d", &doExtensionHtu21d }, + { "ds18b20", &doExtensionDs18b20 }, + { "rht03", &doExtensionRht03 }, { "mcp3002", &doExtensionMcp3002 }, { "mcp3004", &doExtensionMcp3004 }, { "mcp4802", &doExtensionMcp4802 }, @@ -686,6 +853,7 @@ static struct extensionFunctionStruct extensionFunctions [] = { "max5322", &doExtensionMax5322 }, { "sn3218", &doExtensionSn3218 }, { "drcs", &doExtensionDrcS }, + { "drcn", &doExtensionDrcNet }, { NULL, NULL }, } ; @@ -703,7 +871,7 @@ int loadWPiExtension (char *progName, char *extensionData, int printErrors) char *p ; char *extension = extensionData ; struct extensionFunctionStruct *extensionFn ; - unsigned pinBase = 0 ; + int pinBase = 0 ; verbose = printErrors ; @@ -755,6 +923,6 @@ int loadWPiExtension (char *progName, char *extensionData, int printErrors) return extensionFn->function (progName, pinBase, p) ; } - verbError ("%s: extension %s not found", progName, extension) ; + fprintf (stderr, "%s: extension %s not found", progName, extension) ; return FALSE ; } diff --git a/wiringPiD/Makefile b/wiringPiD/Makefile new file mode 100644 index 0000000..6b2cc9e --- /dev/null +++ b/wiringPiD/Makefile @@ -0,0 +1,100 @@ +# +# Makefile: +# The wiringPiD utility: +# https://projects.drogon.net/wiring-pi +# +# Copyright (c) 2012-2017 Gordon Henderson +################################################################################# +# This file is part of wiringPi: +# A "wiring" library for the Raspberry Pi +# +# wiringPi is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# wiringPi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with wiringPi. If not, see . +################################################################################# + +DESTDIR?=/usr +PREFIX?=/local + +ifneq ($V,1) +Q ?= @ +endif + +#DEBUG = -g -O0 +DEBUG = -O2 +CC = gcc +INCLUDE = -I$(DESTDIR)$(PREFIX)/include +CFLAGS = $(DEBUG) -Wall -Wextra $(INCLUDE) -Winline -pipe + +LDFLAGS = -L$(DESTDIR)$(PREFIX)/lib +LIBS = -lwiringPi -lwiringPiDev -lpthread -lrt -lm -lcrypt + +# May not need to alter anything below this line +############################################################################### + +SRC = wiringpid.c network.c runRemote.c daemonise.c + +OBJ = $(SRC:.c=.o) + +all: wiringpid + +wiringpid: $(OBJ) + $Q echo [Link] + $Q $(CC) -o $@ $(OBJ) $(LDFLAGS) $(LIBS) + +.c.o: + $Q echo [Compile] $< + $Q $(CC) -c $(CFLAGS) $< -o $@ + +.PHONY: clean +clean: + $Q echo "[Clean]" + $Q rm -f $(OBJ) wiringpid *~ core tags *.bak + +.PHONY: tags +tags: $(SRC) + $Q echo [ctags] + $Q ctags $(SRC) + +.PHONY: install +install: wiringpid + $Q echo "[Install]" + $Q mkdir -p $(DESTDIR)$(PREFIX)/sbin + $Q cp wiringpid $(DESTDIR)$(PREFIX)/sbin + $Q chown root.root $(DESTDIR)$(PREFIX)/sbin/wiringpid + +# $Q mkdir -p $(DESTDIR)$(PREFIX)/man/man8 +# $Q cp gpio.1 $(DESTDIR)$(PREFIX)/man/man8 + +.PHONY: install-deb +install-deb: gpio + $Q echo "[Install: deb]" + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/bin + $Q install -m 0755 gpio ~/wiringPi/debian-template/wiringPi/usr/bin + $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/man/man1 + $Q install -m 0644 gpio.1 ~/wiringPi/debian-template/wiringPi/man/man1 + +.PHONY: uninstall +uninstall: + $Q echo "[UnInstall]" + $Q rm -f $(DESTDIR)$(PREFIX)/sbin/wiringpid + $Q rm -f $(DESTDIR)$(PREFIX)/man/man8/wiringpid.8 + +.PHONY: depend +depend: + makedepend -Y $(SRC) +# DO NOT DELETE + +wiringpid.o: drcNetCmd.h network.h runRemote.h daemonise.h +network.o: network.h +runRemote.o: drcNetCmd.h network.h runRemote.h +daemonise.o: daemonise.h diff --git a/wiringPiD/daemonise.c b/wiringPiD/daemonise.c new file mode 100644 index 0000000..134a6bb --- /dev/null +++ b/wiringPiD/daemonise.c @@ -0,0 +1,82 @@ +/* + * daemonise.c: + * Fairly generic "Turn the current process into a daemon" code. + * + * Copyright (c) 2016-2017 Gordon Henderson. + ********************************************************************************* + */ + +#include +#include +#include +#include +#include +#include + +#include "daemonise.h" + +void daemonise (const char *pidFile) +{ + pid_t pid ; + int i ; + FILE *fd ; + + syslog (LOG_DAEMON | LOG_INFO, "Becoming daemon") ; + +// Fork from the parent + + if ((pid = fork ()) < 0) + { + syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 1 failed: %m") ; + exit (EXIT_FAILURE) ; + } + + if (pid > 0) // Parent - terminate + exit (EXIT_SUCCESS) ; + +// Now running on the child - become session leader + + if (setsid() < 0) + { + syslog (LOG_DAEMON | LOG_ALERT, "setsid failed: %m") ; + exit (EXIT_FAILURE) ; + } + +// Ignore a few signals + + signal (SIGCHLD, SIG_IGN) ; + signal (SIGHUP, SIG_IGN) ; + +// Fork again + + if ((pid = fork ()) < 0) + { + syslog (LOG_DAEMON | LOG_ALERT, "Fork no. 2 failed: %m") ; + exit (EXIT_FAILURE) ; + } + + if (pid > 0) // parent - terminate + exit (EXIT_SUCCESS) ; + +// Tidying up - reset umask, change to / and close all files + + umask (0) ; + chdir ("/") ; + + for (i = 0 ; i < sysconf (_SC_OPEN_MAX) ; ++i) + close (i) ; + +// Write PID into /var/run + + if (pidFile != NULL) + { + if ((fd = fopen (pidFile, "w")) == NULL) + { + syslog (LOG_DAEMON | LOG_ALERT, "Unable to write PID file: %m") ; + exit (EXIT_FAILURE) ; + } + + fprintf (fd, "%d\n", getpid ()) ; + fclose (fd) ; + } +} diff --git a/wiringPiD/daemonise.h b/wiringPiD/daemonise.h new file mode 100644 index 0000000..8d13319 --- /dev/null +++ b/wiringPiD/daemonise.h @@ -0,0 +1,9 @@ +/* + * daemonise.h: + * Fairly generic "Turn the current process into a daemon" code. + * + * Copyright (c) 2016-2017 Gordon Henderson. + ********************************************************************************* + */ + +extern void daemonise (const char *pidFile) ; diff --git a/wiringPiD/drcNetCmd.h b/wiringPiD/drcNetCmd.h new file mode 100644 index 0000000..23f7dc1 --- /dev/null +++ b/wiringPiD/drcNetCmd.h @@ -0,0 +1,44 @@ +/* + * drcNetCmd.c: + * Copyright (c) 2012-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#define DEFAULT_SERVER_PORT 6124 + +#define DRCN_PIN_MODE 1 +#define DRCN_PULL_UP_DN 2 + +#define DRCN_DIGITAL_WRITE 3 +#define DRCN_DIGITAL_WRITE8 4 +#define DRCN_ANALOG_WRITE 5 +#define DRCN_PWM_WRITE 6 + +#define DRCN_DIGITAL_READ 7 +#define DRCN_DIGITAL_READ8 8 +#define DRCN_ANALOG_READ 9 + + +struct drcNetComStruct +{ + uint32_t pin ; + uint32_t cmd ; + uint32_t data ; +} comDat ; + diff --git a/wiringPiD/network.c b/wiringPiD/network.c new file mode 100644 index 0000000..9f6bb88 --- /dev/null +++ b/wiringPiD/network.c @@ -0,0 +1,330 @@ +/* + * network.c: + * Part of wiringPiD + * Copyright (c) 2012-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "network.h" + +#define TRUE (1==1) +#define FALSE (!TRUE) + +// Local data + +#define SALT_LEN 16 + +static char salt [SALT_LEN + 1] ; +static char *returnedHash = NULL ; +static int serverFd = -1 ; + +// Union for the server Socket Address + +static union +{ + struct sockaddr_in sin ; + struct sockaddr_in6 sin6 ; +} serverSockAddr ; + +// and client address + +static union +{ + struct sockaddr_in sin ; + struct sockaddr_in6 sin6 ; +} clientSockAddr ; + + +/* + * getClientIP: + * Returns a pointer to a static string containing the clients IP address + ********************************************************************************* + */ + +char *getClientIP (void) +{ + char buf [INET6_ADDRSTRLEN] ; + static char ipAddress [1024] ; + + if (clientSockAddr.sin.sin_family == AF_INET) // IPv4 + { + if (snprintf (ipAddress, 1024, "IPv4: %s", + inet_ntop (clientSockAddr.sin.sin_family, (void *)&clientSockAddr.sin.sin_addr, buf, sizeof (buf))) == 1024) + strcpy (ipAddress, "Too long") ; + } + else // IPv6 + { + if (clientSockAddr.sin.sin_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&clientSockAddr.sin6.sin6_addr)) + { + if (snprintf (ipAddress, 1024, "IPv4in6: %s", + inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024) + strcpy (ipAddress, "Too long") ; + } + else + { + if (snprintf (ipAddress, 1024, "IPv6: %s", + inet_ntop (clientSockAddr.sin.sin_family, (char *)&clientSockAddr.sin6.sin6_addr, buf, sizeof(buf))) == 1024) + strcpy (ipAddress, "Too long") ; + } + } + + return ipAddress ; +} + + + +/* + * clientPstr: clientPrintf: + * Print over a network socket + ********************************************************************************* + */ + +static int clientPstr (int fd, char *s) +{ + int len = strlen (s) ; + return (write (fd, s, len) == len) ? 0 : -1 ; +} + +static int clientPrintf (const int fd, const char *message, ...) +{ + va_list argp ; + char buffer [1024] ; + + va_start (argp, message) ; + vsnprintf (buffer, 1023, message, argp) ; + va_end (argp) ; + + return clientPstr (fd, buffer) ; +} + + +/* + * sendGreeting: + * Send some text to the client device + ********************************************************************************* + */ + +int sendGreeting (int clientFd) +{ + if (clientPrintf (clientFd, "200 Welcome to wiringPiD - http://wiringpi.com/\n") < 0) + return -1 ; + + return clientPrintf (clientFd, "200 Connecting from: %s\n", getClientIP ()) ; +} + + +/* + * getSalt: + * Create a random 'salt' value for the password encryption process + ********************************************************************************* + */ + +static int getSalt (char drySalt []) +{ + static const char *seaDog = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789/." ; + + unsigned char wetSalt [SALT_LEN] ; + int i, fd ; + + if ((fd = open ("/dev/urandom", O_RDONLY)) < 0) + return fd ; + + if (read (fd, wetSalt, SALT_LEN) != SALT_LEN) + return -1 ; + + close (fd) ; + + for (i = 0 ; i < SALT_LEN ; ++i) + drySalt [i] = seaDog [wetSalt [i] & 63] ; + + drySalt [SALT_LEN] = 0 ; + + return 0 ; +} + + +/* + * sendChallenge: + * Create and send our salt (aka nonce) to the remote device + ********************************************************************************* + */ + +int sendChallenge (int clientFd) +{ + if (getSalt (salt) < 0) + return -1 ; + + return clientPrintf (clientFd, "Challenge %s\n", salt) ; +} + + +/* + * getResponse: + * Read the encrypted password from the remote device. + ********************************************************************************* + */ + + +int getResponse (int clientFd) +{ + char reply [1024] ; + int len ; + +// Being sort of lazy about this. I'm expecting an SHA-512 hash back and these +// are exactly 86 characters long, so no reason not to, I guess... + + len = 86 ; + + if (setsockopt (clientFd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) + return -1 ; + + len = recv (clientFd, reply, 86, 0) ; + if (len != 86) + return -1 ; + + reply [len] = 0 ; + + if ((returnedHash = malloc (len + 1)) == NULL) + return -1 ; + + strcpy (returnedHash, reply) ; + + return 0 ; +} + + +/* + * passwordMatch: + * See if there's a match. If not, we simply dump them. + ********************************************************************************* + */ + +int passwordMatch (const char *password) +{ + char *encrypted ; + char salted [1024] ; + + sprintf (salted, "$6$%s$", salt) ; + + encrypted = crypt (password, salted) ; + +// 20: $6$ then 16 characters of salt, then $ +// 86 is the length of an SHA-512 hash + + return strncmp (encrypted + 20, returnedHash, 86) == 0 ; +} + + +/* + * setupServer: + * Do what's needed to create a local server socket instance that can listen + * on both IPv4 and IPv6 interfaces. + ********************************************************************************* + */ + +int setupServer (int serverPort) +{ + socklen_t clientSockAddrSize = sizeof (clientSockAddr) ; + + int on = 1 ; + int family ; + socklen_t serverSockAddrSize ; + int clientFd ; + +// Try to create an IPv6 socket + + serverFd = socket (PF_INET6, SOCK_STREAM, 0) ; + +// If it didn't work, then fall-back to IPv4. + + if (serverFd < 0) + { + if ((serverFd = socket (PF_INET, SOCK_STREAM, 0)) < 0) + return -1 ; + + family = AF_INET ; + serverSockAddrSize = sizeof (struct sockaddr_in) ; + } + else // We got an IPv6 socket + { + family = AF_INET6 ; + serverSockAddrSize = sizeof (struct sockaddr_in6) ; + } + + if (setsockopt (serverFd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) + return -1 ; + +// Setup the servers socket address - cope with IPv4 and v6. + + memset (&serverSockAddr, 0, sizeof (serverSockAddr)) ; + switch (family) + { + case AF_INET: + serverSockAddr.sin.sin_family = AF_INET ; + serverSockAddr.sin.sin_addr.s_addr = htonl (INADDR_ANY) ; + serverSockAddr.sin.sin_port = htons (serverPort) ; + break; + + case AF_INET6: + serverSockAddr.sin6.sin6_family = AF_INET6 ; + serverSockAddr.sin6.sin6_addr = in6addr_any ; + serverSockAddr.sin6.sin6_port = htons (serverPort) ; + } + +// Bind, listen and accept + + if (bind (serverFd, (struct sockaddr *)&serverSockAddr, serverSockAddrSize) < 0) + return -1 ; + + if (listen (serverFd, 4) < 0) // Really only going to talk to one client at a time... + return -1 ; + + if ((clientFd = accept (serverFd, (struct sockaddr *)&clientSockAddr, &clientSockAddrSize)) < 0) + return -1 ; + + return clientFd ; +} + + +/* + * closeServer: + ********************************************************************************* + */ + +void closeServer (int clientFd) +{ + if (serverFd != -1) close (serverFd) ; + if (clientFd != -1) close (clientFd) ; + serverFd = clientFd = -1 ; +} diff --git a/wiringPiD/network.h b/wiringPiD/network.h new file mode 100644 index 0000000..94c3380 --- /dev/null +++ b/wiringPiD/network.h @@ -0,0 +1,31 @@ +/* + * network.h: + * Part of wiringPiD + * Copyright (c) 2012-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +extern char *getClientIP (void) ; +extern int getResponce (int clientFd) ; +extern int setupServer (int serverPort) ; +extern int sendGreeting (int clientFd) ; +extern int sendChallenge (int clientFd) ; +extern int getResponse (int clientFd) ; +extern int passwordMatch (const char *password) ; +extern void closeServer (int clientFd) ; diff --git a/wiringPiD/runRemote.c b/wiringPiD/runRemote.c new file mode 100644 index 0000000..cd7432b --- /dev/null +++ b/wiringPiD/runRemote.c @@ -0,0 +1,126 @@ +/* + * runRemote.c: + * Run the remote commands passed over the network link. + * + * Copyright (c) 2012-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +//#include + +#include +#include + +#include "drcNetCmd.h" +#include "network.h" +#include "runRemote.h" + + + +int noLocalPins = FALSE ; + + +void runRemoteCommands (int fd) +{ + register uint32_t pin ; + int len ; + struct drcNetComStruct cmd ; + + len = sizeof (struct drcNetComStruct) ; + + if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) + return ; + + for (;;) + { + if (recv (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) // Probably remote hangup + return ; + + pin = cmd.pin ; + if (noLocalPins && ((pin & PI_GPIO_MASK) == 0)) + { + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + continue ; + } + + switch (cmd.cmd) + { + case DRCN_PIN_MODE: + pinMode (pin, cmd.data) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_PULL_UP_DN: + pullUpDnControl (pin, cmd.data) ; + break ; + + case DRCN_PWM_WRITE: + pwmWrite (pin, cmd.data) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_DIGITAL_WRITE: + digitalWrite (pin, cmd.data) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_DIGITAL_WRITE8: + //digitalWrite8 (pin, cmd.data) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_DIGITAL_READ: + cmd.data = digitalRead (pin) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_DIGITAL_READ8: + //cmd.data = digitalRead8 (pin) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_ANALOG_WRITE: + analogWrite (pin, cmd.data) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + + case DRCN_ANALOG_READ: + cmd.data = analogRead (pin) ; + if (send (fd, &cmd, sizeof (cmd), 0) != sizeof (cmd)) + return ; + break ; + } + } + +} diff --git a/gpio/pins.c b/wiringPiD/runRemote.h similarity index 74% rename from gpio/pins.c rename to wiringPiD/runRemote.h index d889a45..57d5018 100644 --- a/gpio/pins.c +++ b/wiringPiD/runRemote.h @@ -1,7 +1,8 @@ /* - * pins.c: - * Just display a handy Pi pinnout diagram. - * Copyright (c) 2012-2015 Gordon Henderson + * runRemote.h: + * Run the remote commands passed over the network link. + * + * Copyright (c) 2012-2017 Gordon Henderson *********************************************************************** * This file is part of wiringPi: * https://projects.drogon.net/raspberry-pi/wiringpi/ @@ -21,13 +22,8 @@ *********************************************************************** */ +// Globals -#include - -void doPins (void) -{ - printf ("The pins command has been deprecated - sorry. Please use the\n") ; - printf (" gpio readall\n") ; - printf ("command to get a list of the pinnouts for your Pi.\n") ; -} +extern int noLocalPins ; +extern void runRemoteCommands (int fd) ; diff --git a/wiringPiD/wiringpid.c b/wiringPiD/wiringpid.c new file mode 100644 index 0000000..8dde1cd --- /dev/null +++ b/wiringPiD/wiringpid.c @@ -0,0 +1,382 @@ +/* + * wiringPiD.c: + * Copyright (c) 2012-2017 Gordon Henderson + *********************************************************************** + * This file is part of wiringPi: + * https://projects.drogon.net/raspberry-pi/wiringpi/ + * + * wiringPi is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * wiringPi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with wiringPi. If not, see . + *********************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "drcNetCmd.h" +#include "network.h" +#include "runRemote.h" +#include "daemonise.h" + + +#define PIDFILE "/var/run/wiringPiD.pid" + + +// Globals + +static const char *usage = "[-h] [-d] [-g | -1 | -z] [[-x extension:pin:params] ...] password" ; +static int doDaemon = FALSE ; + +// + +static void logMsg (const char *message, ...) +{ + va_list argp ; + char buffer [1024] ; + + va_start (argp, message) ; + vsnprintf (buffer, 1023, message, argp) ; + va_end (argp) ; + + if (doDaemon) + syslog (LOG_DAEMON | LOG_INFO, "%s", buffer) ; + else + printf ("%s\n", buffer) ; +} + + +/* + * sigHandler: + * setupSigHandler: + * Somehing has happened that would normally terminate the program so try + * to close down nicely. + ********************************************************************************* + */ + +void sigHandler (int sig) +{ + logMsg ("Exiting on signal %d: %s", sig, strsignal (sig)) ; + (void)unlink (PIDFILE) ; + exit (EXIT_FAILURE) ; +} + +void setupSigHandler (void) +{ + struct sigaction action ; + + sigemptyset (&action.sa_mask) ; + action.sa_flags = 0 ; + +// Ignore what we can + + action.sa_handler = SIG_IGN ; + + sigaction (SIGHUP, &action, NULL) ; + sigaction (SIGTTIN, &action, NULL) ; + sigaction (SIGTTOU, &action, NULL) ; + +// Trap what we can to exit gracefully + + action.sa_handler = sigHandler ; + + sigaction (SIGINT, &action, NULL) ; + sigaction (SIGQUIT, &action, NULL) ; + sigaction (SIGILL, &action, NULL) ; + sigaction (SIGABRT, &action, NULL) ; + sigaction (SIGFPE, &action, NULL) ; + sigaction (SIGSEGV, &action, NULL) ; + sigaction (SIGPIPE, &action, NULL) ; + sigaction (SIGALRM, &action, NULL) ; + sigaction (SIGTERM, &action, NULL) ; + sigaction (SIGUSR1, &action, NULL) ; + sigaction (SIGUSR2, &action, NULL) ; + sigaction (SIGCHLD, &action, NULL) ; + sigaction (SIGTSTP, &action, NULL) ; + sigaction (SIGBUS, &action, NULL) ; +} + + +/* + * The works... + ********************************************************************************* + */ + +int main (int argc, char *argv []) +{ + int clientFd ; + char *p, *password ; + int i ; + int port = DEFAULT_SERVER_PORT ; + int wpiSetup = 0 ; + + if (argc < 2) + { + fprintf (stderr, "Usage: %s %s\n", argv [0], usage) ; + exit (EXIT_FAILURE) ; + } + +// Help? + + if (strcasecmp (argv [1], "-h") == 0) + { + printf ("Usage: %s %s\n", argv [0], usage) ; + return 0 ; + } + +// Daemonize? +// Must come before the other args as e.g. some extensions +// open files which get closed on daemonise... + + if (strcasecmp (argv [1], "-d") == 0) + { + if (geteuid () != 0) + { + fprintf (stderr, "%s: Must be root to run as a daemon.\n", argv [0]) ; + exit (EXIT_FAILURE) ; + } + + doDaemon = TRUE ; + daemonise (PIDFILE) ; + + for (i = 2 ; i < argc ; ++i) + argv [i - 1] = argv [i] ; + --argc ; + } + +// Scan all other arguments + + while (*argv [1] == '-') + { + +// Look for wiringPi setup arguments: +// Same as the gpio command and rtb. + +// -g - bcm_gpio + + if (strcasecmp (argv [1], "-g") == 0) + { + if (wpiSetup == 0) + { + logMsg ("BCM_GPIO mode selected") ; + wiringPiSetupGpio () ; + } + + for (i = 2 ; i < argc ; ++i) + argv [i - 1] = argv [i] ; + --argc ; + ++wpiSetup ; + continue ; + } + +// -1 - physical pins + + if (strcasecmp (argv [1], "-1") == 0) + { + if (wpiSetup == 0) + { + logMsg ("GPIO-PHYS mode selected") ; + wiringPiSetupPhys () ; + } + + for (i = 2 ; i < argc ; ++i) + argv [i - 1] = argv [i] ; + --argc ; + ++wpiSetup ; + continue ; + } + +// -z - no wiringPi - blocks remotes accessing local pins + + if (strcasecmp (argv [1], "-z") == 0) + { + if (wpiSetup == 0) + logMsg ("No GPIO mode selected") ; + + for (i = 2 ; i < argc ; ++i) + argv [i - 1] = argv [i] ; + --argc ; + noLocalPins = TRUE ; + ++wpiSetup ; + continue ; + } + +// -p to select the port + + if (strcasecmp (argv [1], "-p") == 0) + { + if (argc < 3) + { + logMsg ("-p missing extension port") ; + exit (EXIT_FAILURE) ; + } + + logMsg ("Setting port to: %s", argv [2]) ; + + port = atoi (argv [2]) ; + if ((port < 1) || (port > 65535)) + { + logMsg ("Invalid server port: %d", port) ; + exit (EXIT_FAILURE) ; + } + +// Shift args down by 2 + + for (i = 3 ; i < argc ; ++i) + argv [i - 2] = argv [i] ; + argc -= 2 ; + + continue ; + } + +// Check for -x argument to load in a new extension +// -x extension:base:args +// Can load many modules to extend the daemon. + + if (strcasecmp (argv [1], "-x") == 0) + { + if (argc < 3) + { + logMsg ("-x missing extension name:data:etc.") ; + exit (EXIT_FAILURE) ; + } + + logMsg ("Loading extension: %s", argv [2]) ; + + if (!loadWPiExtension (argv [0], argv [2], TRUE)) + { + logMsg ("Extension load failed: %s", strerror (errno)) ; + exit (EXIT_FAILURE) ; + } + +// Shift args down by 2 + + for (i = 3 ; i < argc ; ++i) + argv [i - 2] = argv [i] ; + argc -= 2 ; + + continue ; + } + + logMsg ("Invalid parameter: %s", argv [1]) ; + exit (EXIT_FAILURE) ; + } + +// Default to wiringPi mode + + if (wpiSetup == 0) + { + logMsg ("WiringPi GPIO mode selected") ; + wiringPiSetup () ; + } + +// Finally, should just be one arg left - the password... + + if (argc != 2) + { + logMsg ("No password supplied") ; + exit (EXIT_FAILURE) ; + } + + if (strlen (argv [1]) < 6) + { + logMsg ("Password too short - at least 6 chars, not %d", strlen (argv [1])) ; + exit (EXIT_FAILURE) ; + } + + if ((password = malloc (strlen (argv [1]) + 1)) == NULL) + { + logMsg ("Out of memory") ; + exit (EXIT_FAILURE) ; + } + strcpy (password, argv [1]) ; + +// Wipe out the password on the command-line in a vague attempt to try to +// hide it from snoopers + + for (p = argv [1] ; *p ; ++p) + *p = ' ' ; + + setupSigHandler () ; + +// Enter our big loop + + for (;;) + { + + if (!doDaemon) + printf ("-=-\nWaiting for a new connection...\n") ; + + if ((clientFd = setupServer (port)) < 0) + { + logMsg ("Unable to setup server: %s", strerror (errno)) ; + exit (EXIT_FAILURE) ; + } + + logMsg ("New connection from: %s.", getClientIP ()) ; + + if (!doDaemon) + printf ("Sending Greeting.\n") ; + + if (sendGreeting (clientFd) < 0) + { + logMsg ("Unable to send greeting message: %s", strerror (errno)) ; + closeServer (clientFd) ; + continue ; + } + + if (!doDaemon) + printf ("Sending Challenge.\n") ; + + if (sendChallenge (clientFd) < 0) + { + logMsg ("Unable to send challenge message: %s", strerror (errno)) ; + closeServer (clientFd) ; + continue ; + } + + if (!doDaemon) + printf ("Waiting for response.\n") ; + + if (getResponse (clientFd) < 0) + { + logMsg ("Connection closed waiting for response: %s", strerror (errno)) ; + closeServer (clientFd) ; + continue ; + } + + if (!passwordMatch (password)) + { + logMsg ("Password failure") ; + closeServer (clientFd) ; + continue ; + } + + logMsg ("Password OK - Starting") ; + + runRemoteCommands (clientFd) ; + closeServer (clientFd) ; + } + + return 0 ; +}