diff --git a/FlippR-Driver/src/input/Detector.cpp b/FlippR-Driver/src/input/Detector.cpp new file mode 100644 index 0000000..0c63807 --- /dev/null +++ b/FlippR-Driver/src/input/Detector.cpp @@ -0,0 +1,98 @@ +/* + * Detector.cpp + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + */ + +#include "Detector.h" + +#include +#include +#include + +#include "../lib/wiringPi/wiringPi.h" + +namespace Input +{ + +Detector::Detector(std::set events) : + input_events(events), is_running(true) +{ + detect_thread = std::thread(&Detector::detect, this); +} + + +Detector::~Detector() +{ + is_running = false; + detect_thread.join(); +} + +void Detector::register_input_event_handler(InputEventHandler* handler) +{ + event_handler.insert(handler); +} + +void Detector::unregister_input_event_handler(InputEventHandler* handler) +{ + event_handler.erase(handler); +} + +void Detector::detect() +{ + while(is_running) + { + char address; + if(check_inputs(address)) + { + if(InputEvent* event = find_event(address)) + { + notify_handlers(*event); + } + } + } +} + +void Detector::notify_handlers(InputEvent& event) +{ + for(auto* handler : event_handler) + { + handler->handle(event); + } +} + +bool Detector::check_inputs(char& address) +{ + for(int row = 0; row < 8; row++) + { + digitalWrite(gpio["ROW_A"], row & 0b001); + digitalWrite(gpio["ROW_B"], row & 0b010); + digitalWrite(gpio["ROW_C"], row & 0b100); + + for(int col = 0; col < 8; col++) + { + digitalWrite(gpio["COL_A"], col & 0b001); + digitalWrite(gpio["COL_B"], col & 0b010); + digitalWrite(gpio["COL_C"], col & 0b100); + + // wait for mux to set address + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_DURATION)); + if(digitalRead(gpio["INPUT"])) + { + address = pow(2, row) + col; + return true; + } + } + } + return false; +} + +InputEvent* Detector::find_event(char address) +{ + return *std::find_if(input_events.begin(), input_events.end(), + [address] (InputEvent* e) { return *e == address; } + ); +} + +} diff --git a/FlippR-Driver/src/input/Detector.h b/FlippR-Driver/src/input/Detector.h new file mode 100644 index 0000000..7dc5c27 --- /dev/null +++ b/FlippR-Driver/src/input/Detector.h @@ -0,0 +1,54 @@ +/* + * Detector.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + */ + +#ifndef DETECTOR_H_ +#define DETECTOR_H_ + +#include +#include +#include +#include + +#include "InputEvent.h" +#include "InputEventHandler.h" + +#define SLEEP_DURATION 0.1f + +namespace Input +{ + +class Detector +{ +public: + Detector(std::set events); + ~Detector(); + + void register_input_event_handler(InputEventHandler* handler); + void unregister_input_event_handler(InputEventHandler* handler); + +private: + void detect(); + + bool check_inputs(char& address); + void notify_handlers(InputEvent& event); + InputEvent* find_event(char address); + +private: + std::map gpio; + + std::set input_events; + std::set event_handler; + + std::thread detect_thread; + bool is_running; +}; + +} + + + +#endif /* DETECTOR_H_ */ diff --git a/FlippR-Driver/src/input/InputEvent.h b/FlippR-Driver/src/input/InputEvent.h new file mode 100644 index 0000000..a48478a --- /dev/null +++ b/FlippR-Driver/src/input/InputEvent.h @@ -0,0 +1,44 @@ +/* + * InputEvent.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + */ + +#ifndef INPUTEVENT_H_ +#define INPUTEVENT_H_ + +#include +#include + +namespace Input +{ + +class InputEvent +{ +public: + InputEvent(char address, std::string name) : address(address), name(name){} + + bool operator==(const char other) + { + return this->address == other; + } + + bool operator==(const std::string other) + { + return this->name == other; + } + + bool operator<(const InputEvent& other) + { + return this->address < other.address; + } +private: + const char address; + const std::string name; +}; + +} + + +#endif /* INPUTEVENT_H_ */ diff --git a/FlippR-Driver/src/input/InputEventHandler.h b/FlippR-Driver/src/input/InputEventHandler.h new file mode 100644 index 0000000..1857a32 --- /dev/null +++ b/FlippR-Driver/src/input/InputEventHandler.h @@ -0,0 +1,26 @@ +/* + * InputEventHandler.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + */ + +#ifndef INPUTEVENTHANDLER_H_ +#define INPUTEVENTHANDLER_H_ + +#include "InputEvent.h" + +namespace Input +{ + + +class InputEventHandler +{ +public: + virtual ~InputEventHandler(){}; + virtual void handle(InputEvent& event) = 0; +}; + +} + +#endif /* INPUTEVENTHANDLER_H_ */ diff --git a/FlippR-Driver/src/input/InputFactory.h b/FlippR-Driver/src/input/InputFactory.h new file mode 100644 index 0000000..aa86965 --- /dev/null +++ b/FlippR-Driver/src/input/InputFactory.h @@ -0,0 +1,33 @@ +/* + * InputFactory.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + */ + +#ifndef INPUTFACTORY_H_ +#define INPUTFACTORY_H_ +#include + +#include "InputEvent.h" + +namespace Input +{ +class InputFactory +{ + +public: + InputFactory(); + ~InputFactory(); + + std::vector get_input_events(); + +private: + std::vector input_events; + +}; +} + + + +#endif /* INPUTFACTORY_H_ */ diff --git a/FlippR-Driver/src/input/main.cpp b/FlippR-Driver/src/input/main.cpp new file mode 100644 index 0000000..0fc28ce --- /dev/null +++ b/FlippR-Driver/src/input/main.cpp @@ -0,0 +1,12 @@ +#include +#include "InputEvent.h" +#include "Detector.h" +#include +int main() +{ + Input::Detector(std::set()); + + std::printf("hallo"); + + return 0; +} diff --git a/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER b/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/FlippR-Driver/src/lib/wiringPi/Makefile b/FlippR-Driver/src/lib/wiringPi/Makefile new file mode 100644 index 0000000..e1868b9 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/Makefile @@ -0,0 +1,177 @@ +# +# 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 + +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) + +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,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-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 libwiringPi.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 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/FlippR-Driver/src/lib/wiringPi/ads1115.c b/FlippR-Driver/src/lib/wiringPi/ads1115.c new file mode 100644 index 0000000..648e612 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/ads1115.c @@ -0,0 +1,293 @@ +/* + * ads1115.c: + * Extend wiringPi with the ADS1115 I2C 16-bit ADC + * 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 . + *********************************************************************** + */ + +/* + ********************************************************************************* + * We're going to work in a hybrid mode to fit in with the wiringPi way of + * doing things, so there will be 4 analog pin which read the 4 single-ended + * channels as usual, also some fake digitalOutputs - these are the control + * registers that allow the user to put it into single/diff mode, set the + * gain and data rates. + ********************************************************************************* + */ + +#include +#include +#include + +#include +#include + +#include "ads1115.h" + +// Bits in the config register (it's a 16-bit register) + +#define CONFIG_OS_MASK (0x8000) // Operational Status Register +#define CONFIG_OS_SINGLE (0x8000) // Write - Starts a single-conversion + // Read 1 = Conversion complete + +// The multiplexor + +#define CONFIG_MUX_MASK (0x7000) + +// Differential modes + +#define CONFIG_MUX_DIFF_0_1 (0x0000) // Pos = AIN0, Neg = AIN1 (default) +#define CONFIG_MUX_DIFF_0_3 (0x1000) // Pos = AIN0, Neg = AIN3 +#define CONFIG_MUX_DIFF_1_3 (0x2000) // Pos = AIN1, Neg = AIN3 +#define CONFIG_MUX_DIFF_2_3 (0x3000) // Pos = AIN2, Neg = AIN3 (2nd differential channel) + +// Single-ended modes + +#define CONFIG_MUX_SINGLE_0 (0x4000) // AIN0 +#define CONFIG_MUX_SINGLE_1 (0x5000) // AIN1 +#define CONFIG_MUX_SINGLE_2 (0x6000) // AIN2 +#define CONFIG_MUX_SINGLE_3 (0x7000) // AIN3 + +// Programmable Gain Amplifier + +#define CONFIG_PGA_MASK (0x0E00) +#define CONFIG_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3 +#define CONFIG_PGA_4_096V (0x0200) // +/-4.096V range = Gain 1 +#define CONFIG_PGA_2_048V (0x0400) // +/-2.048V range = Gain 2 (default) +#define CONFIG_PGA_1_024V (0x0600) // +/-1.024V range = Gain 4 +#define CONFIG_PGA_0_512V (0x0800) // +/-0.512V range = Gain 8 +#define CONFIG_PGA_0_256V (0x0A00) // +/-0.256V range = Gain 16 + +#define CONFIG_MODE (0x0100) // 0 is continuous, 1 is single-shot (default) + +// Data Rate + +#define CONFIG_DR_MASK (0x00E0) +#define CONFIG_DR_8SPS (0x0000) // 8 samples per second +#define CONFIG_DR_16SPS (0x0020) // 16 samples per second +#define CONFIG_DR_32SPS (0x0040) // 32 samples per second +#define CONFIG_DR_64SPS (0x0060) // 64 samples per second +#define CONFIG_DR_128SPS (0x0080) // 128 samples per second (default) +#define CONFIG_DR_475SPS (0x00A0) // 475 samples per second +#define CONFIG_DR_860SPS (0x00C0) // 860 samples per second + +// Comparator mode + +#define CONFIG_CMODE_MASK (0x0010) +#define CONFIG_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default) +#define CONFIG_CMODE_WINDOW (0x0010) // Window comparator + +// Comparator polarity - the polarity of the output alert/rdy pin + +#define CONFIG_CPOL_MASK (0x0008) +#define CONFIG_CPOL_ACTVLOW (0x0000) // Active low (default) +#define CONFIG_CPOL_ACTVHI (0x0008) // Active high + +// Latching comparator - does the alert/rdy pin latch + +#define CONFIG_CLAT_MASK (0x0004) +#define CONFIG_CLAT_NONLAT (0x0000) // Non-latching comparator (default) +#define CONFIG_CLAT_LATCH (0x0004) // Latching comparator + +// Comparitor queue + +#define CONFIG_CQUE_MASK (0x0003) +#define CONFIG_CQUE_1CONV (0x0000) // Assert after one conversions +#define CONFIG_CQUE_2CONV (0x0001) // Assert after two conversions +#define CONFIG_CQUE_4CONV (0x0002) // Assert after four conversions +#define CONFIG_CQUE_NONE (0x0003) // Disable the comparator (default) + +#define CONFIG_DEFAULT (0x8583) // From the datasheet + + +static const uint16_t dataRates [8] = +{ + CONFIG_DR_8SPS, CONFIG_DR_16SPS, CONFIG_DR_32SPS, CONFIG_DR_64SPS, CONFIG_DR_128SPS, CONFIG_DR_475SPS, CONFIG_DR_860SPS +} ; + +static const uint16_t gains [6] = +{ + CONFIG_PGA_6_144V, CONFIG_PGA_4_096V, CONFIG_PGA_2_048V, CONFIG_PGA_1_024V, CONFIG_PGA_0_512V, CONFIG_PGA_0_256V +} ; + + +/* + * analogRead: + * Pin is the channel to sample on the device. + * Channels 0-3 are single ended inputs, + * channels 4-7 are the various differential combinations. + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int chan = pin - node->pinBase ; + int16_t result ; + uint16_t config = CONFIG_DEFAULT ; + + chan &= 7 ; + +// Setup the configuration register + +// Set PGA/voltage range + + config &= ~CONFIG_PGA_MASK ; + config |= node->data0 ; + +// Set sample speed + + config &= ~CONFIG_DR_MASK ; + config |= node->data1 ; + +// Set single-ended channel or differential mode + + config &= ~CONFIG_MUX_MASK ; + + switch (chan) + { + case 0: config |= CONFIG_MUX_SINGLE_0 ; break ; + case 1: config |= CONFIG_MUX_SINGLE_1 ; break ; + case 2: config |= CONFIG_MUX_SINGLE_2 ; break ; + case 3: config |= CONFIG_MUX_SINGLE_3 ; break ; + + case 4: config |= CONFIG_MUX_DIFF_0_1 ; break ; + case 5: config |= CONFIG_MUX_DIFF_2_3 ; break ; + case 6: config |= CONFIG_MUX_DIFF_0_3 ; break ; + case 7: config |= CONFIG_MUX_DIFF_1_3 ; break ; + } + +// Start a single conversion + + config |= CONFIG_OS_SINGLE ; + config = __bswap_16 (config) ; + wiringPiI2CWriteReg16 (node->fd, 1, config) ; + +// Wait for the conversion to complete + + for (;;) + { + result = wiringPiI2CReadReg16 (node->fd, 1) ; + result = __bswap_16 (result) ; + if ((result & CONFIG_OS_MASK) != 0) + break ; + delayMicroseconds (100) ; + } + + result = wiringPiI2CReadReg16 (node->fd, 0) ; + result = __bswap_16 (result) ; + +// Sometimes with a 0v input on a single-ended channel the internal 0v reference +// can be higher than the input, so you get a negative result... + + if ( (chan < 4) && (result < 0) ) + return 0 ; + else + return (int)result ; +} + + +/* + * digitalWrite: + * It may seem odd to have a digital write here, but it's the best way + * to pass paramters into the chip in the wiringPi way of things. + * We have 2 digital registers: + * 0 is the gain control + * 1 is the data rate control + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int data) +{ + int chan = pin - node->pinBase ; + chan &= 3 ; + + if (chan == 0) // Gain Control + { + if ( (data < 0) || (data > 6) ) // Use default if out of range + data = 2 ; + node->data0 = gains [data] ; + } + else // Data rate control + { + if ( (data < 0) || (data > 7) ) // Use default if out of range + data = 4 ; + node->data1 = dataRates [data] ; // Bugfix 0-1 by "Eric de jong (gm)" - Thanks. + } + +} + + +/* + * analogWrite: + * We're using this to write to the 2 comparitor threshold registers. + * We could use a digitalWrite here but as it's an analog comparison + * then it feels better to do it this way. + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int data) +{ + int chan = pin - node->pinBase ; + int reg ; + int16_t ndata ; + + chan &= 3 ; + + reg = chan + 2 ; + + /**/ if (data < -32767) + ndata = -32767 ; + else if (data > 32767) + ndata = 32767 ; + else + ndata = (int16_t)data ; + + ndata = __bswap_16 (ndata) ; + wiringPiI2CWriteReg16 (node->fd, reg, data) ; +} + + + +/* + * ads1115Setup: + * Create a new wiringPi device node for an ads1115 on the Pi's + * I2C interface. + ********************************************************************************* + */ + +int ads1115Setup (const int pinBase, int i2cAddr) +{ + struct wiringPiNodeStruct *node ; + int fd ; + + if ((fd = wiringPiI2CSetup (i2cAddr)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 8) ; + + node->fd = fd ; + node->data0 = CONFIG_PGA_4_096V ; // Gain in data0 + node->data1 = CONFIG_DR_128SPS ; // Samples/sec in data1 + node->analogRead = myAnalogRead ; + node->analogWrite = myAnalogWrite ; + node->digitalWrite = myDigitalWrite ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/ads1115.h b/FlippR-Driver/src/lib/wiringPi/ads1115.h new file mode 100644 index 0000000..5c91735 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/ads1115.h @@ -0,0 +1,55 @@ +/* + * ads1115.c: + * Extend wiringPi with the ADS1115 I2C 16-bit ADC + * 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 . + *********************************************************************** + */ + +// Constants for some of the internal functions + +// Gain + +#define ADS1115_GAIN_6 0 +#define ADS1115_GAIN_4 1 +#define ADS1115_GAIN_2 2 +#define ADS1115_GAIN_1 3 +#define ADS1115_GAIN_HALF 4 +#define ADS1115_GAIN_QUARTER 5 + +// Data rate + +#define ADS1115_DR_8 0 +#define ADS1115_DR_16 1 +#define ADS1115_DR_32 2 +#define ADS1115_DR_64 3 +#define ADS1115_DR_128 4 +#define ADS1115_DR_250 5 +#define ADS1115_DR_475 6 +#define ADS1115_DR_860 7 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ads1115Setup (int pinBase, int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/bmp180.c b/FlippR-Driver/src/lib/wiringPi/bmp180.c new file mode 100644 index 0000000..bad4bb3 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/bmp180.h b/FlippR-Driver/src/lib/wiringPi/bmp180.h new file mode 100644 index 0000000..4a6d13a --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/drcNet.c b/FlippR-Driver/src/lib/wiringPi/drcNet.c new file mode 100644 index 0000000..0964ff7 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/drcNet.h b/FlippR-Driver/src/lib/wiringPi/drcNet.h new file mode 100644 index 0000000..00f9b05 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/drcSerial.c b/FlippR-Driver/src/lib/wiringPi/drcSerial.c new file mode 100644 index 0000000..db7cc09 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/drcSerial.c @@ -0,0 +1,196 @@ +/* + * drcSerial.c: + * Extend wiringPi with the DRC Serial protocol (e.g. to Arduino) + * Copyright (c) 2013-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 "wiringSerial.h" + +#include "drcSerial.h" + + +/* + * myPinMode: + * Change the pin mode on the remote DRC device + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + /**/ if (mode == OUTPUT) + serialPutchar (node->fd, 'o') ; // Input + else if (mode == PWM_OUTPUT) + serialPutchar (node->fd, 'p') ; // PWM + else + serialPutchar (node->fd, 'i') ; // Default to input + + serialPutchar (node->fd, pin - node->pinBase) ; +} + + +/* + * myPullUpDnControl: + * ATmegas only have pull-up's on of off. No pull-downs. + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + +// Force pin into input mode + + serialPutchar (node->fd, 'i' ) ; + serialPutchar (node->fd, pin - node->pinBase) ; + + /**/ if (mode == PUD_UP) + { + serialPutchar (node->fd, '1') ; + serialPutchar (node->fd, pin - node->pinBase) ; + } + else if (mode == PUD_OFF) + { + serialPutchar (node->fd, '0') ; + serialPutchar (node->fd, pin - node->pinBase) ; + } +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + serialPutchar (node->fd, value == 0 ? '0' : '1') ; + serialPutchar (node->fd, pin - node->pinBase) ; +} + + +/* + * myPwmWrite: + ********************************************************************************* + */ + +static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + serialPutchar (node->fd, 'v') ; + serialPutchar (node->fd, pin - node->pinBase) ; + serialPutchar (node->fd, value & 0xFF) ; +} + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int vHi, vLo ; + + serialPutchar (node->fd, 'a') ; + serialPutchar (node->fd, pin - node->pinBase) ; + vHi = serialGetchar (node->fd) ; + vLo = serialGetchar (node->fd) ; + + return (vHi << 8) | vLo ; +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + serialPutchar (node->fd, 'r') ; // Send read command + serialPutchar (node->fd, pin - node->pinBase) ; + return (serialGetchar (node->fd) == '0') ? 0 : 1 ; +} + + +/* + * drcSetup: + * Create a new instance of an DRC GPIO interface. + * Could be a variable nunber of pins here - we might not know in advance + * if it's an ATmega with 14 pins, or something with less or more! + ********************************************************************************* + */ + +int drcSetupSerial (const int pinBase, const int numPins, const char *device, const int baud) +{ + int fd ; + int ok, tries ; + time_t then ; + struct wiringPiNodeStruct *node ; + + if ((fd = serialOpen (device, baud)) < 0) + return FALSE ; + + delay (10) ; // May need longer if it's an Uno that reboots on the open... + +// Flush any pending input + + while (serialDataAvail (fd)) + (void)serialGetchar (fd) ; + + ok = FALSE ; + for (tries = 1 ; (tries < 5) && (!ok) ; ++tries) + { + serialPutchar (fd, '@') ; // Ping + then = time (NULL) + 2 ; + while (time (NULL) < then) + if (serialDataAvail (fd)) + { + if (serialGetchar (fd) == '@') + { + ok = TRUE ; + break ; + } + } + } + + if (!ok) + { + serialClose (fd) ; + return FALSE ; + } + + node = wiringPiNewNode (pinBase, numPins) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->analogRead = myAnalogRead ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->pwmWrite = myPwmWrite ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/drcSerial.h b/FlippR-Driver/src/lib/wiringPi/drcSerial.h new file mode 100644 index 0000000..29e988e --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/drcSerial.h @@ -0,0 +1,33 @@ +/* + * drcSerial.h: + * Extend wiringPi with the DRC Serial protocol (e.g. to Arduino) + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int drcSetupSerial (const int pinBase, const int numPins, const char *device, const int baud) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/ds18b20.c b/FlippR-Driver/src/lib/wiringPi/ds18b20.c new file mode 100644 index 0000000..533398e --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/ds18b20.h b/FlippR-Driver/src/lib/wiringPi/ds18b20.h new file mode 100644 index 0000000..a9ea291 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/htu21d.c b/FlippR-Driver/src/lib/wiringPi/htu21d.c new file mode 100644 index 0000000..46c0fcb --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/htu21d.h b/FlippR-Driver/src/lib/wiringPi/htu21d.h new file mode 100644 index 0000000..3965c54 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/max31855.c b/FlippR-Driver/src/lib/wiringPi/max31855.c new file mode 100644 index 0000000..d86cabd --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/max31855.c @@ -0,0 +1,99 @@ +/* + * max31855.c: + * Extend wiringPi with the max31855 SPI Analog to Digital convertor + * 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 . + *********************************************************************** + */ + +#include +#include + +#include +#include + +#include "max31855.h" + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + uint32_t spiData ; + int temp ; + int chan = pin - node->pinBase ; + + wiringPiSPIDataRW (node->fd, (unsigned char *)&spiData, 4) ; + + spiData = __bswap_32(spiData) ; + + switch (chan) + { + case 0: // Existing read - return raw value * 4 + spiData >>= 18 ; + temp = spiData & 0x1FFF ; // Bottom 13 bits + if ((spiData & 0x2000) != 0) // Negative + temp = -temp ; + + return temp ; + + case 1: // Return error bits + return spiData & 0x7 ; + + case 2: // Return temp in C * 10 + spiData >>= 18 ; + temp = spiData & 0x1FFF ; // Bottom 13 bits + if ((spiData & 0x2000) != 0) // Negative + temp = -temp ; + + return (int)((((double)temp * 25) + 0.5) / 10.0) ; + + case 3: // Return temp in F * 10 + spiData >>= 18 ; + temp = spiData & 0x1FFF ; // Bottom 13 bits + if ((spiData & 0x2000) != 0) // Negative + temp = -temp ; + + return (int)((((((double)temp * 0.25 * 9.0 / 5.0) + 32.0) * 100.0) + 0.5) / 10.0) ; + + default: // Who knows... + return 0 ; + + } +} + + +/* + * max31855Setup: + * Create a new wiringPi device node for an max31855 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int max31855Setup (const int pinBase, int spiChannel) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiChannel, 5000000) < 0) // 5MHz - prob 4 on the Pi + return FALSE ; + + node = wiringPiNewNode (pinBase, 4) ; + + node->fd = spiChannel ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/max31855.h b/FlippR-Driver/src/lib/wiringPi/max31855.h new file mode 100644 index 0000000..385c4bd --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/max31855.h @@ -0,0 +1,33 @@ +/* + * max31855.c: + * Extend wiringPi with the MAX31855 SPI Thermocouple driver + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int max31855Setup (int pinBase, int spiChannel) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/max5322.c b/FlippR-Driver/src/lib/wiringPi/max5322.c new file mode 100644 index 0000000..e56b085 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/max5322.c @@ -0,0 +1,84 @@ +/* + * max5322.c: + * Extend wiringPi with the MAX5322 SPI Digital to Analog convertor + * 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 "max5322.h" + +/* + * myAnalogWrite: + * Write analog value on the given pin + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + unsigned char spiData [2] ; + unsigned char chanBits, dataBits ; + int chan = pin - node->pinBase ; + + if (chan == 0) + chanBits = 0b01000000 ; + else + chanBits = 0b01010000 ; + + chanBits |= ((value >> 12) & 0x0F) ; + dataBits = ((value ) & 0xFF) ; + + spiData [0] = chanBits ; + spiData [1] = dataBits ; + + wiringPiSPIDataRW (node->fd, spiData, 2) ; +} + +/* + * max5322Setup: + * Create a new wiringPi device node for an max5322 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int max5322Setup (const int pinBase, int spiChannel) +{ + struct wiringPiNodeStruct *node ; + unsigned char spiData [2] ; + + if (wiringPiSPISetup (spiChannel, 8000000) < 0) // 10MHz Max + return FALSE ; + + node = wiringPiNewNode (pinBase, 2) ; + + node->fd = spiChannel ; + node->analogWrite = myAnalogWrite ; + +// Enable both DACs + + spiData [0] = 0b11100000 ; + spiData [1] = 0 ; + + wiringPiSPIDataRW (node->fd, spiData, 2) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/max5322.h b/FlippR-Driver/src/lib/wiringPi/max5322.h new file mode 100644 index 0000000..a217cf8 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/max5322.h @@ -0,0 +1,33 @@ +/* + * max5322.h: + * Extend wiringPi with the MAX5322 SPI Digital to Analog convertor + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int max5322Setup (int pinBase, int spiChannel) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23008.c b/FlippR-Driver/src/lib/wiringPi/mcp23008.c new file mode 100644 index 0000000..71757a8 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23008.c @@ -0,0 +1,149 @@ +/* + * mcp23008.c: + * Extend wiringPi with the MCP 23008 I2C GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiI2C.h" +#include "mcp23x0817.h" + +#include "mcp23008.h" + + +/* + * myPinMode: + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + reg = MCP23x08_IODIR ; + mask = 1 << (pin - node->pinBase) ; + old = wiringPiI2CReadReg8 (node->fd, reg) ; + + if (mode == OUTPUT) + old &= (~mask) ; + else + old |= mask ; + + wiringPiI2CWriteReg8 (node->fd, reg, old) ; +} + + +/* + * myPullUpDnControl: + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + reg = MCP23x08_GPPU ; + mask = 1 << (pin - node->pinBase) ; + + old = wiringPiI2CReadReg8 (node->fd, reg) ; + + if (mode == PUD_UP) + old |= mask ; + else + old &= (~mask) ; + + wiringPiI2CWriteReg8 (node->fd, reg, old) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + bit = 1 << ((pin - node->pinBase) & 7) ; + + old = node->data2 ; + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWriteReg8 (node->fd, MCP23x08_GPIO, old) ; + node->data2 = old ; +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value ; + + mask = 1 << ((pin - node->pinBase) & 7) ; + value = wiringPiI2CReadReg8 (node->fd, MCP23x08_GPIO) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * mcp23008Setup: + * Create a new instance of an MCP23008 I2C GPIO interface. We know it + * has 8 pins, so all we need to know here is the I2C address and the + * user-defined pin base. + ********************************************************************************* + */ + +int mcp23008Setup (const int pinBase, const int i2cAddress) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + wiringPiI2CWriteReg8 (fd, MCP23x08_IOCON, IOCON_INIT) ; + + node = wiringPiNewNode (pinBase, 8) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = wiringPiI2CReadReg8 (fd, MCP23x08_OLAT) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23008.h b/FlippR-Driver/src/lib/wiringPi/mcp23008.h new file mode 100644 index 0000000..e9299a8 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23008.h @@ -0,0 +1,33 @@ +/* + * 23008.h: + * Extend wiringPi with the MCP 23008 I2C GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp23008Setup (const int pinBase, const int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016.c b/FlippR-Driver/src/lib/wiringPi/mcp23016.c new file mode 100644 index 0000000..928d9e5 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23016.c @@ -0,0 +1,164 @@ +/* + * mcp23016.c: + * Extend wiringPi with the MCP 23016 I2C GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiI2C.h" +#include "mcp23016.h" + +#include "mcp23016reg.h" + + +/* + * myPinMode: + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + reg = MCP23016_IODIR0 ; + else + { + reg = MCP23016_IODIR1 ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + old = wiringPiI2CReadReg8 (node->fd, reg) ; + + if (mode == OUTPUT) + old &= (~mask) ; + else + old |= mask ; + + wiringPiI2CWriteReg8 (node->fd, reg, old) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + pin -= node->pinBase ; // Pin now 0-15 + + bit = 1 << (pin & 7) ; + + if (pin < 8) // Bank A + { + old = node->data2 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWriteReg8 (node->fd, MCP23016_GP0, old) ; + node->data2 = old ; + } + else // Bank B + { + old = node->data3 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWriteReg8 (node->fd, MCP23016_GP1, old) ; + node->data3 = old ; + } +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value, gpio ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + gpio = MCP23016_GP0 ; + else + { + gpio = MCP23016_GP1 ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + value = wiringPiI2CReadReg8 (node->fd, gpio) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * mcp23016Setup: + * Create a new instance of an MCP23016 I2C GPIO interface. We know it + * has 16 pins, so all we need to know here is the I2C address and the + * user-defined pin base. + ********************************************************************************* + */ + +int mcp23016Setup (const int pinBase, const int i2cAddress) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + wiringPiI2CWriteReg8 (fd, MCP23016_IOCON0, IOCON_INIT) ; + wiringPiI2CWriteReg8 (fd, MCP23016_IOCON1, IOCON_INIT) ; + + node = wiringPiNewNode (pinBase, 16) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = wiringPiI2CReadReg8 (fd, MCP23016_OLAT0) ; + node->data3 = wiringPiI2CReadReg8 (fd, MCP23016_OLAT1) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016.h b/FlippR-Driver/src/lib/wiringPi/mcp23016.h new file mode 100644 index 0000000..f9b5cc5 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23016.h @@ -0,0 +1,33 @@ +/* + * mcp23016.h: + * Extend wiringPi with the MCP 23016 I2C GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp23016Setup (const int pinBase, const int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h b/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h new file mode 100644 index 0000000..9aea92d --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h @@ -0,0 +1,48 @@ +/* + * mcp23016: + * Copyright (c) 2012-2013 Gordon Henderson + * + * Header file for code using the MCP23016 GPIO expander + * chip. + *********************************************************************** + * 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 . + *********************************************************************** + */ + +// MCP23016 Registers + +#define MCP23016_GP0 0x00 +#define MCP23016_GP1 0x01 +#define MCP23016_OLAT0 0x02 +#define MCP23016_OLAT1 0x03 +#define MCP23016_IPOL0 0x04 +#define MCP23016_IPOL1 0x05 +#define MCP23016_IODIR0 0x06 +#define MCP23016_IODIR1 0x07 +#define MCP23016_INTCAP0 0x08 +#define MCP23016_INTCAP1 0x09 +#define MCP23016_IOCON0 0x0A +#define MCP23016_IOCON1 0x0B + +// Bits in the IOCON register + +#define IOCON_IARES 0x01 + +// Default initialisation mode + +#define IOCON_INIT 0 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23017.c b/FlippR-Driver/src/lib/wiringPi/mcp23017.c new file mode 100644 index 0000000..4c3952d --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23017.c @@ -0,0 +1,195 @@ +/* + * mcp23017.c: + * Extend wiringPi with the MCP 23017 I2C GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiI2C.h" +#include "mcp23x0817.h" + +#include "mcp23017.h" + + +/* + * myPinMode: + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + reg = MCP23x17_IODIRA ; + else + { + reg = MCP23x17_IODIRB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + old = wiringPiI2CReadReg8 (node->fd, reg) ; + + if (mode == OUTPUT) + old &= (~mask) ; + else + old |= mask ; + + wiringPiI2CWriteReg8 (node->fd, reg, old) ; +} + + +/* + * myPullUpDnControl: + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + reg = MCP23x17_GPPUA ; + else + { + reg = MCP23x17_GPPUB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + old = wiringPiI2CReadReg8 (node->fd, reg) ; + + if (mode == PUD_UP) + old |= mask ; + else + old &= (~mask) ; + + wiringPiI2CWriteReg8 (node->fd, reg, old) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + pin -= node->pinBase ; // Pin now 0-15 + + bit = 1 << (pin & 7) ; + + if (pin < 8) // Bank A + { + old = node->data2 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWriteReg8 (node->fd, MCP23x17_GPIOA, old) ; + node->data2 = old ; + } + else // Bank B + { + old = node->data3 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWriteReg8 (node->fd, MCP23x17_GPIOB, old) ; + node->data3 = old ; + } +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value, gpio ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + gpio = MCP23x17_GPIOA ; + else + { + gpio = MCP23x17_GPIOB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + value = wiringPiI2CReadReg8 (node->fd, gpio) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * mcp23017Setup: + * Create a new instance of an MCP23017 I2C GPIO interface. We know it + * has 16 pins, so all we need to know here is the I2C address and the + * user-defined pin base. + ********************************************************************************* + */ + +int mcp23017Setup (const int pinBase, const int i2cAddress) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + wiringPiI2CWriteReg8 (fd, MCP23x17_IOCON, IOCON_INIT) ; + + node = wiringPiNewNode (pinBase, 16) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = wiringPiI2CReadReg8 (fd, MCP23x17_OLATA) ; + node->data3 = wiringPiI2CReadReg8 (fd, MCP23x17_OLATB) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23017.h b/FlippR-Driver/src/lib/wiringPi/mcp23017.h new file mode 100644 index 0000000..79b4d7b --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23017.h @@ -0,0 +1,33 @@ +/* + * 23017.h: + * Extend wiringPi with the MCP 23017 I2C GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp23017Setup (const int pinBase, const int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s08.c b/FlippR-Driver/src/lib/wiringPi/mcp23s08.c new file mode 100644 index 0000000..f293f3a --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23s08.c @@ -0,0 +1,188 @@ +/* + * mcp23s08.c: + * Extend wiringPi with the MCP 23s08 SPI GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiSPI.h" +#include "mcp23x0817.h" + +#include "mcp23s08.h" + +#define MCP_SPEED 4000000 + + + +/* + * writeByte: + * Write a byte to a register on the MCP23s08 on the SPI bus. + ********************************************************************************* + */ + +static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data) +{ + uint8_t spiData [4] ; + + spiData [0] = CMD_WRITE | ((devId & 7) << 1) ; + spiData [1] = reg ; + spiData [2] = data ; + + wiringPiSPIDataRW (spiPort, spiData, 3) ; +} + +/* + * readByte: + * Read a byte from a register on the MCP23s08 on the SPI bus. + ********************************************************************************* + */ + +static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg) +{ + uint8_t spiData [4] ; + + spiData [0] = CMD_READ | ((devId & 7) << 1) ; + spiData [1] = reg ; + + wiringPiSPIDataRW (spiPort, spiData, 3) ; + + return spiData [2] ; +} + + +/* + * myPinMode: + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + reg = MCP23x08_IODIR ; + mask = 1 << (pin - node->pinBase) ; + old = readByte (node->data0, node->data1, reg) ; + + if (mode == OUTPUT) + old &= (~mask) ; + else + old |= mask ; + + writeByte (node->data0, node->data1, reg, old) ; +} + + +/* + * myPullUpDnControl: + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + reg = MCP23x08_GPPU ; + mask = 1 << (pin - node->pinBase) ; + + old = readByte (node->data0, node->data1, reg) ; + + if (mode == PUD_UP) + old |= mask ; + else + old &= (~mask) ; + + writeByte (node->data0, node->data1, reg, old) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + bit = 1 << ((pin - node->pinBase) & 7) ; + + old = node->data2 ; + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + writeByte (node->data0, node->data1, MCP23x08_GPIO, old) ; + node->data2 = old ; +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value ; + + mask = 1 << ((pin - node->pinBase) & 7) ; + value = readByte (node->data0, node->data1, MCP23x08_GPIO) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * mcp23s08Setup: + * Create a new instance of an MCP23s08 SPI GPIO interface. We know it + * has 8 pins, so all we need to know here is the SPI address and the + * user-defined pin base. + ********************************************************************************* + */ + +int mcp23s08Setup (const int pinBase, const int spiPort, const int devId) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiPort, MCP_SPEED) < 0) + return FALSE ; + + writeByte (spiPort, devId, MCP23x08_IOCON, IOCON_INIT) ; + + node = wiringPiNewNode (pinBase, 8) ; + + node->data0 = spiPort ; + node->data1 = devId ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = readByte (spiPort, devId, MCP23x08_OLAT) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s08.h b/FlippR-Driver/src/lib/wiringPi/mcp23s08.h new file mode 100644 index 0000000..ebf93d1 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23s08.h @@ -0,0 +1,33 @@ +/* + * 23s08.h: + * Extend wiringPi with the MCP 23s08 SPI GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp23s08Setup (const int pinBase, const int spiPort, const int devId) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s17.c b/FlippR-Driver/src/lib/wiringPi/mcp23s17.c new file mode 100644 index 0000000..42b0358 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23s17.c @@ -0,0 +1,235 @@ +/* + * mcp23s17.c: + * Extend wiringPi with the MCP 23s17 SPI GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiSPI.h" +#include "mcp23x0817.h" + +#include "mcp23s17.h" + +#define MCP_SPEED 4000000 + + + +/* + * writeByte: + * Write a byte to a register on the MCP23s17 on the SPI bus. + ********************************************************************************* + */ + +static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data) +{ + uint8_t spiData [4] ; + + spiData [0] = CMD_WRITE | ((devId & 7) << 1) ; + spiData [1] = reg ; + spiData [2] = data ; + + wiringPiSPIDataRW (spiPort, spiData, 3) ; +} + +/* + * readByte: + * Read a byte from a register on the MCP23s17 on the SPI bus. + ********************************************************************************* + */ + +static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg) +{ + uint8_t spiData [4] ; + + spiData [0] = CMD_READ | ((devId & 7) << 1) ; + spiData [1] = reg ; + + wiringPiSPIDataRW (spiPort, spiData, 3) ; + + return spiData [2] ; +} + + +/* + * myPinMode: + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + reg = MCP23x17_IODIRA ; + else + { + reg = MCP23x17_IODIRB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + old = readByte (node->data0, node->data1, reg) ; + + if (mode == OUTPUT) + old &= (~mask) ; + else + old |= mask ; + + writeByte (node->data0, node->data1, reg, old) ; +} + + +/* + * myPullUpDnControl: + ********************************************************************************* + */ + +static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int mask, old, reg ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + reg = MCP23x17_GPPUA ; + else + { + reg = MCP23x17_GPPUB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + old = readByte (node->data0, node->data1, reg) ; + + if (mode == PUD_UP) + old |= mask ; + else + old &= (~mask) ; + + writeByte (node->data0, node->data1, reg, old) ; +} + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + pin -= node->pinBase ; // Pin now 0-15 + + bit = 1 << (pin & 7) ; + + if (pin < 8) // Bank A + { + old = node->data2 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + writeByte (node->data0, node->data1, MCP23x17_GPIOA, old) ; + node->data2 = old ; + } + else // Bank B + { + old = node->data3 ; + + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + writeByte (node->data0, node->data1, MCP23x17_GPIOB, old) ; + node->data3 = old ; + } +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value, gpio ; + + pin -= node->pinBase ; + + if (pin < 8) // Bank A + gpio = MCP23x17_GPIOA ; + else + { + gpio = MCP23x17_GPIOB ; + pin &= 0x07 ; + } + + mask = 1 << pin ; + value = readByte (node->data0, node->data1, gpio) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * mcp23s17Setup: + * Create a new instance of an MCP23s17 SPI GPIO interface. We know it + * has 16 pins, so all we need to know here is the SPI address and the + * user-defined pin base. + ********************************************************************************* + */ + +int mcp23s17Setup (const int pinBase, const int spiPort, const int devId) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiPort, MCP_SPEED) < 0) + return FALSE ; + + writeByte (spiPort, devId, MCP23x17_IOCON, IOCON_INIT | IOCON_HAEN) ; + writeByte (spiPort, devId, MCP23x17_IOCONB, IOCON_INIT | IOCON_HAEN) ; + + node = wiringPiNewNode (pinBase, 16) ; + + node->data0 = spiPort ; + node->data1 = devId ; + node->pinMode = myPinMode ; + node->pullUpDnControl = myPullUpDnControl ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = readByte (spiPort, devId, MCP23x17_OLATA) ; + node->data3 = readByte (spiPort, devId, MCP23x17_OLATB) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s17.h b/FlippR-Driver/src/lib/wiringPi/mcp23s17.h new file mode 100644 index 0000000..3b2a808 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23s17.h @@ -0,0 +1,33 @@ +/* + * 23s17.h: + * Extend wiringPi with the MCP 23s17 SPI GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp23s17Setup (int pinBase, int spiPort, int devId) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23x08.h b/FlippR-Driver/src/lib/wiringPi/mcp23x08.h new file mode 100644 index 0000000..c4e6b27 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23x08.h @@ -0,0 +1,73 @@ +/* + * mcp23x17: + * Copyright (c) 2012-2013 Gordon Henderson + * + * Header file for code using the MCP23x17 GPIO expander chip. + * This comes in 2 flavours: MCP23017 which has an I2C interface, + * an the MXP23S17 which has an SPI interface. + *********************************************************************** + * 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 . + *********************************************************************** + */ + + +// MCP23x17 Registers + +#define IODIRA 0x00 +#define IPOLA 0x02 +#define GPINTENA 0x04 +#define DEFVALA 0x06 +#define INTCONA 0x08 +#define IOCON 0x0A +#define GPPUA 0x0C +#define INTFA 0x0E +#define INTCAPA 0x10 +#define GPIOA 0x12 +#define OLATA 0x14 + +#define IODIRB 0x01 +#define IPOLB 0x03 +#define GPINTENB 0x05 +#define DEFVALB 0x07 +#define INTCONB 0x09 +#define IOCONB 0x0B +#define GPPUB 0x0D +#define INTFB 0x0F +#define INTCAPB 0x11 +#define GPIOB 0x13 +#define OLATB 0x15 + +// Bits in the IOCON register + +#define IOCON_UNUSED 0x01 +#define IOCON_INTPOL 0x02 +#define IOCON_ODR 0x04 +#define IOCON_HAEN 0x08 +#define IOCON_DISSLW 0x10 +#define IOCON_SEQOP 0x20 +#define IOCON_MIRROR 0x40 +#define IOCON_BANK_MODE 0x80 + +// Default initialisation mode + +#define IOCON_INIT (IOCON_SEQOP) + +// SPI Command codes + +#define CMD_WRITE 0x40 +#define CMD_READ 0x41 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h b/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h new file mode 100644 index 0000000..58bc038 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h @@ -0,0 +1,87 @@ +/* + * mcp23xxx: + * Copyright (c) 2012-2013 Gordon Henderson + * + * Header file for code using the MCP23x08 and 17 GPIO expander + * chips. + * This comes in 2 flavours: MCP230xx (08/17) which has an I2C + * interface, and the MXP23Sxx (08/17) which has an SPI interface. + *********************************************************************** + * 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 . + *********************************************************************** + */ + +// MCP23x08 Registers + +#define MCP23x08_IODIR 0x00 +#define MCP23x08_IPOL 0x01 +#define MCP23x08_GPINTEN 0x02 +#define MCP23x08_DEFVAL 0x03 +#define MCP23x08_INTCON 0x04 +#define MCP23x08_IOCON 0x05 +#define MCP23x08_GPPU 0x06 +#define MCP23x08_INTF 0x07 +#define MCP23x08_INTCAP 0x08 +#define MCP23x08_GPIO 0x09 +#define MCP23x08_OLAT 0x0A + +// MCP23x17 Registers + +#define MCP23x17_IODIRA 0x00 +#define MCP23x17_IPOLA 0x02 +#define MCP23x17_GPINTENA 0x04 +#define MCP23x17_DEFVALA 0x06 +#define MCP23x17_INTCONA 0x08 +#define MCP23x17_IOCON 0x0A +#define MCP23x17_GPPUA 0x0C +#define MCP23x17_INTFA 0x0E +#define MCP23x17_INTCAPA 0x10 +#define MCP23x17_GPIOA 0x12 +#define MCP23x17_OLATA 0x14 + +#define MCP23x17_IODIRB 0x01 +#define MCP23x17_IPOLB 0x03 +#define MCP23x17_GPINTENB 0x05 +#define MCP23x17_DEFVALB 0x07 +#define MCP23x17_INTCONB 0x09 +#define MCP23x17_IOCONB 0x0B +#define MCP23x17_GPPUB 0x0D +#define MCP23x17_INTFB 0x0F +#define MCP23x17_INTCAPB 0x11 +#define MCP23x17_GPIOB 0x13 +#define MCP23x17_OLATB 0x15 + +// Bits in the IOCON register + +#define IOCON_UNUSED 0x01 +#define IOCON_INTPOL 0x02 +#define IOCON_ODR 0x04 +#define IOCON_HAEN 0x08 +#define IOCON_DISSLW 0x10 +#define IOCON_SEQOP 0x20 +#define IOCON_MIRROR 0x40 +#define IOCON_BANK_MODE 0x80 + +// Default initialisation mode + +#define IOCON_INIT (IOCON_SEQOP) + +// SPI Command codes + +#define CMD_WRITE 0x40 +#define CMD_READ 0x41 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3002.c b/FlippR-Driver/src/lib/wiringPi/mcp3002.c new file mode 100644 index 0000000..9ebf3e4 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3002.c @@ -0,0 +1,76 @@ +/* + * mcp3002.c: + * Extend wiringPi with the MCP3002 SPI Analog to Digital convertor + * 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 "mcp3002.h" + +/* + * myAnalogRead: + * Return the analog value of the given pin + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + unsigned char spiData [2] ; + unsigned char chanBits ; + int chan = pin - node->pinBase ; + + if (chan == 0) + chanBits = 0b11010000 ; + else + chanBits = 0b11110000 ; + + spiData [0] = chanBits ; + spiData [1] = 0 ; + + wiringPiSPIDataRW (node->fd, spiData, 2) ; + + return ((spiData [0] << 8) | (spiData [1] >> 1)) & 0x3FF ; +} + + +/* + * mcp3002Setup: + * Create a new wiringPi device node for an mcp3002 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int mcp3002Setup (const int pinBase, int spiChannel) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiChannel, 1000000) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 2) ; + + node->fd = spiChannel ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3002.h b/FlippR-Driver/src/lib/wiringPi/mcp3002.h new file mode 100644 index 0000000..0cd727f --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3002.h @@ -0,0 +1,33 @@ +/* + * mcp3002.c: + * Extend wiringPi with the MCP3002 SPI Analog to Digital convertor + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp3002Setup (int pinBase, int spiChannel) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3004.c b/FlippR-Driver/src/lib/wiringPi/mcp3004.c new file mode 100644 index 0000000..be8383e --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3004.c @@ -0,0 +1,76 @@ +/* + * mcp3004.c: + * Extend wiringPi with the MCP3004 SPI Analog to Digital convertor + * Copyright (c) 2012-2013 Gordon Henderson + * + * Thanks also to "ShorTie" on IRC for some remote debugging help! + *********************************************************************** + * 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 "mcp3004.h" + +/* + * myAnalogRead: + * Return the analog value of the given pin + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + unsigned char spiData [3] ; + unsigned char chanBits ; + int chan = pin - node->pinBase ; + + chanBits = 0b10000000 | (chan << 4) ; + + spiData [0] = 1 ; // Start bit + spiData [1] = chanBits ; + spiData [2] = 0 ; + + wiringPiSPIDataRW (node->fd, spiData, 3) ; + + return ((spiData [1] << 8) | spiData [2]) & 0x3FF ; +} + + +/* + * mcp3004Setup: + * Create a new wiringPi device node for an mcp3004 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int mcp3004Setup (const int pinBase, int spiChannel) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiChannel, 1000000) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 8) ; + + node->fd = spiChannel ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3004.h b/FlippR-Driver/src/lib/wiringPi/mcp3004.h new file mode 100644 index 0000000..a07c0bf --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3004.h @@ -0,0 +1,33 @@ +/* + * mcp3004.c: + * Extend wiringPi with the MCP3004 SPI Analog to Digital convertor + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp3004Setup (int pinBase, int spiChannel) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3422.c b/FlippR-Driver/src/lib/wiringPi/mcp3422.c new file mode 100644 index 0000000..be14db6 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3422.c @@ -0,0 +1,125 @@ +/* + * mcp3422.c: + * Extend wiringPi with the MCP3422/3/4 I2C ADC chip + * This code assumes single-ended mode only. + * Tested on actual hardware: 20th Feb 2016. + * Copyright (c) 2013-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 "mcp3422.h" + + +/* + * waitForConversion: + * Common code to wait for the ADC to finish conversion + ********************************************************************************* + */ + +void waitForConversion (int fd, unsigned char *buffer, int n) +{ + for (;;) + { + read (fd, buffer, n) ; + if ((buffer [n-1] & 0x80) == 0) + break ; + delay (1) ; + } +} + +/* + * myAnalogRead: + * Read a channel from the device + ********************************************************************************* + */ + +int myAnalogRead (struct wiringPiNodeStruct *node, int chan) +{ + unsigned char config ; + unsigned char buffer [4] ; + int value = 0 ; + int realChan = (chan & 3) - node->pinBase ; + +// One-shot mode, trigger plus the other configs. + + config = 0x80 | (realChan << 5) | (node->data0 << 2) | (node->data1) ; + + wiringPiI2CWrite (node->fd, config) ; + + switch (node->data0) // Sample rate + { + case MCP3422_SR_3_75: // 18 bits + waitForConversion (node->fd, &buffer [0], 4) ; + value = ((buffer [0] & 3) << 16) | (buffer [1] << 8) | buffer [2] ; + break ; + + case MCP3422_SR_15: // 16 bits + waitForConversion (node->fd, buffer, 3) ; + value = (buffer [0] << 8) | buffer [1] ; + break ; + + case MCP3422_SR_60: // 14 bits + waitForConversion (node->fd, buffer, 3) ; + value = ((buffer [0] & 0x3F) << 8) | buffer [1] ; + break ; + + case MCP3422_SR_240: // 12 bits - default + waitForConversion (node->fd, buffer, 3) ; + value = ((buffer [0] & 0x0F) << 8) | buffer [1] ; + break ; + } + + return value ; +} + + +/* + * mcp3422Setup: + * Create a new wiringPi device node for the mcp3422 + ********************************************************************************* + */ + +int mcp3422Setup (int pinBase, int i2cAddress, int sampleRate, int gain) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 4) ; + + node->fd = fd ; + node->data0 = sampleRate ; + node->data1 = gain ; + node->analogRead = myAnalogRead ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3422.h b/FlippR-Driver/src/lib/wiringPi/mcp3422.h new file mode 100644 index 0000000..72647d4 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp3422.h @@ -0,0 +1,43 @@ +/* + * mcp3422.h: + * Extend wiringPi with the MCP3422/3/4 I2C ADC chip + *********************************************************************** + * 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 MCP3422_SR_240 0 +#define MCP3422_SR_60 1 +#define MCP3422_SR_15 2 +#define MCP3422_SR_3_75 3 + +#define MCP3422_GAIN_1 0 +#define MCP3422_GAIN_2 1 +#define MCP3422_GAIN_4 2 +#define MCP3422_GAIN_8 3 + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp3422Setup (int pinBase, int i2cAddress, int sampleRate, int gain) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp4802.c b/FlippR-Driver/src/lib/wiringPi/mcp4802.c new file mode 100644 index 0000000..ef104ed --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp4802.c @@ -0,0 +1,76 @@ +/* + * mcp4802.c: + * Extend wiringPi with the MCP4802 SPI Digital to Analog convertor + * 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 "mcp4802.h" + +/* + * myAnalogWrite: + * Write analog value on the given pin + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + unsigned char spiData [2] ; + unsigned char chanBits, dataBits ; + int chan = pin - node->pinBase ; + + if (chan == 0) + chanBits = 0x30 ; + else + chanBits = 0xB0 ; + + chanBits |= ((value >> 4) & 0x0F) ; + dataBits = ((value << 4) & 0xF0) ; + + spiData [0] = chanBits ; + spiData [1] = dataBits ; + + wiringPiSPIDataRW (node->fd, spiData, 2) ; +} + +/* + * mcp4802Setup: + * Create a new wiringPi device node for an mcp4802 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int mcp4802Setup (const int pinBase, int spiChannel) +{ + struct wiringPiNodeStruct *node ; + + if (wiringPiSPISetup (spiChannel, 1000000) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 2) ; + + node->fd = spiChannel ; + node->analogWrite = myAnalogWrite ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp4802.h b/FlippR-Driver/src/lib/wiringPi/mcp4802.h new file mode 100644 index 0000000..effa024 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/mcp4802.h @@ -0,0 +1,33 @@ +/* + * mcp4802.c: + * Extend wiringPi with the MCP4802 SPI Digital to Analog convertor + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mcp4802Setup (int pinBase, int spiChannel) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8574.c b/FlippR-Driver/src/lib/wiringPi/pcf8574.c new file mode 100644 index 0000000..e0b686a --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/pcf8574.c @@ -0,0 +1,126 @@ +/* + * pcf8574.c: + * Extend wiringPi with the PCF8574 I2C GPIO expander chip + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiI2C.h" + +#include "pcf8574.h" + + +/* + * myPinMode: + * The PCF8574 is an odd chip - the pins are effectively bi-directional, + * however the pins should be drven high when used as an input pin... + * So, we're effectively copying digitalWrite... + ********************************************************************************* + */ + +static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) +{ + int bit, old ; + + bit = 1 << ((pin - node->pinBase) & 7) ; + + old = node->data2 ; + if (mode == OUTPUT) + old &= (~bit) ; // Write bit to 0 + else + old |= bit ; // Write bit to 1 + + wiringPiI2CWrite (node->fd, old) ; + node->data2 = old ; +} + + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int bit, old ; + + bit = 1 << ((pin - node->pinBase) & 7) ; + + old = node->data2 ; + if (value == LOW) + old &= (~bit) ; + else + old |= bit ; + + wiringPiI2CWrite (node->fd, old) ; + node->data2 = old ; +} + + +/* + * myDigitalRead: + ********************************************************************************* + */ + +static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) +{ + int mask, value ; + + mask = 1 << ((pin - node->pinBase) & 7) ; + value = wiringPiI2CRead (node->fd) ; + + if ((value & mask) == 0) + return LOW ; + else + return HIGH ; +} + + +/* + * pcf8574Setup: + * Create a new instance of a PCF8574 I2C GPIO interface. We know it + * has 8 pins, so all we need to know here is the I2C address and the + * user-defined pin base. + ********************************************************************************* + */ + +int pcf8574Setup (const int pinBase, const int i2cAddress) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 8) ; + + node->fd = fd ; + node->pinMode = myPinMode ; + node->digitalRead = myDigitalRead ; + node->digitalWrite = myDigitalWrite ; + node->data2 = wiringPiI2CRead (fd) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8574.h b/FlippR-Driver/src/lib/wiringPi/pcf8574.h new file mode 100644 index 0000000..8e2d818 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/pcf8574.h @@ -0,0 +1,33 @@ +/* + * pcf8574.h: + * Extend wiringPi with the PCF8574 I2C GPIO expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int pcf8574Setup (const int pinBase, const int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8591.c b/FlippR-Driver/src/lib/wiringPi/pcf8591.c new file mode 100644 index 0000000..66c6255 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/pcf8591.c @@ -0,0 +1,90 @@ +/* + * pcf8591.c: + * Extend wiringPi with the PCF8591 I2C GPIO Analog expander chip + * The chip has 1 8-bit DAC and 4 x 8-bit ADCs + * Copyright (c) 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 "wiringPi.h" +#include "wiringPiI2C.h" + +#include "pcf8591.h" + + +/* + * myAnalogWrite: + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, UNU int pin, int value) +{ + unsigned char b [2] ; + b [0] = 0x40 ; + b [1] = value & 0xFF ; + write (node->fd, b, 2) ; +} + + +/* + * myAnalogRead: + ********************************************************************************* + */ + +static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) +{ + int x ; + + wiringPiI2CWrite (node->fd, 0x40 | ((pin - node->pinBase) & 3)) ; + + x = wiringPiI2CRead (node->fd) ; // Throw away the first read + x = wiringPiI2CRead (node->fd) ; + + return x ; +} + + +/* + * pcf8591Setup: + * 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 pcf8591Setup (const int pinBase, const int i2cAddress) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) + return FALSE ; + + node = wiringPiNewNode (pinBase, 4) ; + + node->fd = fd ; + node->analogRead = myAnalogRead ; + node->analogWrite = myAnalogWrite ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8591.h b/FlippR-Driver/src/lib/wiringPi/pcf8591.h new file mode 100644 index 0000000..6b44ccf --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/pcf8591.h @@ -0,0 +1,33 @@ +/* + * pcf8591.h: + * Extend wiringPi with the PCF8591 I2C GPIO Analog expander chip + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int pcf8591Setup (const int pinBase, const int i2cAddress) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/piHiPri.c b/FlippR-Driver/src/lib/wiringPi/piHiPri.c new file mode 100644 index 0000000..d2f3b4e --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/piHiPri.c @@ -0,0 +1,51 @@ +/* + * piHiPri: + * Simple way to get your program running at high priority + * with realtime schedulling. + * + * Copyright (c) 2012 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 "wiringPi.h" + + +/* + * piHiPri: + * Attempt to set a high priority schedulling for the running program + ********************************************************************************* + */ + +int piHiPri (const int pri) +{ + struct sched_param sched ; + + memset (&sched, 0, sizeof(sched)) ; + + if (pri > sched_get_priority_max (SCHED_RR)) + sched.sched_priority = sched_get_priority_max (SCHED_RR) ; + else + sched.sched_priority = pri ; + + return sched_setscheduler (0, SCHED_RR, &sched) ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/piThread.c b/FlippR-Driver/src/lib/wiringPi/piThread.c new file mode 100644 index 0000000..b0499be --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/piThread.c @@ -0,0 +1,63 @@ +/* + * piThread.c: + * Provide a simplified interface to pthreads + * + * Copyright (c) 2012 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 "wiringPi.h" + +static pthread_mutex_t piMutexes [4] ; + + + +/* + * piThreadCreate: + * Create and start a thread + ********************************************************************************* + */ + +int piThreadCreate (void *(*fn)(void *)) +{ + pthread_t myThread ; + + return pthread_create (&myThread, NULL, fn, NULL) ; +} + +/* + * piLock: piUnlock: + * Activate/Deactivate a mutex. + * We're keeping things simple here and only tracking 4 mutexes which + * is more than enough for out entry-level pthread programming + ********************************************************************************* + */ + +void piLock (int key) +{ + pthread_mutex_lock (&piMutexes [key]) ; +} + +void piUnlock (int key) +{ + pthread_mutex_unlock (&piMutexes [key]) ; +} + diff --git a/FlippR-Driver/src/lib/wiringPi/pseudoPins.c b/FlippR-Driver/src/lib/wiringPi/pseudoPins.c new file mode 100644 index 0000000..c2bf5e0 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/pseudoPins.h b/FlippR-Driver/src/lib/wiringPi/pseudoPins.h new file mode 100644 index 0000000..bef4660 --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/rht03.c b/FlippR-Driver/src/lib/wiringPi/rht03.c new file mode 100644 index 0000000..1129cfd --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/rht03.h b/FlippR-Driver/src/lib/wiringPi/rht03.h new file mode 100644 index 0000000..9523fbf --- /dev/null +++ b/FlippR-Driver/src/lib/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/FlippR-Driver/src/lib/wiringPi/sn3218.c b/FlippR-Driver/src/lib/wiringPi/sn3218.c new file mode 100644 index 0000000..d9b9113 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/sn3218.c @@ -0,0 +1,75 @@ +/* + * sn3218.c: + * Extend wiringPi with the SN3218 I2C LEd Driver + * 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 "sn3218.h" + +/* + * myAnalogWrite: + * Write analog value on the given pin + ********************************************************************************* + */ + +static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + int fd = node->fd ; + int chan = 0x01 + (pin - node->pinBase) ; + + wiringPiI2CWriteReg8 (fd, chan, value & 0xFF) ; // Value + wiringPiI2CWriteReg8 (fd, 0x16, 0x00) ; // Update +} + +/* + * sn3218Setup: + * Create a new wiringPi device node for an sn3218 on the Pi's + * SPI interface. + ********************************************************************************* + */ + +int sn3218Setup (const int pinBase) +{ + int fd ; + struct wiringPiNodeStruct *node ; + + if ((fd = wiringPiI2CSetup (0x54)) < 0) + return FALSE ; + +// Setup the chip - initialise all 18 LEDs to off + +//wiringPiI2CWriteReg8 (fd, 0x17, 0) ; // Reset + wiringPiI2CWriteReg8 (fd, 0x00, 1) ; // Not Shutdown + wiringPiI2CWriteReg8 (fd, 0x13, 0x3F) ; // Enable LEDs 0- 5 + wiringPiI2CWriteReg8 (fd, 0x14, 0x3F) ; // Enable LEDs 6-11 + wiringPiI2CWriteReg8 (fd, 0x15, 0x3F) ; // Enable LEDs 12-17 + wiringPiI2CWriteReg8 (fd, 0x16, 0x00) ; // Update + + node = wiringPiNewNode (pinBase, 18) ; + + node->fd = fd ; + node->analogWrite = myAnalogWrite ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/sn3218.h b/FlippR-Driver/src/lib/wiringPi/sn3218.h new file mode 100644 index 0000000..580d5f9 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/sn3218.h @@ -0,0 +1,33 @@ +/* + * sn3218.c: + * Extend wiringPi with the SN3218 I2C LED driver board. + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int sn3218Setup (int pinBase) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softPwm.c b/FlippR-Driver/src/lib/wiringPi/softPwm.c new file mode 100644 index 0000000..d99fa00 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softPwm.c @@ -0,0 +1,183 @@ +/* + * softPwm.c: + * 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/ + * + * 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 "wiringPi.h" +#include "softPwm.h" + +// MAX_PINS: +// 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 64 + +// The PWM Frequency is derived from the "pulse time" below. Essentially, +// the frequency is a function of the range and this pulse time. +// The total period will be range * pulse time in µS, so a pulse time +// of 100 and a range of 100 gives a period of 100 * 100 = 10,000 µS +// which is a frequency of 100Hz. +// +// 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 +// 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... + +#define PULSE_TIME 100 + +static volatile int marks [MAX_PINS] ; +static volatile int range [MAX_PINS] ; +static volatile pthread_t threads [MAX_PINS] ; +static volatile int newPin = -1 ; + + +/* + * softPwmThread: + * Thread to do the actual PWM output + ********************************************************************************* + */ + +static void *softPwmThread (void *arg) +{ + int pin, mark, space ; + struct sched_param param ; + + 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 ; + + piHiPri (90) ; + + for (;;) + { + mark = marks [pin] ; + space = range [pin] - mark ; + + if (mark != 0) + digitalWrite (pin, HIGH) ; + delayMicroseconds (mark * 100) ; + + if (space != 0) + digitalWrite (pin, LOW) ; + delayMicroseconds (space * 100) ; + } + + return NULL ; +} + + +/* + * softPwmWrite: + * Write a PWM value to the given pin + ********************************************************************************* + */ + +void softPwmWrite (int pin, int value) +{ + if (pin < MAX_PINS) + { + /**/ if (value < 0) + value = 0 ; + else if (value > range [pin]) + value = range [pin] ; + + marks [pin] = value ; + } +} + + +/* + * softPwmCreate: + * Create a new softPWM thread. + ********************************************************************************* + */ + +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 (pwmRange <= 0) + return -1 ; + + passPin = malloc (sizeof (*passPin)) ; + if (passPin == NULL) + return -1 ; + + digitalWrite (pin, LOW) ; + pinMode (pin, OUTPUT) ; + + marks [pin] = initialValue ; + range [pin] = pwmRange ; + + *passPin = pin ; + newPin = pin ; + res = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ; + + while (newPin != -1) + delay (1) ; + + threads [pin] = myThread ; + + return res ; +} + + +/* + * softPwmStop: + * Stop an existing softPWM thread + ********************************************************************************* + */ + +void softPwmStop (int pin) +{ + if (pin < MAX_PINS) + { + if (range [pin] != 0) + { + pthread_cancel (threads [pin]) ; + pthread_join (threads [pin], NULL) ; + range [pin] = 0 ; + digitalWrite (pin, LOW) ; + } + } +} diff --git a/FlippR-Driver/src/lib/wiringPi/softPwm.h b/FlippR-Driver/src/lib/wiringPi/softPwm.h new file mode 100644 index 0000000..0351da5 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softPwm.h @@ -0,0 +1,35 @@ +/* + * softPwm.h: + * Provide 2 channels of software driven PWM. + * Copyright (c) 2012 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 softPwmCreate (int pin, int value, int range) ; +extern void softPwmWrite (int pin, int value) ; +extern void softPwmStop (int pin) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softServo.c b/FlippR-Driver/src/lib/wiringPi/softServo.c new file mode 100644 index 0000000..9de9f4f --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softServo.c @@ -0,0 +1,211 @@ +/* + * softServo.c: + * Provide N channels of software driven PWM suitable for RC + * servo motors. + * Copyright (c) 2012 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 "wiringPi.h" +#include "softServo.h" + +// RC Servo motors are a bit of an oddity - designed in the days when +// radio control was experimental and people were tryin to make +// things as simple as possible as it was all very expensive... +// +// So... To drive an RC Servo motor, you need to send it a modified PWM +// signal - it needs anything from 1ms to 2ms - with 1ms meaning +// to move the server fully left, and 2ms meaning to move it fully +// right. Then you need a long gap before sending the next pulse. +// The reason for this is that you send a multiplexed stream of these +// pulses up the radio signal into the reciever which de-multiplexes +// them into the signals for each individual servo. Typically there +// might be 8 channels, so you need at least 8 "slots" of 2mS pulses +// meaning the entire frame must fit into a 16mS slot - which would +// then be repeated... +// +// In practice we have a total slot width of about 20mS - so we're sending 50 +// updates per second to each servo. +// +// In this code, we don't need to be too fussy about the gap as we're not doing +// the multipexing, but it does need to be at least 10mS, and preferably 16 +// from what I've been able to determine. + +// WARNING: +// This code is really experimental. It was written in response to some people +// asking for a servo driver, however while it works, there is too much +// jitter to successfully drive a small servo - I have tried it with a micro +// servo and it worked, but the servo ran hot due to the jitter in the signal +// being sent to it. +// +// If you want servo control for the Pi, then use the servoblaster kernel +// module. + +#define MAX_SERVOS 8 + +static int pinMap [MAX_SERVOS] ; // Keep track of our pins +static int pulseWidth [MAX_SERVOS] ; // microseconds + + +/* + * softServoThread: + * Thread to do the actual Servo PWM output + ********************************************************************************* + */ + +static PI_THREAD (softServoThread) +{ + register int i, j, k, m, tmp ; + int lastDelay, pin, servo ; + + int myDelays [MAX_SERVOS] ; + int myPins [MAX_SERVOS] ; + + struct timeval tNow, tStart, tPeriod, tGap, tTotal ; + struct timespec tNs ; + + tTotal.tv_sec = 0 ; + tTotal.tv_usec = 8000 ; + + piHiPri (50) ; + + for (;;) + { + gettimeofday (&tStart, NULL) ; + + memcpy (myDelays, pulseWidth, sizeof (myDelays)) ; + memcpy (myPins, pinMap, sizeof (myPins)) ; + +// Sort the delays (& pins), shortest first + + for (m = MAX_SERVOS / 2 ; m > 0 ; m /= 2 ) + for (j = m ; j < MAX_SERVOS ; ++j) + for (i = j - m ; i >= 0 ; i -= m) + { + k = i + m ; + if (myDelays [k] >= myDelays [i]) + break ; + else // Swap + { + tmp = myDelays [i] ; myDelays [i] = myDelays [k] ; myDelays [k] = tmp ; + tmp = myPins [i] ; myPins [i] = myPins [k] ; myPins [k] = tmp ; + } + } + +// All on + + lastDelay = 0 ; + for (servo = 0 ; servo < MAX_SERVOS ; ++servo) + { + if ((pin = myPins [servo]) == -1) + continue ; + + digitalWrite (pin, HIGH) ; + myDelays [servo] = myDelays [servo] - lastDelay ; + lastDelay += myDelays [servo] ; + } + +// Now loop, turning them all off as required + + for (servo = 0 ; servo < MAX_SERVOS ; ++servo) + { + if ((pin = myPins [servo]) == -1) + continue ; + + delayMicroseconds (myDelays [servo]) ; + digitalWrite (pin, LOW) ; + } + +// Wait until the end of an 8mS time-slot + + gettimeofday (&tNow, NULL) ; + timersub (&tNow, &tStart, &tPeriod) ; + timersub (&tTotal, &tPeriod, &tGap) ; + tNs.tv_sec = tGap.tv_sec ; + tNs.tv_nsec = tGap.tv_usec * 1000 ; + nanosleep (&tNs, NULL) ; + } + + return NULL ; +} + + +/* + * softServoWrite: + * Write a Servo value to the given pin + ********************************************************************************* + */ + +void softServoWrite (int servoPin, int value) +{ + int servo ; + + servoPin &= 63 ; + + /**/ if (value < -250) + value = -250 ; + else if (value > 1250) + value = 1250 ; + + for (servo = 0 ; servo < MAX_SERVOS ; ++servo) + if (pinMap [servo] == servoPin) + pulseWidth [servo] = value + 1000 ; // uS +} + + +/* + * softServoSetup: + * Setup the software servo system + ********************************************************************************* + */ + +int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7) +{ + int servo ; + + if (p0 != -1) { pinMode (p0, OUTPUT) ; digitalWrite (p0, LOW) ; } + if (p1 != -1) { pinMode (p1, OUTPUT) ; digitalWrite (p1, LOW) ; } + if (p2 != -1) { pinMode (p2, OUTPUT) ; digitalWrite (p2, LOW) ; } + if (p3 != -1) { pinMode (p3, OUTPUT) ; digitalWrite (p3, LOW) ; } + if (p4 != -1) { pinMode (p4, OUTPUT) ; digitalWrite (p4, LOW) ; } + if (p5 != -1) { pinMode (p5, OUTPUT) ; digitalWrite (p5, LOW) ; } + if (p6 != -1) { pinMode (p6, OUTPUT) ; digitalWrite (p6, LOW) ; } + if (p7 != -1) { pinMode (p7, OUTPUT) ; digitalWrite (p7, LOW) ; } + + pinMap [0] = p0 ; + pinMap [1] = p1 ; + pinMap [2] = p2 ; + pinMap [3] = p3 ; + pinMap [4] = p4 ; + pinMap [5] = p5 ; + pinMap [6] = p6 ; + pinMap [7] = p7 ; + + for (servo = 0 ; servo < MAX_SERVOS ; ++servo) + pulseWidth [servo] = 1500 ; // Mid point + + return piThreadCreate (softServoThread) ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/softServo.h b/FlippR-Driver/src/lib/wiringPi/softServo.h new file mode 100644 index 0000000..794cf55 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softServo.h @@ -0,0 +1,35 @@ +/* + * softServo.h: + * Provide N channels of software driven PWM suitable for RC + * servo motors. + * Copyright (c) 2012 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 void softServoWrite (int pin, int value) ; +extern int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softTone.c b/FlippR-Driver/src/lib/wiringPi/softTone.c new file mode 100644 index 0000000..e2fb737 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softTone.c @@ -0,0 +1,150 @@ +/* + * softTone.c: + * For that authentic retro sound... + * Er... A little experiment to produce tones out of a Pi using + * one (or 2) GPIO pins and a piezeo "speaker" element. + * (Or a high impedance speaker, but don'y blame me if you blow-up + * the GPIO pins!) + * Copyright (c) 2012 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 "wiringPi.h" +#include "softTone.h" + +#define MAX_PINS 64 + +#define PULSE_TIME 100 + +static int freqs [MAX_PINS] ; +static pthread_t threads [MAX_PINS] ; + +static int newPin = -1 ; + + +/* + * softToneThread: + * Thread to do the actual PWM output + ********************************************************************************* + */ + +static PI_THREAD (softToneThread) +{ + int pin, freq, halfPeriod ; + struct sched_param param ; + + param.sched_priority = sched_get_priority_max (SCHED_RR) ; + pthread_setschedparam (pthread_self (), SCHED_RR, ¶m) ; + + pin = newPin ; + newPin = -1 ; + + piHiPri (50) ; + + for (;;) + { + freq = freqs [pin] ; + if (freq == 0) + delay (1) ; + else + { + halfPeriod = 500000 / freq ; + + digitalWrite (pin, HIGH) ; + delayMicroseconds (halfPeriod) ; + + digitalWrite (pin, LOW) ; + delayMicroseconds (halfPeriod) ; + } + } + + return NULL ; +} + + +/* + * softToneWrite: + * Write a frequency value to the given pin + ********************************************************************************* + */ + +void softToneWrite (int pin, int freq) +{ + pin &= 63 ; + + /**/ if (freq < 0) + freq = 0 ; + else if (freq > 5000) // Max 5KHz + freq = 5000 ; + + freqs [pin] = freq ; +} + + +/* + * softToneCreate: + * Create a new tone thread. + ********************************************************************************* + */ + +int softToneCreate (int pin) +{ + int res ; + pthread_t myThread ; + + pinMode (pin, OUTPUT) ; + digitalWrite (pin, LOW) ; + + if (threads [pin] != 0) + return -1 ; + + freqs [pin] = 0 ; + + newPin = pin ; + res = pthread_create (&myThread, NULL, softToneThread, NULL) ; + + while (newPin != -1) + delay (1) ; + + threads [pin] = myThread ; + + return res ; +} + + +/* + * softToneStop: + * Stop an existing softTone thread + ********************************************************************************* + */ + +void softToneStop (int pin) +{ + if (threads [pin] != 0) + { + pthread_cancel (threads [pin]) ; + pthread_join (threads [pin], NULL) ; + threads [pin] = 0 ; + digitalWrite (pin, LOW) ; + } +} diff --git a/FlippR-Driver/src/lib/wiringPi/softTone.h b/FlippR-Driver/src/lib/wiringPi/softTone.h new file mode 100644 index 0000000..a93c5af --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/softTone.h @@ -0,0 +1,39 @@ +/* + * softTone.c: + * For that authentic retro sound... + * Er... A little experiment to produce tones out of a Pi using + * one (or 2) GPIO pins and a piezeo "speaker" element. + * (Or a high impedance speaker, but don'y blame me if you blow-up + * the GPIO pins!) + * Copyright (c) 2012 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 softToneCreate (int pin) ; +extern void softToneStop (int pin) ; +extern void softToneWrite (int pin, int freq) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/sr595.c b/FlippR-Driver/src/lib/wiringPi/sr595.c new file mode 100644 index 0000000..8280618 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/sr595.c @@ -0,0 +1,109 @@ +/* + * sr595.c: + * Extend wiringPi with the 74x595 shift register as a GPIO + * expander chip. + * Note that the code can cope with a number of 595's + * daisy-chained together - up to 4 for now as we're storing + * the output "register" in a single unsigned int. + * + * Copyright (c) 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 "wiringPi.h" + +#include "sr595.h" + + +/* + * myDigitalWrite: + ********************************************************************************* + */ + +static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) +{ + unsigned int mask ; + int dataPin, clockPin, latchPin ; + int bit, bits, output ; + + pin -= node->pinBase ; // Normalise pin number + bits = node->pinMax - node->pinBase + 1 ; // ie. number of clock pulses + dataPin = node->data0 ; + clockPin = node->data1 ; + latchPin = node->data2 ; + output = node->data3 ; + + mask = 1 << pin ; + + if (value == LOW) + output &= (~mask) ; + else + output |= mask ; + + node->data3 = output ; + +// A low -> high latch transition copies the latch to the output pins + + digitalWrite (latchPin, LOW) ; delayMicroseconds (1) ; + for (bit = bits - 1 ; bit >= 0 ; --bit) + { + digitalWrite (dataPin, output & (1 << bit)) ; + + digitalWrite (clockPin, HIGH) ; delayMicroseconds (1) ; + digitalWrite (clockPin, LOW) ; delayMicroseconds (1) ; + } + digitalWrite (latchPin, HIGH) ; delayMicroseconds (1) ; +} + + +/* + * sr595Setup: + * Create a new instance of a 74x595 shift register GPIO expander. + ********************************************************************************* + */ + +int sr595Setup (const int pinBase, const int numPins, + const int dataPin, const int clockPin, const int latchPin) +{ + struct wiringPiNodeStruct *node ; + + node = wiringPiNewNode (pinBase, numPins) ; + + node->data0 = dataPin ; + node->data1 = clockPin ; + node->data2 = latchPin ; + node->data3 = 0 ; // Output register + node->digitalWrite = myDigitalWrite ; + +// Initialise the underlying hardware + + digitalWrite (dataPin, LOW) ; + digitalWrite (clockPin, LOW) ; + digitalWrite (latchPin, HIGH) ; + + pinMode (dataPin, OUTPUT) ; + pinMode (clockPin, OUTPUT) ; + pinMode (latchPin, OUTPUT) ; + + return TRUE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/sr595.h b/FlippR-Driver/src/lib/wiringPi/sr595.h new file mode 100644 index 0000000..4a26dc7 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/sr595.h @@ -0,0 +1,34 @@ +/* + * sr595.h: + * Extend wiringPi with the 74x595 shift registers. + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int sr595Setup (const int pinBase, const int numPins, + const int dataPin, const int clockPin, const int latchPin) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPi.c b/FlippR-Driver/src/lib/wiringPi/wiringPi.c new file mode 100644 index 0000000..bd1a369 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPi.c @@ -0,0 +1,2373 @@ +/* + * wiringPi: + * Arduino look-a-like Wiring library for the Raspberry Pi + * Copyright (c) 2012-2017 Gordon Henderson + * Additional code for pwmSetClock by Chris Hall + * + * Thanks to code samples from Gert Jan van Loo and the + * BCM2835 ARM Peripherals manual, however it's missing + * the clock section /grr/mutter/ + *********************************************************************** + * 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 . + *********************************************************************** + */ + +// Revisions: +// 19 Jul 2012: +// Moved to the LGPL +// Added an abstraction layer to the main routines to save a tiny +// bit of run-time and make the clode a little cleaner (if a little +// larger) +// Added waitForInterrupt code +// Added piHiPri code +// +// 9 Jul 2012: +// Added in support to use the /sys/class/gpio interface. +// 2 Jul 2012: +// Fixed a few more bugs to do with range-checking when in GPIO mode. +// 11 Jun 2012: +// Fixed some typos. +// Added c++ support for the .h file +// Added a new function to allow for using my "pin" numbers, or native +// GPIO pin numbers. +// Removed my busy-loop delay and replaced it with a call to delayMicroseconds +// +// 02 May 2012: +// Added in the 2 UART pins +// Change maxPins to numPins to more accurately reflect purpose + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "softPwm.h" +#include "softTone.h" + +#include "wiringPi.h" +#include "../version.h" + +// Environment Variables + +#define ENV_DEBUG "WIRINGPI_DEBUG" +#define ENV_CODES "WIRINGPI_CODES" +#define ENV_GPIOMEM "WIRINGPI_GPIOMEM" + + +// Extend wiringPi with other pin-based devices and keep track of +// them in this structure + +struct wiringPiNodeStruct *wiringPiNodes = NULL ; + +// BCM Magic + +#define BCM_PASSWORD 0x5A000000 + + +// The BCM2835 has 54 GPIO pins. +// BCM2835 data sheet, Page 90 onwards. +// There are 6 control registers, each control the functions of a block +// of 10 pins. +// Each control register has 10 sets of 3 bits per GPIO pin - the ALT values +// +// 000 = GPIO Pin X is an input +// 001 = GPIO Pin X is an output +// 100 = GPIO Pin X takes alternate function 0 +// 101 = GPIO Pin X takes alternate function 1 +// 110 = GPIO Pin X takes alternate function 2 +// 111 = GPIO Pin X takes alternate function 3 +// 011 = GPIO Pin X takes alternate function 4 +// 010 = GPIO Pin X takes alternate function 5 +// +// So the 3 bits for port X are: +// X / 10 + ((X % 10) * 3) + +// Port function select bits + +#define FSEL_INPT 0b000 +#define FSEL_OUTP 0b001 +#define FSEL_ALT0 0b100 +#define FSEL_ALT1 0b101 +#define FSEL_ALT2 0b110 +#define FSEL_ALT3 0b111 +#define FSEL_ALT4 0b011 +#define FSEL_ALT5 0b010 + +// Access from ARM Running Linux +// Taken from Gert/Doms code. Some of this is not in the manual +// that I can find )-: +// +// Updates in September 2015 - all now static variables (and apologies for the caps) +// due to the Pi v2, v3, etc. and the new /dev/gpiomem interface + +static volatile unsigned int GPIO_PADS ; +static volatile unsigned int GPIO_CLOCK_BASE ; +static volatile unsigned int GPIO_BASE ; +static volatile unsigned int GPIO_TIMER ; +static volatile unsigned int GPIO_PWM ; + +#define PAGE_SIZE (4*1024) +#define BLOCK_SIZE (4*1024) + +// PWM +// Word offsets into the PWM control region + +#define PWM_CONTROL 0 +#define PWM_STATUS 1 +#define PWM0_RANGE 4 +#define PWM0_DATA 5 +#define PWM1_RANGE 8 +#define PWM1_DATA 9 + +// Clock regsiter offsets + +#define PWMCLK_CNTL 40 +#define PWMCLK_DIV 41 + +#define PWM0_MS_MODE 0x0080 // Run in MS mode +#define PWM0_USEFIFO 0x0020 // Data from FIFO +#define PWM0_REVPOLAR 0x0010 // Reverse polarity +#define PWM0_OFFSTATE 0x0008 // Ouput Off state +#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty +#define PWM0_SERIAL 0x0002 // Run in serial mode +#define PWM0_ENABLE 0x0001 // Channel Enable + +#define PWM1_MS_MODE 0x8000 // Run in MS mode +#define PWM1_USEFIFO 0x2000 // Data from FIFO +#define PWM1_REVPOLAR 0x1000 // Reverse polarity +#define PWM1_OFFSTATE 0x0800 // Ouput Off state +#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty +#define PWM1_SERIAL 0x0200 // Run in serial mode +#define PWM1_ENABLE 0x0100 // Channel Enable + +// Timer +// Word offsets + +#define TIMER_LOAD (0x400 >> 2) +#define TIMER_VALUE (0x404 >> 2) +#define TIMER_CONTROL (0x408 >> 2) +#define TIMER_IRQ_CLR (0x40C >> 2) +#define TIMER_IRQ_RAW (0x410 >> 2) +#define TIMER_IRQ_MASK (0x414 >> 2) +#define TIMER_RELOAD (0x418 >> 2) +#define TIMER_PRE_DIV (0x41C >> 2) +#define TIMER_COUNTER (0x420 >> 2) + +// 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 ; + +#ifdef USE_TIMER +static volatile uint32_t *timer ; +static volatile uint32_t *timerIrqRaw ; +#endif + +// Data for use with the boardId functions. +// The order of entries here to correspond with the PI_MODEL_X +// and PI_VERSION_X defines in wiringPi.h +// Only intended for the gpio command - use at your own risk! + +// 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] = +{ + "Model A", // 0 + "Model B", // 1 + "Model A+", // 2 + "Model B+", // 3 + "Pi 2", // 4 + "Alpha", // 5 + "CM", // 6 + "Unknown07", // 07 + "Pi 3", // 08 + "Pi Zero", // 09 + "CM3", // 10 + "Unknown11", // 11 + "Pi Zero-W", // 12 + "Unknown13", // 13 + "Unknown14", // 14 + "Unknown15", // 15 +} ; + +const char *piRevisionNames [16] = +{ + "00", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "10", + "11", + "12", + "13", + "14", + "15", +} ; + +const char *piMakerNames [16] = +{ + "Sony", // 0 + "Egoman", // 1 + "Embest", // 2 + "Unknown", // 3 + "Embest", // 4 + "Unknown05", // 5 + "Unknown06", // 6 + "Unknown07", // 7 + "Unknown08", // 8 + "Unknown09", // 9 + "Unknown10", // 10 + "Unknown11", // 11 + "Unknown12", // 12 + "Unknown13", // 13 + "Unknown14", // 14 + "Unknown15", // 15 +} ; + +const int piMemorySize [8] = +{ + 256, // 0 + 512, // 1 + 1024, // 2 + 0, // 3 + 0, // 4 + 0, // 5 + 0, // 6 + 0, // 7 +} ; + +// Time for easy calculations + +static uint64_t epochMilli, epochMicro ; + +// Misc + +static int wiringPiMode = WPI_MODE_UNINITIALISED ; +static volatile int pinPass = -1 ; +static pthread_mutex_t pinMutex ; + +// Debugging & Return codes + +int wiringPiDebug = FALSE ; +int wiringPiReturnCodes = FALSE ; + +// Use /dev/gpiomem ? + +int wiringPiTryGpioMem = FALSE ; + +// sysFds: +// Map a file descriptor from the /sys/class/gpio/gpioX/value + +static int sysFds [64] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +} ; + +// ISR Data + +static void (*isrFunctions [64])(void) ; + + +// Doing it the Arduino way with lookup tables... +// Yes, it's probably more innefficient than all the bit-twidling, but it +// does tend to make it all a bit clearer. At least to me! + +// pinToGpio: +// Take a Wiring pin (0 through X) and re-map it to the BCM_GPIO pin +// Cope for 3 different board revisions here. + +static int *pinToGpio ; + +// Revision 1, 1.1: + +static int pinToGpioR1 [64] = +{ + 17, 18, 21, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 + 0, 1, // I2C - SDA1, SCL1 wpi 8 - 9 + 8, 7, // SPI - CE1, CE0 wpi 10 - 11 + 10, 9, 11, // SPI - MOSI, MISO, SCLK wpi 12 - 14 + 14, 15, // UART - Tx, Rx wpi 15 - 16 + +// Padding: + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 31 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 +} ; + +// Revision 2: + +static int pinToGpioR2 [64] = +{ + 17, 18, 27, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 + 2, 3, // I2C - SDA0, SCL0 wpi 8 - 9 + 8, 7, // SPI - CE1, CE0 wpi 10 - 11 + 10, 9, 11, // SPI - MOSI, MISO, SCLK wpi 12 - 14 + 14, 15, // UART - Tx, Rx wpi 15 - 16 + 28, 29, 30, 31, // Rev 2: New GPIOs 8 though 11 wpi 17 - 20 + 5, 6, 13, 19, 26, // B+ wpi 21, 22, 23, 24, 25 + 12, 16, 20, 21, // B+ wpi 26, 27, 28, 29 + 0, 1, // B+ wpi 30, 31 + +// Padding: + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 +} ; + + +// physToGpio: +// Take a physical pin (1 through 26) and re-map it to the BCM_GPIO pin +// Cope for 2 different board revisions here. +// Also add in the P5 connector, so the P5 pins are 3,4,5,6, so 53,54,55,56 + +static int *physToGpio ; + +static int physToGpioR1 [64] = +{ + -1, // 0 + -1, -1, // 1, 2 + 0, -1, + 1, -1, + 4, 14, + -1, 15, + 17, 18, + 21, -1, + 22, 23, + -1, 24, + 10, -1, + 9, 25, + 11, 8, + -1, 7, // 25, 26 + + -1, -1, -1, -1, -1, // ... 31 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 +} ; + +static int physToGpioR2 [64] = +{ + -1, // 0 + -1, -1, // 1, 2 + 2, -1, + 3, -1, + 4, 14, + -1, 15, + 17, 18, + 27, -1, + 22, 23, + -1, 24, + 10, -1, + 9, 25, + 11, 8, + -1, 7, // 25, 26 + +// B+ + + 0, 1, + 5, -1, + 6, 12, + 13, -1, + 19, 16, + 26, 20, + -1, 21, + +// the P5 connector on the Rev 2 boards: + + -1, -1, + -1, -1, + -1, -1, + -1, -1, + -1, -1, + 28, 29, + 30, 31, + -1, -1, + -1, -1, + -1, -1, + -1, -1, +} ; + +// gpioToGPFSEL: +// Map a BCM_GPIO pin to it's Function Selection +// control port. (GPFSEL 0-5) +// Groups of 10 - 3 bits per Function - 30 bits per port + +static uint8_t gpioToGPFSEL [] = +{ + 0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5, +} ; + + +// gpioToShift +// Define the shift up for the 3 bits per pin in each GPFSEL port + +static uint8_t gpioToShift [] = +{ + 0,3,6,9,12,15,18,21,24,27, + 0,3,6,9,12,15,18,21,24,27, + 0,3,6,9,12,15,18,21,24,27, + 0,3,6,9,12,15,18,21,24,27, + 0,3,6,9,12,15,18,21,24,27, + 0,3,6,9,12,15,18,21,24,27, +} ; + + +// gpioToGPSET: +// (Word) offset to the GPIO Set registers for each GPIO pin + +static uint8_t gpioToGPSET [] = +{ + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, +} ; + +// gpioToGPCLR: +// (Word) offset to the GPIO Clear registers for each GPIO pin + +static uint8_t gpioToGPCLR [] = +{ + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +} ; + + +// gpioToGPLEV: +// (Word) offset to the GPIO Input level registers for each GPIO pin + +static uint8_t gpioToGPLEV [] = +{ + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, +} ; + + +#ifdef notYetReady +// gpioToEDS +// (Word) offset to the Event Detect Status + +static uint8_t gpioToEDS [] = +{ + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +} ; + +// gpioToREN +// (Word) offset to the Rising edge ENable register + +static uint8_t gpioToREN [] = +{ + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, +} ; + +// gpioToFEN +// (Word) offset to the Falling edgde ENable register + +static uint8_t gpioToFEN [] = +{ + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, +} ; +#endif + + +// GPPUD: +// GPIO Pin pull up/down register + +#define GPPUD 37 + +// gpioToPUDCLK +// (Word) offset to the Pull Up Down Clock regsiter + +static uint8_t gpioToPUDCLK [] = +{ + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, +} ; + + +// gpioToPwmALT +// the ALT value to put a GPIO pin into PWM mode + +static uint8_t gpioToPwmALT [] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7 + 0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, 0, 0, // 8 -> 15 + 0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, 0, 0, // 16 -> 23 + 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 + 0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39 + FSEL_ALT0, FSEL_ALT0, 0, 0, 0, FSEL_ALT0, 0, 0, // 40 -> 47 + 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 + 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 +} ; + + +// gpioToPwmPort +// The port value to put a GPIO pin into PWM mode + +static uint8_t gpioToPwmPort [] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7 + 0, 0, 0, 0, PWM0_DATA, PWM1_DATA, 0, 0, // 8 -> 15 + 0, 0, PWM0_DATA, PWM1_DATA, 0, 0, 0, 0, // 16 -> 23 + 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 + 0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39 + PWM0_DATA, PWM1_DATA, 0, 0, 0, PWM1_DATA, 0, 0, // 40 -> 47 + 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 + 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 + +} ; + +// gpioToGpClkALT: +// ALT value to put a GPIO pin into GP Clock mode. +// On the Pi we can really only use BCM_GPIO_4 and BCM_GPIO_21 +// for clocks 0 and 1 respectively, however I'll include the full +// list for completeness - maybe one day... + +#define GPIO_CLOCK_SOURCE 1 + +// gpioToGpClkALT0: + +static uint8_t gpioToGpClkALT0 [] = +{ + 0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, // 0 -> 7 + 0, 0, 0, 0, 0, 0, 0, 0, // 8 -> 15 + 0, 0, 0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, // 16 -> 23 + 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 + FSEL_ALT0, 0, FSEL_ALT0, 0, 0, 0, 0, 0, // 32 -> 39 + 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, 0, 0, // 40 -> 47 + 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 + 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 +} ; + +// gpioToClk: +// (word) Offsets to the clock Control and Divisor register + +static uint8_t gpioToClkCon [] = +{ + -1, -1, -1, -1, 28, 30, 32, -1, // 0 -> 7 + -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 + -1, -1, -1, -1, 28, 30, -1, -1, // 16 -> 23 + -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 + 28, -1, 28, -1, -1, -1, -1, -1, // 32 -> 39 + -1, -1, 28, 30, 28, -1, -1, -1, // 40 -> 47 + -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 + -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 +} ; + +static uint8_t gpioToClkDiv [] = +{ + -1, -1, -1, -1, 29, 31, 33, -1, // 0 -> 7 + -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 + -1, -1, -1, -1, 29, 31, -1, -1, // 16 -> 23 + -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 + 29, -1, 29, -1, -1, -1, -1, -1, // 32 -> 39 + -1, -1, 29, 31, 29, -1, -1, -1, // 40 -> 47 + -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 + -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 +} ; + + +/* + * Functions + ********************************************************************************* + */ + + +/* + * wiringPiFailure: + * Fail. Or not. + ********************************************************************************* + */ + +int wiringPiFailure (int fatal, const char *message, ...) +{ + va_list argp ; + char buffer [1024] ; + + if (!fatal && wiringPiReturnCodes) + return -1 ; + + va_start (argp, message) ; + vsnprintf (buffer, 1023, message, argp) ; + va_end (argp) ; + + fprintf (stderr, "%s", buffer) ; + exit (EXIT_FAILURE) ; + + return 0 ; +} + + +/* + * 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 + * really interested in here. The very earliest Pi's and the + * ones that came after that which switched some pins .... + * + * Revision 1 really means the early Model A and B's. + * Revision 2 is everything else - it covers the B, B+ and CM. + * ... and the Pi 2 - which is a B+ ++ ... + * ... and the Pi 0 - which is an A+ ... + * + * The main difference between the revision 1 and 2 system that I use here + * is the mapping of the GPIO pins. From revision 2, the Pi Foundation changed + * 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 piGpioLayoutOops (const char *why) +{ + fprintf (stderr, "Oops: Unable to determine board revision from /proc/cpuinfo\n") ; + fprintf (stderr, " -> %s\n", why) ; + 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 piGpioLayout (void) +{ + FILE *cpuFd ; + char line [120] ; + char *c ; + static int gpioLayout = -1 ; + + if (gpioLayout != -1) // No point checking twice + return gpioLayout ; + + if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) + 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 +// they can't get it to work on weirdFruitPi boards... + + while (fgets (line, 120, cpuFd) != NULL) + if (strncmp (line, "Hardware", 8) == 0) + break ; + + if (strncmp (line, "Hardware", 8) != 0) + piGpioLayoutOops ("No \"Hardware\" line") ; + + if (wiringPiDebug) + printf ("piGpioLayout: Hardware: %s\n", line) ; + +// See if it's BCM2708 or BCM2709 or the new BCM2835. + +// 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. + + 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, 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) ; + } + +// Right - 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. + +// Isolate the Revision line + + rewind (cpuFd) ; + while (fgets (line, 120, cpuFd) != NULL) + if (strncmp (line, "Revision", 8) == 0) + break ; + + fclose (cpuFd) ; + + if (strncmp (line, "Revision", 8) != 0) + piGpioLayoutOops ("No \"Revision\" line") ; + +// Chomp trailing CR/NL + + for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) + *c = 0 ; + + if (wiringPiDebug) + printf ("piGpioLayout: Revision string: %s\n", line) ; + +// Scan to the first character of the revision number + + for (c = line ; *c ; ++c) + if (*c == ':') + break ; + + if (*c != ':') + piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; + +// Chomp spaces + + ++c ; + while (isspace (*c)) + ++c ; + + if (!isxdigit (*c)) + piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; + +// Make sure its long enough + + if (strlen (c) < 4) + piGpioLayoutOops ("Bogus revision line (too small)") ; + +// Isolate last 4 characters: (in-case of overvolting or new encoding scheme) + + c = c + strlen (c) - 4 ; + + if (wiringPiDebug) + printf ("piGpioLayout: last4Chars are: \"%s\"\n", c) ; + + if ( (strcmp (c, "0002") == 0) || (strcmp (c, "0003") == 0)) + gpioLayout = 1 ; + else + gpioLayout = 2 ; // Covers everything else from the B revision 2 to the B+, the Pi v2, v3, zero and CM's. + + if (wiringPiDebug) + printf ("piGpioLayoutOops: Returning revision: %d\n", gpioLayout) ; + + return gpioLayout ; +} + +/* + * piBoardRev: + * Deprecated, but does the same as piGpioLayout + ********************************************************************************* + */ + +int piBoardRev (void) +{ + return piGpioLayout () ; +} + + + +/* + * piBoardId: + * Return the real details of the board we have. + * + * This is undocumented and really only intended for the GPIO command. + * Use at your own risk! + * + * Seems there are some boards with 0000 in them (mistake in manufacture) + * So the distinction between boards that I can see is: + * + * 0000 - Error + * 0001 - Not used + * + * Original Pi boards: + * 0002 - Model B, Rev 1, 256MB, Egoman + * 0003 - Model B, Rev 1.1, 256MB, Egoman, Fuses/D14 removed. + * + * Newer Pi's with remapped GPIO: + * 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 + * 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 + * + * The Pi compute module has an revision of 0011 or 0014 - since we only + * check the last digit, then it's 1, therefore it'll default to not 2 or + * 3 for a Rev 1, so will appear as a Rev 2. This is fine for the most part, but + * we'll properly detect the Compute Module later and adjust accordingly. + * + * And then things changed with the introduction of the v2... + * + * For Pi v2 and subsequent models - e.g. the Zero: + * + * [USER:8] [NEW:1] [MEMSIZE:3] [MANUFACTURER:4] [PROCESSOR:4] [TYPE:8] [REV:4] + * NEW 23: will be 1 for the new scheme, 0 for the old scheme + * MEMSIZE 20: 0=256M 1=512M 2=1G + * MANUFACTURER 16: 0=SONY 1=EGOMAN 2=EMBEST + * PROCESSOR 12: 0=2835 1=2836 + * TYPE 04: 0=MODELA 1=MODELB 2=MODELA+ 3=MODELB+ 4=Pi2 MODEL B 5=ALPHA 6=CM + * REV 00: 0=REV0 1=REV1 2=REV2 + ********************************************************************************* + */ + +void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) +{ + FILE *cpuFd ; + char line [120] ; + char *c ; + unsigned int revision ; + int bRev, bType, bProc, bMfg, bMem, bWarranty ; + +// Will deal with the properly later on - for now, lets just get it going... +// unsigned int modelNum ; + + (void)piGpioLayout () ; // Call this first to make sure all's OK. Don't care about the result. + + if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) + piGpioLayoutOops ("Unable to open /proc/cpuinfo") ; + + while (fgets (line, 120, cpuFd) != NULL) + if (strncmp (line, "Revision", 8) == 0) + break ; + + fclose (cpuFd) ; + + if (strncmp (line, "Revision", 8) != 0) + piGpioLayoutOops ("No \"Revision\" line") ; + +// Chomp trailing CR/NL + + for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) + *c = 0 ; + + if (wiringPiDebug) + printf ("piBoardId: Revision string: %s\n", line) ; + +// Need to work out if it's using the new or old encoding scheme: + +// Scan to the first character of the revision number + + for (c = line ; *c ; ++c) + if (*c == ':') + break ; + + if (*c != ':') + piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; + +// Chomp spaces + + ++c ; + while (isspace (*c)) + ++c ; + + if (!isxdigit (*c)) + piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; + + revision = (unsigned int)strtol (c, NULL, 16) ; // Hex number with no leading 0x + +// Check for new way: + + if ((revision & (1 << 23)) != 0) // New way + { + if (wiringPiDebug) + printf ("piBoardId: New Way: revision is: 0x%08X\n", revision) ; + + bRev = (revision & (0x0F << 0)) >> 0 ; + bType = (revision & (0xFF << 4)) >> 4 ; + bProc = (revision & (0x0F << 12)) >> 12 ; // Not used for now. + bMfg = (revision & (0x0F << 16)) >> 16 ; + bMem = (revision & (0x07 << 20)) >> 20 ; + bWarranty = (revision & (0x03 << 24)) != 0 ; + + *model = bType ; + *rev = bRev ; + *mem = bMem ; + *maker = bMfg ; + *warranty = bWarranty ; + + if (wiringPiDebug) + printf ("piBoardId: rev: %d, type: %d, proc: %d, mfg: %d, mem: %d, warranty: %d\n", + bRev, bType, bProc, bMfg, bMem, bWarranty) ; + } + else // Old way + { + if (wiringPiDebug) + printf ("piBoardId: Old Way: revision is: %s\n", c) ; + + if (!isdigit (*c)) + piGpioLayoutOops ("Bogus \"Revision\" line (no digit at start of revision)") ; + +// Make sure its long enough + + if (strlen (c) < 4) + piGpioLayoutOops ("Bogus \"Revision\" line (not long enough)") ; + +// If longer than 4, we'll assume it's been overvolted + + *warranty = strlen (c) > 4 ; + +// Extract last 4 characters: + + c = c + strlen (c) - 4 ; + +// Fill out the replys as appropriate + + /**/ 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_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, "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 ; } + } +} + + + +/* + * wpiPinToGpio: + * Translate a wiringPi Pin number to native GPIO pin number. + * Provided for external support. + ********************************************************************************* + */ + +int wpiPinToGpio (int wpiPin) +{ + return pinToGpio [wpiPin & 63] ; +} + + +/* + * physPinToGpio: + * Translate a physical Pin number to native GPIO pin number. + * Provided for external support. + ********************************************************************************* + */ + +int physPinToGpio (int physPin) +{ + return physToGpio [physPin & 63] ; +} + + +/* + * setPadDrive: + * Set the PAD driver value + ********************************************************************************* + */ + +void setPadDrive (int group, int value) +{ + uint32_t wrVal ; + + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if ((group < 0) || (group > 2)) + return ; + + wrVal = BCM_PASSWORD | 0x18 | (value & 7) ; + *(pads + group + 11) = wrVal ; + + if (wiringPiDebug) + { + printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ; + printf ("Read : %08X\n", *(pads + group + 11)) ; + } + } +} + + +/* + * getAlt: + * Returns the ALT bits for a given port. Only really of-use + * for the gpio readall command (I think) + ********************************************************************************* + */ + +int getAlt (int pin) +{ + int fSel, shift, alt ; + + pin &= 63 ; + + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return 0 ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + alt = (*(gpio + fSel) >> shift) & 7 ; + + return alt ; +} + + +/* + * pwmSetMode: + * Select the native "balanced" mode, or standard mark:space mode + ********************************************************************************* + */ + +void pwmSetMode (int mode) +{ + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if (mode == PWM_MODE_MS) + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; + else + *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; + } +} + + +/* + * pwmSetRange: + * Set the PWM range register. We set both range registers to the same + * value. If you want different in your own code, then write your own. + ********************************************************************************* + */ + +void pwmSetRange (unsigned int range) +{ + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; + *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; + } +} + + +/* + * pwmSetClock: + * Set/Change the PWM clock. Originally my code, but changed + * (for the better!) by Chris Hall, + * after further study of the manual and testing with a 'scope + ********************************************************************************* + */ + +void pwmSetClock (int divisor) +{ + uint32_t pwm_control ; + divisor &= 4095 ; + + if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) + { + if (wiringPiDebug) + printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; + + pwm_control = *(pwm + PWM_CONTROL) ; // preserve PWM_CONTROL + +// We need to stop PWM prior to stopping PWM clock in MS mode otherwise BUSY +// stays high. + + *(pwm + PWM_CONTROL) = 0 ; // Stop PWM + +// Stop PWM clock before changing divisor. The delay after this does need to +// this big (95uS occasionally fails, 100uS OK), it's almost as though the BUSY +// flag is not working properly in balanced mode. Without the delay when DIV is +// adjusted the clock sometimes switches to very slow, once slow further DIV +// adjustments do nothing and it's difficult to get out of this mode. + + *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock + delayMicroseconds (110) ; // prevents clock going sloooow + + while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY + delayMicroseconds (1) ; + + *(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ; + + *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Start PWM clock + *(pwm + PWM_CONTROL) = pwm_control ; // restore PWM_CONTROL + + if (wiringPiDebug) + printf ("Set to: %d. Now : 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; + } +} + + +/* + * gpioClockSet: + * Set the freuency on a GPIO clock pin + ********************************************************************************* + */ + +void gpioClockSet (int pin, int freq) +{ + int divi, divr, divf ; + + pin &= 63 ; + + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + divi = 19200000 / freq ; + divr = 19200000 % freq ; + divf = (int)((double)divr * 4096.0 / 19200000.0) ; + + if (divi > 4095) + divi = 4095 ; + + *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | GPIO_CLOCK_SOURCE ; // Stop GPIO Clock + while ((*(clk + gpioToClkCon [pin]) & 0x80) != 0) // ... and wait + ; + + *(clk + gpioToClkDiv [pin]) = BCM_PASSWORD | (divi << 12) | divf ; // Set dividers + *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | 0x10 | GPIO_CLOCK_SOURCE ; // Start Clock +} + + +/* + * wiringPiFindNode: + * Locate our device node + ********************************************************************************* + */ + +struct wiringPiNodeStruct *wiringPiFindNode (int pin) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + while (node != NULL) + if ((pin >= node->pinBase) && (pin <= node->pinMax)) + return node ; + else + node = node->next ; + + return NULL ; +} + + +/* + * wiringPiNewNode: + * Create a new GPIO node into the wiringPi handling system + ********************************************************************************* + */ + +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) +{ + int pin ; + struct wiringPiNodeStruct *node ; + +// Minimum pin base is 64 + + if (pinBase < 64) + (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: pinBase of %d is < 64\n", pinBase) ; + +// Check all pins in-case there is overlap: + + for (pin = pinBase ; pin < (pinBase + numPins) ; ++pin) + if (wiringPiFindNode (pin) != NULL) + (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Pin %d overlaps with existing definition\n", pin) ; + + node = (struct wiringPiNodeStruct *)calloc (sizeof (struct wiringPiNodeStruct), 1) ; // calloc zeros + 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->digitalRead8 = digitalRead8Dummy ; + node->digitalWrite = digitalWriteDummy ; +//node->digitalWrite8 = digitalWrite8Dummy ; + node->pwmWrite = pwmWriteDummy ; + node->analogRead = analogReadDummy ; + node->analogWrite = analogWriteDummy ; + node->next = wiringPiNodes ; + wiringPiNodes = node ; + + return node ; +} + + +#ifdef notYetReady +/* + * pinED01: + * pinED10: + * Enables edge-detect mode on a pin - from a 0 to a 1 or 1 to 0 + * Pin must already be in input mode with appropriate pull up/downs set. + ********************************************************************************* + */ + +void pinEnableED01Pi (int pin) +{ + pin = pinToGpio [pin & 63] ; +} +#endif + + +/* + ********************************************************************************* + * Core Functions + ********************************************************************************* + */ + +/* + * pinModeAlt: + * This is an un-documented special to let you set any pin to any mode + ********************************************************************************* + */ + +void pinModeAlt (int pin, int mode) +{ + int fSel, shift ; + + if ((pin & PI_GPIO_MASK) == 0) // On-board pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ; + } +} + + +/* + * pinMode: + * Sets the mode of a pin to be input, output or PWM output + ********************************************************************************* + */ + +void pinMode (int pin, int mode) +{ + int fSel, shift, alt ; + struct wiringPiNodeStruct *node = wiringPiNodes ; + int origPin = pin ; + + if ((pin & PI_GPIO_MASK) == 0) // On-board pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + softPwmStop (origPin) ; + softToneStop (origPin) ; + + fSel = gpioToGPFSEL [pin] ; + shift = gpioToShift [pin] ; + + /**/ if (mode == INPUT) + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input + else if (mode == OUTPUT) + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ; + else if (mode == SOFT_PWM_OUTPUT) + softPwmCreate (origPin, 0, 100) ; + else if (mode == SOFT_TONE_OUTPUT) + softToneCreate (origPin) ; + else if (mode == PWM_TONE_OUTPUT) + { + pinMode (origPin, PWM_OUTPUT) ; // Call myself to enable PWM mode + pwmSetMode (PWM_MODE_MS) ; + } + else if (mode == PWM_OUTPUT) + { + if ((alt = gpioToPwmALT [pin]) == 0) // Not a hardware capable PWM pin + return ; + +// Set pin to PWM mode + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; + delayMicroseconds (110) ; // See comments in pwmSetClockWPi + + pwmSetMode (PWM_MODE_BAL) ; // Pi default mode + pwmSetRange (1024) ; // Default range of 1024 + pwmSetClock (32) ; // 19.2 / 32 = 600KHz - Also starts the PWM + } + else if (mode == GPIO_CLOCK) + { + if ((alt = gpioToGpClkALT0 [pin]) == 0) // Not a GPIO_CLOCK pin + return ; + +// Set pin to GPIO_CLOCK mode and set the clock frequency to 100KHz + + *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; + delayMicroseconds (110) ; + gpioClockSet (pin, 100000) ; + } + } + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pinMode (node, pin, mode) ; + return ; + } +} + + +/* + * 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. + ********************************************************************************* + */ + +void pullUpDnControl (int pin, int pud) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + *(gpio + GPPUD) = pud & 3 ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; + + *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; + *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; + } + else // Extension module + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pullUpDnControl (node, pin, pud) ; + return ; + } +} + + +/* + * digitalRead: + * Read the value of a given Pin, returning HIGH or LOW + ********************************************************************************* + */ + +int digitalRead (int pin) +{ + char c ; + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + { + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode + { + if (sysFds [pin] == -1) + return LOW ; + + lseek (sysFds [pin], 0L, SEEK_SET) ; + read (sysFds [pin], &c, 1) ; + return (c == '0') ? LOW : HIGH ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return LOW ; + + if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) + return HIGH ; + else + return LOW ; + } + else + { + if ((node = wiringPiFindNode (pin)) == NULL) + return LOW ; + return node->digitalRead (node, 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 + ********************************************************************************* + */ + +void digitalWrite (int pin, int value) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + { + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode + { + if (sysFds [pin] != -1) + { + if (value == LOW) + write (sysFds [pin], "0\n", 2) ; + else + write (sysFds [pin], "1\n", 2) ; + } + return ; + } + else if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + if (value == LOW) + *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; + else + *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; + } + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->digitalWrite (node, pin, 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 + ********************************************************************************* + */ + +void pwmWrite (int pin, int value) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin + { + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + else if (wiringPiMode != WPI_MODE_GPIO) + return ; + + *(pwm + gpioToPwmPort [pin]) = value ; + } + else + { + if ((node = wiringPiFindNode (pin)) != NULL) + node->pwmWrite (node, pin, value) ; + } +} + + +/* + * analogRead: + * Read the analog value of a given Pin. + * There is no on-board Pi analog hardware, + * so this needs to go to a new node. + ********************************************************************************* + */ + +int analogRead (int pin) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((node = wiringPiFindNode (pin)) == NULL) + return 0 ; + else + return node->analogRead (node, pin) ; +} + + +/* + * analogWrite: + * Write the analog value to the given Pin. + * There is no on-board Pi analog hardware, + * so this needs to go to a new node. + ********************************************************************************* + */ + +void analogWrite (int pin, int value) +{ + struct wiringPiNodeStruct *node = wiringPiNodes ; + + if ((node = wiringPiFindNode (pin)) == NULL) + return ; + + node->analogWrite (node, pin, value) ; +} + + +/* + * pwmToneWrite: + * Pi Specific. + * Output the given frequency on the Pi's PWM pin + ********************************************************************************* + */ + +void pwmToneWrite (int pin, int freq) +{ + int range ; + + if (freq == 0) + pwmWrite (pin, 0) ; // Off + else + { + range = 600000 / freq ; + pwmSetRange (range) ; + pwmWrite (pin, freq / 2) ; + } +} + + + +/* + * digitalWriteByte: + * digitalReadByte: + * Pi Specific + * Write an 8-bit byte to the first 8 GPIO pins - try to do it as + * fast as possible. + * However it still needs 2 operations to set the bits, so any external + * hardware must not rely on seeing a change as there will be a change + * to set the outputs bits to zero, then another change to set the 1's + * 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, 3, zero + ********************************************************************************* + */ + +void digitalWriteByte (const int value) +{ + uint32_t pinSet = 0 ; + uint32_t pinClr = 0 ; + int mask = 1 ; + int pin ; + + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) + { + for (pin = 0 ; pin < 8 ; ++pin) + { + digitalWrite (pinToGpio [pin], value & mask) ; + mask <<= 1 ; + } + return ; + } + else + { + for (pin = 0 ; pin < 8 ; ++pin) + { + if ((value & mask) == 0) + pinClr |= (1 << pinToGpio [pin]) ; + else + pinSet |= (1 << pinToGpio [pin]) ; + + mask <<= 1 ; + } + + *(gpio + gpioToGPCLR [0]) = pinClr ; + *(gpio + gpioToGPSET [0]) = pinSet ; + } +} + +unsigned int digitalReadByte (void) +{ + int pin, x ; + uint32_t raw ; + uint32_t data = 0 ; + + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) + { + for (pin = 0 ; pin < 8 ; ++pin) + { + x = digitalRead (pinToGpio [pin]) ; + data = (data << 1) | x ; + } + } + else + { + raw = *(gpio + gpioToGPLEV [0]) ; // First bank for these pins + for (pin = 0 ; pin < 8 ; ++pin) + { + x = pinToGpio [pin] ; + data = (data << 1) | (((raw & (1 << x)) == 0) ? 0 : 1) ; + } + } + return data ; +} + + +/* + * digitalWriteByte2: + * digitalReadByte2: + * Pi Specific + * Write an 8-bit byte to the second set of 8 GPIO pins. This is marginally + * faster than the first lot as these are consecutive BCM_GPIO pin numbers. + * However they overlap with the original read/write bytes. + ********************************************************************************* + */ + +void digitalWriteByte2 (const int value) +{ + register int mask = 1 ; + register int pin ; + + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) + { + for (pin = 20 ; pin < 28 ; ++pin) + { + digitalWrite (pin, value & mask) ; + mask <<= 1 ; + } + return ; + } + else + { + *(gpio + gpioToGPCLR [0]) = (~value & 0xFF) << 20 ; // 0x0FF00000; ILJ > CHANGE: Old causes glitch + *(gpio + gpioToGPSET [0]) = ( value & 0xFF) << 20 ; + } +} + +unsigned int digitalReadByte2 (void) +{ + int pin, x ; + uint32_t data = 0 ; + + /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) + { + for (pin = 20 ; pin < 28 ; ++pin) + { + x = digitalRead (pin) ; + data = (data << 1) | x ; + } + } + else + data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins + + return data ; +} + + +/* + * waitForInterrupt: + * Pi Specific. + * Wait for Interrupt on a GPIO pin. + * This is actually done via the /sys/class/gpio interface regardless of + * the wiringPi access mode in-use. Maybe sometime it might get a better + * way for a bit more efficiency. + ********************************************************************************* + */ + +int waitForInterrupt (int pin, int mS) +{ + int fd, x ; + uint8_t c ; + struct pollfd polls ; + + /**/ if (wiringPiMode == WPI_MODE_PINS) + pin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + pin = physToGpio [pin] ; + + if ((fd = sysFds [pin]) == -1) + return -2 ; + +// Setup poll structure + + polls.fd = fd ; + polls.events = POLLPRI | POLLERR ; + +// Wait for it ... + + x = poll (&polls, 1, mS) ; + +// If no error, do a dummy read to clear the interrupt +// A one character read appars to be enough. + + if (x > 0) + { + lseek (fd, 0, SEEK_SET) ; // Rewind + (void)read (fd, &c, 1) ; // Read & clear + } + + return x ; +} + + +/* + * interruptHandler: + * This is a thread and gets started to wait for the interrupt we're + * hoping to catch. It will call the user-function when the interrupt + * fires. + ********************************************************************************* + */ + +static void *interruptHandler (UNU void *arg) +{ + int myPin ; + + (void)piHiPri (55) ; // Only effective if we run as root + + myPin = pinPass ; + pinPass = -1 ; + + for (;;) + if (waitForInterrupt (myPin, -1) > 0) + isrFunctions [myPin] () ; + + return NULL ; +} + + +/* + * wiringPiISR: + * Pi Specific. + * Take the details and create an interrupt handler that will do a call- + * back to the user supplied function. + ********************************************************************************* + */ + +int wiringPiISR (int pin, int mode, void (*function)(void)) +{ + pthread_t threadId ; + const char *modeS ; + char fName [64] ; + char pinS [8] ; + pid_t pid ; + int count, i ; + char c ; + int bcmGpioPin ; + + if ((pin < 0) || (pin > 63)) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-63 (%d)\n", pin) ; + + /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; + else if (wiringPiMode == WPI_MODE_PINS) + bcmGpioPin = pinToGpio [pin] ; + else if (wiringPiMode == WPI_MODE_PHYS) + bcmGpioPin = physToGpio [pin] ; + else + bcmGpioPin = pin ; + +// Now export the pin and set the right edge +// We're going to use the gpio program to do this, so it assumes +// a full installation of wiringPi. It's a bit 'clunky', but it +// is a way that will work when we're running in "Sys" mode, as +// a non-root user. (without sudo) + + if (mode != INT_EDGE_SETUP) + { + /**/ if (mode == INT_EDGE_FALLING) + modeS = "falling" ; + else if (mode == INT_EDGE_RISING) + modeS = "rising" ; + else + modeS = "both" ; + + sprintf (pinS, "%d", bcmGpioPin) ; + + if ((pid = fork ()) < 0) // Fail + return wiringPiFailure (WPI_FATAL, "wiringPiISR: fork failed: %s\n", strerror (errno)) ; + + if (pid == 0) // Child, exec + { + /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0) + { + execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; + } + else if (access ("/usr/bin/gpio", X_OK) == 0) + { + execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; + return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; + } + else + return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ; + } + else // Parent, wait + wait (NULL) ; + } + +// Now pre-open the /sys/class node - but it may already be open if +// we are in Sys mode... + + if (sysFds [bcmGpioPin] == -1) + { + sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ; + if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0) + return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ; + } + +// Clear any initial pending interrupt + + ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ; + for (i = 0 ; i < count ; ++i) + read (sysFds [bcmGpioPin], &c, 1) ; + + isrFunctions [pin] = function ; + + pthread_mutex_lock (&pinMutex) ; + pinPass = pin ; + pthread_create (&threadId, NULL, interruptHandler, NULL) ; + while (pinPass != -1) + delay (1) ; + pthread_mutex_unlock (&pinMutex) ; + + return 0 ; +} + + +/* + * initialiseEpoch: + * Initialise our start-of-time variable to be the current unix + * time in milliseconds and microseconds. + ********************************************************************************* + */ + +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 +} + + +/* + * delay: + * Wait for some number of milliseconds + ********************************************************************************* + */ + +void delay (unsigned int howLong) +{ + struct timespec sleeper, dummy ; + + sleeper.tv_sec = (time_t)(howLong / 1000) ; + sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; + + nanosleep (&sleeper, &dummy) ; +} + + +/* + * delayMicroseconds: + * This is somewhat intersting. It seems that on the Pi, a single call + * to nanosleep takes some 80 to 130 microseconds anyway, so while + * obeying the standards (may take longer), it's not always what we + * want! + * + * So what I'll do now is if the delay is less than 100uS we'll do it + * in a hard loop, watching a built-in counter on the ARM chip. This is + * somewhat sub-optimal in that it uses 100% CPU, something not an issue + * in a microcontroller, but under a multi-tasking, multi-user OS, it's + * wastefull, however we've no real choice )-: + * + * Plan B: It seems all might not be well with that plan, so changing it + * to use gettimeofday () and poll on that instead... + ********************************************************************************* + */ + +void delayMicrosecondsHard (unsigned int howLong) +{ + struct timeval tNow, tLong, tEnd ; + + gettimeofday (&tNow, NULL) ; + tLong.tv_sec = howLong / 1000000 ; + tLong.tv_usec = howLong % 1000000 ; + timeradd (&tNow, &tLong, &tEnd) ; + + while (timercmp (&tNow, &tEnd, <)) + gettimeofday (&tNow, NULL) ; +} + +void delayMicroseconds (unsigned int howLong) +{ + struct timespec sleeper ; + unsigned int uSecs = howLong % 1000000 ; + unsigned int wSecs = howLong / 1000000 ; + + /**/ if (howLong == 0) + return ; + else if (howLong < 100) + delayMicrosecondsHard (howLong) ; + else + { + sleeper.tv_sec = wSecs ; + sleeper.tv_nsec = (long)(uSecs * 1000L) ; + nanosleep (&sleeper, NULL) ; + } +} + + +/* + * millis: + * Return a number of milliseconds as an unsigned int. + * Wraps at 49 days. + ********************************************************************************* + */ + +unsigned int millis (void) +{ + 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) ; +} + + +/* + * micros: + * Return a number of microseconds as an unsigned int. + * Wraps after 71 minutes. + ********************************************************************************* + */ + +unsigned int micros (void) +{ + 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: + * Must be called once at the start of your program execution. + * + * Default setup: Initialises the system into wiringPi Pin mode and uses the + * memory mapped hardware directly. + * + * Changed now to revert to "gpio" mode if we're running on a Compute Module. + ********************************************************************************* + */ + +int wiringPiSetup (void) +{ + int fd ; + int model, rev, mem, maker, overVolted ; + static int alreadyDoneThis = FALSE ; + +// 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. + + if (alreadyDoneThis) + return 0 ; + + alreadyDoneThis = TRUE ; + + if (getenv (ENV_DEBUG) != NULL) + wiringPiDebug = TRUE ; + + if (getenv (ENV_CODES) != NULL) + wiringPiReturnCodes = TRUE ; + + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetup called\n") ; + +// 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 ((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 // A2, B2, A+, B+, CM, Pi2, Pi3, Zero + { + pinToGpio = pinToGpioR2 ; + physToGpio = physToGpioR2 ; + } + +// ... + + switch (model) + { + 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 ; + } + +// 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. + + if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) + { + if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem or /dev/gpiomem: %s.\n Try running with sudo?\n", strerror (errno)) ; + piGpioBase = 0 ; + } + +// Set the offsets into the memory interface. + + 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 (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 (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 (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 (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 (timer == MAP_FAILED) + return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (TIMER) failed: %s\n", strerror (errno)) ; + +// Set the timer to free-running, 1MHz. +// 0xF9 is 249, the timer divide is base clock / (divide+1) +// so base clock is 250MHz / 250 = 1MHz. + + *(timer + TIMER_CONTROL) = 0x0000280 ; + *(timer + TIMER_PRE_DIV) = 0x00000F9 ; + timerIrqRaw = timer + TIMER_IRQ_RAW ; +#endif + + initialiseEpoch () ; + + return 0 ; +} + + +/* + * wiringPiSetupGpio: + * Must be called once at the start of your program execution. + * + * GPIO setup: Initialises the system into GPIO Pin mode and uses the + * memory mapped hardware directly. + ********************************************************************************* + */ + +int wiringPiSetupGpio (void) +{ + (void)wiringPiSetup () ; + + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetupGpio called\n") ; + + wiringPiMode = WPI_MODE_GPIO ; + + return 0 ; +} + + +/* + * wiringPiSetupPhys: + * Must be called once at the start of your program execution. + * + * Phys setup: Initialises the system into Physical Pin mode and uses the + * memory mapped hardware directly. + ********************************************************************************* + */ + +int wiringPiSetupPhys (void) +{ + (void)wiringPiSetup () ; + + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetupPhys called\n") ; + + wiringPiMode = WPI_MODE_PHYS ; + + return 0 ; +} + + +/* + * wiringPiSetupSys: + * Must be called once at the start of your program execution. + * + * Initialisation (again), however this time we are using the /sys/class/gpio + * interface to the GPIO systems - slightly slower, but always usable as + * a non-root user, assuming the devices are already exported and setup correctly. + */ + +int wiringPiSetupSys (void) +{ + int pin ; + char fName [128] ; + + static int alreadyDoneThis = FALSE ; + +// 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. + + if (alreadyDoneThis) + return 0 ; + + alreadyDoneThis = TRUE ; + + if (getenv (ENV_DEBUG) != NULL) + wiringPiDebug = TRUE ; + + if (getenv (ENV_CODES) != NULL) + wiringPiReturnCodes = TRUE ; + + if (wiringPiDebug) + printf ("wiringPi: wiringPiSetupSys called\n") ; + + if (piGpioLayout () == 1) + { + pinToGpio = pinToGpioR1 ; + physToGpio = physToGpioR1 ; + } + else + { + pinToGpio = pinToGpioR2 ; + physToGpio = physToGpioR2 ; + } + +// Open and scan the directory, looking for exported GPIOs, and pre-open +// the 'value' interface to speed things up for later + + for (pin = 0 ; pin < 64 ; ++pin) + { + sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; + sysFds [pin] = open (fName, O_RDWR) ; + } + + initialiseEpoch () ; + + wiringPiMode = WPI_MODE_GPIO_SYS ; + + return 0 ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPi.h b/FlippR-Driver/src/lib/wiringPi/wiringPi.h new file mode 100644 index 0000000..f601f13 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPi.h @@ -0,0 +1,254 @@ +/* + * wiringPi.h: + * Arduino like Wiring library for the Raspberry Pi. + * 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 . + *********************************************************************** + */ + +#ifndef __WIRING_PI_H__ +#define __WIRING_PI_H__ + +// 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 + +#define WPI_MODE_PINS 0 +#define WPI_MODE_GPIO 1 +#define WPI_MODE_GPIO_SYS 2 +#define WPI_MODE_PHYS 3 +#define WPI_MODE_PIFACE 4 +#define WPI_MODE_UNINITIALISED -1 + +// Pin modes + +#define INPUT 0 +#define OUTPUT 1 +#define PWM_OUTPUT 2 +#define GPIO_CLOCK 3 +#define SOFT_PWM_OUTPUT 4 +#define SOFT_TONE_OUTPUT 5 +#define PWM_TONE_OUTPUT 6 + +#define LOW 0 +#define HIGH 1 + +// Pull up/down/none + +#define PUD_OFF 0 +#define PUD_DOWN 1 +#define PUD_UP 2 + +// PWM + +#define PWM_MODE_MS 0 +#define PWM_MODE_BAL 1 + +// Interrupt levels + +#define INT_EDGE_SETUP 0 +#define INT_EDGE_FALLING 1 +#define INT_EDGE_RISING 2 +#define INT_EDGE_BOTH 3 + +// 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_CM3 10 +#define PI_MODEL_ZERO_W 12 + +#define PI_VERSION_1 0 +#define PI_VERSION_1_1 1 +#define PI_VERSION_1_2 2 +#define PI_VERSION_2 3 + +#define PI_MAKER_SONY 0 +#define PI_MAKER_EGOMAN 1 +#define PI_MAKER_EMBEST 2 +#define PI_MAKER_UNKNOWN 3 + +extern const char *piModelNames [16] ; +extern const char *piRevisionNames [16] ; +extern const char *piMakerNames [16] ; +extern const int piMemorySize [ 8] ; + + +// Intended for the GPIO program Use at your own risk. + +// Threads + +#define PI_THREAD(X) void *X (UNU void *dummy) + +// Failure modes + +#define WPI_FATAL (1==1) +#define WPI_ALMOST (1==2) + + +// wiringPiNodeStruct: +// This describes additional device nodes in the extended wiringPi +// 2.0 scheme of things. +// It's a simple linked list for now, but will hopefully migrate to +// a binary tree for efficiency reasons - but then again, the chances +// of more than 1 or 2 devices being added are fairly slim, so who +// knows.... + +struct wiringPiNodeStruct +{ + int pinBase ; + int pinMax ; + + int fd ; // Node specific + unsigned int data0 ; // ditto + unsigned int data1 ; // ditto + 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) ; +//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 ; + + +// Function prototypes +// c++ wrappers thanks to a comment by Nick Lott +// (and others on the Raspberry Pi forums) + +#ifdef __cplusplus +extern "C" { +#endif + +// Data + +// Internal + +extern int wiringPiFailure (int fatal, const char *message, ...) ; + +// Core wiringPi functions + +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 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) + +extern int wiringPiSetupPiFace (void) ; +extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only + +// On-Board Raspberry Pi hardware specific stuff + +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 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) + +extern int waitForInterrupt (int pin, int mS) ; +extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; + +// Threads + +extern int piThreadCreate (void *(*fn)(void *)) ; +extern void piLock (int key) ; +extern void piUnlock (int key) ; + +// Schedulling priority + +extern int piHiPri (const int pri) ; + +// Extras from arduino land + +extern void delay (unsigned int howLong) ; +extern void delayMicroseconds (unsigned int howLong) ; +extern unsigned int millis (void) ; +extern unsigned int micros (void) ; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c new file mode 100644 index 0000000..b0ee5d3 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c @@ -0,0 +1,233 @@ +/* + * wiringPiI2C.c: + * Simplified I2C access routines + * Copyright (c) 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 . + *********************************************************************** + */ + +/* + * Notes: + * The Linux I2C code is actually the same (almost) as the SMBus code. + * SMBus is System Management Bus - and in essentially I2C with some + * additional functionality added, and stricter controls on the electrical + * specifications, etc. however I2C does work well with it and the + * protocols work over both. + * + * I'm directly including the SMBus functions here as some Linux distros + * lack the correct header files, and also some header files are GPLv2 + * rather than the LGPL that wiringPi is released under - presumably because + * originally no-one expected I2C/SMBus to be used outside the kernel - + * however enter the Raspberry Pi with people now taking directly to I2C + * devices without going via the kernel... + * + * This may ultimately reduce the flexibility of this code, but it won't be + * hard to maintain it and keep it current, should things change. + * + * Information here gained from: kernel/Documentation/i2c/dev-interface + * as well as other online resources. + ********************************************************************************* + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wiringPi.h" +#include "wiringPiI2C.h" + +// I2C definitions + +#define I2C_SLAVE 0x0703 +#define I2C_SMBUS 0x0720 /* SMBus-level access */ + +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +// SMBus transaction types + +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + +// SMBus messages + +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ + +// Structures used in the ioctl() calls + +union i2c_smbus_data +{ + uint8_t byte ; + uint16_t word ; + uint8_t block [I2C_SMBUS_BLOCK_MAX + 2] ; // block [0] is used for length + one more for PEC +} ; + +struct i2c_smbus_ioctl_data +{ + char read_write ; + uint8_t command ; + int size ; + union i2c_smbus_data *data ; +} ; + +static inline int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args ; + + args.read_write = rw ; + args.command = command ; + args.size = size ; + args.data = data ; + return ioctl (fd, I2C_SMBUS, &args) ; +} + + +/* + * wiringPiI2CRead: + * Simple device read + ********************************************************************************* + */ + +int wiringPiI2CRead (int fd) +{ + union i2c_smbus_data data ; + + if (i2c_smbus_access (fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)) + return -1 ; + else + return data.byte & 0xFF ; +} + + +/* + * wiringPiI2CReadReg8: wiringPiI2CReadReg16: + * Read an 8 or 16-bit value from a regsiter on the device + ********************************************************************************* + */ + +int wiringPiI2CReadReg8 (int fd, int reg) +{ + union i2c_smbus_data data; + + if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data)) + return -1 ; + else + return data.byte & 0xFF ; +} + +int wiringPiI2CReadReg16 (int fd, int reg) +{ + union i2c_smbus_data data; + + if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, &data)) + return -1 ; + else + return data.word & 0xFFFF ; +} + + +/* + * wiringPiI2CWrite: + * Simple device write + ********************************************************************************* + */ + +int wiringPiI2CWrite (int fd, int data) +{ + return i2c_smbus_access (fd, I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) ; +} + + +/* + * wiringPiI2CWriteReg8: wiringPiI2CWriteReg16: + * Write an 8 or 16-bit value to the given register + ********************************************************************************* + */ + +int wiringPiI2CWriteReg8 (int fd, int reg, int value) +{ + union i2c_smbus_data data ; + + data.byte = value ; + return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data) ; +} + +int wiringPiI2CWriteReg16 (int fd, int reg, int value) +{ + union i2c_smbus_data data ; + + data.word = value ; + return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, &data) ; +} + + +/* + * wiringPiI2CSetupInterface: + * Undocumented access to set the interface explicitly - might be used + * for the Pi's 2nd I2C interface... + ********************************************************************************* + */ + +int wiringPiI2CSetupInterface (const char *device, int devId) +{ + int fd ; + + if ((fd = open (device, O_RDWR)) < 0) + return wiringPiFailure (WPI_ALMOST, "Unable to open I2C device: %s\n", strerror (errno)) ; + + if (ioctl (fd, I2C_SLAVE, devId) < 0) + return wiringPiFailure (WPI_ALMOST, "Unable to select I2C device: %s\n", strerror (errno)) ; + + return fd ; +} + + +/* + * wiringPiI2CSetup: + * Open the I2C device, and regsiter the target device + ********************************************************************************* + */ + +int wiringPiI2CSetup (const int devId) +{ + int rev ; + const char *device ; + + rev = piGpioLayout () ; + + if (rev == 1) + device = "/dev/i2c-0" ; + else + device = "/dev/i2c-1" ; + + return wiringPiI2CSetupInterface (device, devId) ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h new file mode 100644 index 0000000..6db8c68 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h @@ -0,0 +1,42 @@ +/* + * wiringPiI2C.h: + * Simplified I2C access routines + * Copyright (c) 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int wiringPiI2CRead (int fd) ; +extern int wiringPiI2CReadReg8 (int fd, int reg) ; +extern int wiringPiI2CReadReg16 (int fd, int reg) ; + +extern int wiringPiI2CWrite (int fd, int data) ; +extern int wiringPiI2CWriteReg8 (int fd, int reg, int data) ; +extern int wiringPiI2CWriteReg16 (int fd, int reg, int data) ; + +extern int wiringPiI2CSetupInterface (const char *device, int devId) ; +extern int wiringPiI2CSetup (const int devId) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c new file mode 100644 index 0000000..022b99f --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c @@ -0,0 +1,137 @@ +/* + * wiringPiSPI.c: + * Simplified SPI access routines + * 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 . + *********************************************************************** + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include "wiringPi.h" + +#include "wiringPiSPI.h" + + +// The SPI bus parameters +// Variables as they need to be passed as pointers later on + +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] ; + + +/* + * wiringPiSPIGetFd: + * Return the file-descriptor for the given channel + ********************************************************************************* + */ + +int wiringPiSPIGetFd (int channel) +{ + return spiFds [channel & 1] ; +} + + +/* + * wiringPiSPIDataRW: + * Write and Read a block of data over the SPI bus. + * Note the data ia being read into the transmit buffer, so will + * overwrite it! + * This is also a full-duplex operation. + ********************************************************************************* + */ + +int wiringPiSPIDataRW (int channel, unsigned char *data, int len) +{ + struct spi_ioc_transfer spi ; + + channel &= 1 ; + +// Mentioned in spidev.h but not used in the original kernel documentation +// test program )-: + + memset (&spi, 0, sizeof (spi)) ; + + spi.tx_buf = (unsigned long)data ; + spi.rx_buf = (unsigned long)data ; + spi.len = len ; + spi.delay_usecs = spiDelay ; + spi.speed_hz = spiSpeeds [channel] ; + spi.bits_per_word = spiBPW ; + + return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; +} + + +/* + * wiringPiSPISetupMode: + * Open the SPI device, and set it up, with the mode, etc. + ********************************************************************************* + */ + +int wiringPiSPISetupMode (int channel, int speed, int mode) +{ + int fd ; + + mode &= 3 ; // Mode is 0, 1, 2 or 3 + channel &= 1 ; // Channel is 0 or 1 + + if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0) + return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device: %s\n", strerror (errno)) ; + + spiSpeeds [channel] = speed ; + spiFds [channel] = fd ; + +// Set SPI parameters. + + if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0) + return wiringPiFailure (WPI_ALMOST, "SPI Mode Change failure: %s\n", strerror (errno)) ; + + if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) + return wiringPiFailure (WPI_ALMOST, "SPI BPW Change failure: %s\n", strerror (errno)) ; + + if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) + return wiringPiFailure (WPI_ALMOST, "SPI Speed Change failure: %s\n", strerror (errno)) ; + + return fd ; +} + + +/* + * wiringPiSPISetup: + * Open the SPI device, and set it up, etc. in the default MODE 0 + ********************************************************************************* + */ + +int wiringPiSPISetup (int channel, int speed) +{ + return wiringPiSPISetupMode (channel, speed, 0) ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h new file mode 100644 index 0000000..3980321 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h @@ -0,0 +1,36 @@ +/* + * wiringPiSPI.h: + * Simplified SPI access routines + * 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 . + *********************************************************************** + */ + +#ifdef __cplusplus +extern "C" { +#endif + +int wiringPiSPIGetFd (int channel) ; +int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; +int wiringPiSPISetupMode (int channel, int speed, int mode) ; +int wiringPiSPISetup (int channel, int speed) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringSerial.c b/FlippR-Driver/src/lib/wiringPi/wiringSerial.c new file mode 100644 index 0000000..e1587ad --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringSerial.c @@ -0,0 +1,225 @@ +/* + * wiringSerial.c: + * Handle a serial port + *********************************************************************** + * 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 "wiringSerial.h" + +/* + * serialOpen: + * Open and initialise the serial port, setting all the right + * port parameters - or as many as are required - hopefully! + ********************************************************************************* + */ + +int serialOpen (const char *device, const int baud) +{ + struct termios options ; + speed_t myBaud ; + int status, fd ; + + 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 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 ; + } + + if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) + return -1 ; + + fcntl (fd, F_SETFL, O_RDWR) ; + +// Get and modify current options: + + tcgetattr (fd, &options) ; + + cfmakeraw (&options) ; + cfsetispeed (&options, myBaud) ; + cfsetospeed (&options, myBaud) ; + + options.c_cflag |= (CLOCAL | CREAD) ; + options.c_cflag &= ~PARENB ; + options.c_cflag &= ~CSTOPB ; + options.c_cflag &= ~CSIZE ; + options.c_cflag |= CS8 ; + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; + options.c_oflag &= ~OPOST ; + + options.c_cc [VMIN] = 0 ; + options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) + + tcsetattr (fd, TCSANOW, &options) ; + + ioctl (fd, TIOCMGET, &status); + + status |= TIOCM_DTR ; + status |= TIOCM_RTS ; + + ioctl (fd, TIOCMSET, &status); + + usleep (10000) ; // 10mS + + return fd ; +} + + +/* + * serialFlush: + * Flush the serial buffers (both tx & rx) + ********************************************************************************* + */ + +void serialFlush (const int fd) +{ + tcflush (fd, TCIOFLUSH) ; +} + + +/* + * serialClose: + * Release the serial port + ********************************************************************************* + */ + +void serialClose (const int fd) +{ + close (fd) ; +} + + +/* + * serialPutchar: + * Send a single character to the serial port + ********************************************************************************* + */ + +void serialPutchar (const int fd, const unsigned char c) +{ + write (fd, &c, 1) ; +} + + +/* + * serialPuts: + * Send a string to the serial port + ********************************************************************************* + */ + +void serialPuts (const int fd, const char *s) +{ + write (fd, s, strlen (s)) ; +} + +/* + * serialPrintf: + * Printf over Serial + ********************************************************************************* + */ + +void serialPrintf (const int fd, const char *message, ...) +{ + va_list argp ; + char buffer [1024] ; + + va_start (argp, message) ; + vsnprintf (buffer, 1023, message, argp) ; + va_end (argp) ; + + serialPuts (fd, buffer) ; +} + + +/* + * serialDataAvail: + * Return the number of bytes of data avalable to be read in the serial port + ********************************************************************************* + */ + +int serialDataAvail (const int fd) +{ + int result ; + + if (ioctl (fd, FIONREAD, &result) == -1) + return -1 ; + + return result ; +} + + +/* + * serialGetchar: + * Get a single character from the serial device. + * Note: Zero is a valid character and this function will time-out after + * 10 seconds. + ********************************************************************************* + */ + +int serialGetchar (const int fd) +{ + uint8_t x ; + + if (read (fd, &x, 1) != 1) + return -1 ; + + return ((int)x) & 0xFF ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringSerial.h b/FlippR-Driver/src/lib/wiringPi/wiringSerial.h new file mode 100644 index 0000000..430dc73 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringSerial.h @@ -0,0 +1,38 @@ +/* + * wiringSerial.h: + * Handle a serial port + *********************************************************************** + * 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 serialOpen (const char *device, const int baud) ; +extern void serialClose (const int fd) ; +extern void serialFlush (const int fd) ; +extern void serialPutchar (const int fd, const unsigned char c) ; +extern void serialPuts (const int fd, const char *s) ; +extern void serialPrintf (const int fd, const char *message, ...) ; +extern int serialDataAvail (const int fd) ; +extern int serialGetchar (const int fd) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringShift.c b/FlippR-Driver/src/lib/wiringPi/wiringShift.c new file mode 100644 index 0000000..3df94e8 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringShift.c @@ -0,0 +1,83 @@ +/* + * wiringShift.c: + * Emulate some of the Arduino wiring functionality. + * + * Copyright (c) 2009-2012 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 "wiringPi.h" +#include "wiringShift.h" + +/* + * shiftIn: + * Shift data in from a clocked source + ********************************************************************************* + */ + +uint8_t shiftIn (uint8_t dPin, uint8_t cPin, uint8_t order) +{ + uint8_t value = 0 ; + int8_t i ; + + if (order == MSBFIRST) + for (i = 7 ; i >= 0 ; --i) + { + digitalWrite (cPin, HIGH) ; + value |= digitalRead (dPin) << i ; + digitalWrite (cPin, LOW) ; + } + else + for (i = 0 ; i < 8 ; ++i) + { + digitalWrite (cPin, HIGH) ; + value |= digitalRead (dPin) << i ; + digitalWrite (cPin, LOW) ; + } + + return value; +} + +/* + * shiftOut: + * Shift data out to a clocked source + ********************************************************************************* + */ + +void shiftOut (uint8_t dPin, uint8_t cPin, uint8_t order, uint8_t val) +{ + int8_t i; + + if (order == MSBFIRST) + for (i = 7 ; i >= 0 ; --i) + { + digitalWrite (dPin, val & (1 << i)) ; + digitalWrite (cPin, HIGH) ; + digitalWrite (cPin, LOW) ; + } + else + for (i = 0 ; i < 8 ; ++i) + { + digitalWrite (dPin, val & (1 << i)) ; + digitalWrite (cPin, HIGH) ; + digitalWrite (cPin, LOW) ; + } +} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringShift.h b/FlippR-Driver/src/lib/wiringPi/wiringShift.h new file mode 100644 index 0000000..419ade4 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wiringShift.h @@ -0,0 +1,41 @@ +/* + * wiringShift.h: + * Emulate some of the Arduino wiring functionality. + * + * Copyright (c) 2009-2012 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 LSBFIRST 0 +#define MSBFIRST 1 + +#ifndef _STDINT_H +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t shiftIn (uint8_t dPin, uint8_t cPin, uint8_t order) ; +extern void shiftOut (uint8_t dPin, uint8_t cPin, uint8_t order, uint8_t val) ; + +#ifdef __cplusplus +} +#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c new file mode 100644 index 0000000..53fafc0 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c @@ -0,0 +1,928 @@ +/* + * extensions.c: + * Originally part of the GPIO program to test, peek, poke and otherwise + * noodle with the GPIO hardware on the Raspberry Pi. + * Now used as a general purpose library to allow systems to dynamically + * add in new devices into wiringPi at program run-time. + * 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 . + *********************************************************************** + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mcp23008.h" +#include "mcp23016.h" +#include "mcp23017.h" +#include "mcp23s08.h" +#include "mcp23s17.h" +#include "sr595.h" +#include "pcf8574.h" +#include "pcf8591.h" +#include "mcp3002.h" +#include "mcp3004.h" +#include "mcp4802.h" +#include "mcp3422.h" +#include "max31855.h" +#include "max5322.h" +#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" + +extern int wiringPiDebug ; + +static int verbose ; +static char errorMessage [1024] ; + + +// Local structure to hold details + +struct extensionFunctionStruct +{ + const char *name ; + int (*function)(char *progName, int pinBase, char *params) ; +} ; + + +/* + * verbError: + * Convenient error handling + ********************************************************************************* + */ + +static void verbError (const char *message, ...) +{ + va_list argp ; + va_start (argp, message) ; + vsnprintf (errorMessage, 1023, message, argp) ; + va_end (argp) ; + + if (verbose) + fprintf (stderr, "%s\n", errorMessage) ; +} + + +/* + * extractInt: + * Check & return an integer at the given location (prefixed by a :) + ********************************************************************************* + */ + +static char *extractInt (char *progName, char *p, int *num) +{ + if (*p != ':') + { + verbError ("%s: colon expected", progName) ; + return NULL ; + } + + ++p ; + + if (!isdigit (*p)) + { + verbError ("%s: digit expected", progName) ; + return NULL ; + } + + *num = strtol (p, NULL, 0) ; + +// Increment p, but we need to check for hex 0x + + if ((*p == '0') && (*(p + 1) == 'x')) + p +=2 ; + + while (isxdigit (*p)) + ++p ; + + return p ; +} + + +/* + * 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 != ':') + { + verbError ("%s: colon expected", progName) ; + return NULL ; + } + + ++p ; + + if (*p == '[') + { + quoted = TRUE ; + ++p ; + } + + if (!isprint (*p)) // Is this needed? + { + verbError ("%s: character expected", progName) ; + return NULL ; + } + + q = p ; + 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 ; +} + + + +/* + * doExtensionMcp23008: + * MCP23008 - 8-bit I2C GPIO expansion chip + * mcp23002:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionMcp23008 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x01) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + mcp23008Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * doExtensionMcp23016: + * MCP230016- 16-bit I2C GPIO expansion chip + * mcp23016:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionMcp23016 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + mcp23016Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * doExtensionMcp23017: + * MCP230017- 16-bit I2C GPIO expansion chip + * mcp23017:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionMcp23017 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + mcp23017Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * doExtensionMcp23s08: + * MCP23s08 - 8-bit SPI GPIO expansion chip + * mcp23s08:base:spi:port + ********************************************************************************* + */ + +static int doExtensionMcp23s08 (char *progName, int pinBase, char *params) +{ + int spi, port ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI address (%d) out of range", progName, spi) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &port)) == NULL) + return FALSE ; + + if ((port < 0) || (port > 7)) + { + verbError ("%s: port address (%d) out of range", progName, port) ; + return FALSE ; + } + + mcp23s08Setup (pinBase, spi, port) ; + + return TRUE ; +} + + +/* + * doExtensionMcp23s17: + * MCP23s17 - 16-bit SPI GPIO expansion chip + * mcp23s17:base:spi:port + ********************************************************************************* + */ + +static int doExtensionMcp23s17 (char *progName, int pinBase, char *params) +{ + int spi, port ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI address (%d) out of range", progName, spi) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &port)) == NULL) + return FALSE ; + + if ((port < 0) || (port > 7)) + { + verbError ("%s: port address (%d) out of range", progName, port) ; + return FALSE ; + } + + mcp23s17Setup (pinBase, spi, port) ; + + return TRUE ; +} + + +/* + * doExtensionSr595: + * Shift Register 74x595 + * sr595:base:pins:data:clock:latch + ********************************************************************************* + */ + +static int doExtensionSr595 (char *progName, int pinBase, char *params) +{ + int pins, data, clock, latch ; + +// Extract pins + + if ((params = extractInt (progName, params, &pins)) == NULL) + return FALSE ; + + if ((pins < 8) || (pins > 32)) + { + verbError ("%s: pin count (%d) out of range - 8-32 expected.", progName, pins) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &data)) == NULL) + return FALSE ; + + if ((params = extractInt (progName, params, &clock)) == NULL) + return FALSE ; + + if ((params = extractInt (progName, params, &latch)) == NULL) + return FALSE ; + + sr595Setup (pinBase, pins, data, clock, latch) ; + + return TRUE ; +} + + +/* + * doExtensionPcf8574: + * Digital IO (Crude!) + * pcf8574:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionPcf8574 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + pcf8574Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * doExtensionAds1115: + * Analog Input + * ads1115:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionAds1115 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + ads1115Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * doExtensionPcf8591: + * Analog IO + * pcf8591:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionPcf8591 (char *progName, int pinBase, char *params) +{ + int i2c ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + pcf8591Setup (pinBase, i2c) ; + + return TRUE ; +} + + +/* + * 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 + ********************************************************************************* + */ + +static int doExtensionMax31855 (char *progName, int pinBase, char *params) +{ + int spi ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI channel (%d) out of range", progName, spi) ; + return FALSE ; + } + + max31855Setup (pinBase, spi) ; + + return TRUE ; +} + + +/* + * doExtensionMcp3002: + * Analog IO + * mcp3002:base:spiChan + ********************************************************************************* + */ + +static int doExtensionMcp3002 (char *progName, int pinBase, char *params) +{ + int spi ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI channel (%d) out of range", progName, spi) ; + return FALSE ; + } + + mcp3002Setup (pinBase, spi) ; + + return TRUE ; +} + + +/* + * doExtensionMcp3004: + * Analog IO + * mcp3004:base:spiChan + ********************************************************************************* + */ + +static int doExtensionMcp3004 (char *progName, int pinBase, char *params) +{ + int spi ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI channel (%d) out of range", progName, spi) ; + return FALSE ; + } + + mcp3004Setup (pinBase, spi) ; + + return TRUE ; +} + + +/* + * doExtensionMax5322: + * Analog O + * max5322:base:spiChan + ********************************************************************************* + */ + +static int doExtensionMax5322 (char *progName, int pinBase, char *params) +{ + int spi ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI channel (%d) out of range", progName, spi) ; + return FALSE ; + } + + max5322Setup (pinBase, spi) ; + + return TRUE ; +} + + +/* + * doExtensionMcp4802: + * Analog IO + * mcp4802:base:spiChan + ********************************************************************************* + */ + +static int doExtensionMcp4802 (char *progName, int pinBase, char *params) +{ + int spi ; + + if ((params = extractInt (progName, params, &spi)) == NULL) + return FALSE ; + + if ((spi < 0) || (spi > 1)) + { + verbError ("%s: SPI channel (%d) out of range", progName, spi) ; + return FALSE ; + } + + mcp4802Setup (pinBase, spi) ; + + return TRUE ; +} + + +/* + * doExtensionSn3218: + * Analog Output (LED Driver) + * sn3218:base + ********************************************************************************* + */ + +static int doExtensionSn3218 (UNU char *progName, int pinBase, UNU char *params) +{ + sn3218Setup (pinBase) ; + return TRUE ; +} + + +/* + * doExtensionMcp3422: + * Analog IO + * mcp3422:base:i2cAddr + ********************************************************************************* + */ + +static int doExtensionMcp3422 (char *progName, int pinBase, char *params) +{ + int i2c, sampleRate, gain ; + + if ((params = extractInt (progName, params, &i2c)) == NULL) + return FALSE ; + + if ((i2c < 0x03) || (i2c > 0x77)) + { + verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &sampleRate)) == NULL) + return FALSE ; + + if ((sampleRate < 0) || (sampleRate > 3)) + { + verbError ("%s: sample rate (%d) out of range", progName, sampleRate) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &gain)) == NULL) + return FALSE ; + + if ((gain < 0) || (gain > 3)) + { + verbError ("%s: gain (%d) out of range", progName, gain) ; + return FALSE ; + } + + mcp3422Setup (pinBase, i2c, sampleRate, gain) ; + + return TRUE ; +} + + +/* + * doExtensionDrcS: + * Interface to a DRC Serial system + * drcs:base:pins:serialPort:baud + ********************************************************************************* + */ + +static int doExtensionDrcS (char *progName, int pinBase, char *params) +{ + char *port ; + int pins, baud ; + + 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, &port)) == NULL) + return FALSE ; + + if (strlen (port) == 0) + { + verbError ("%s: serial port device name required", progName) ; + return FALSE ; + } + + if ((params = extractInt (progName, params, &baud)) == NULL) + return FALSE ; + + if ((baud < 1) || (baud > 4000000)) + { + verbError ("%s: baud rate (%d) out of range", progName, baud) ; + return FALSE ; + } + + drcSetupSerial (pinBase, pins, port, baud) ; + + return TRUE ; +} + + +/* + * 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 + ********************************************************************************* + */ + +static struct extensionFunctionStruct extensionFunctions [] = +{ + { "mcp23008", &doExtensionMcp23008 }, + { "mcp23016", &doExtensionMcp23016 }, + { "mcp23017", &doExtensionMcp23017 }, + { "mcp23s08", &doExtensionMcp23s08 }, + { "mcp23s17", &doExtensionMcp23s17 }, + { "sr595", &doExtensionSr595 }, + { "pcf8574", &doExtensionPcf8574 }, + { "pcf8591", &doExtensionPcf8591 }, + { "bmp180", &doExtensionBmp180 }, + { "pseudoPins", &doExtensionPseudoPins }, + { "htu21d", &doExtensionHtu21d }, + { "ds18b20", &doExtensionDs18b20 }, + { "rht03", &doExtensionRht03 }, + { "mcp3002", &doExtensionMcp3002 }, + { "mcp3004", &doExtensionMcp3004 }, + { "mcp4802", &doExtensionMcp4802 }, + { "mcp3422", &doExtensionMcp3422 }, + { "max31855", &doExtensionMax31855 }, + { "ads1115", &doExtensionAds1115 }, + { "max5322", &doExtensionMax5322 }, + { "sn3218", &doExtensionSn3218 }, + { "drcs", &doExtensionDrcS }, + { "drcn", &doExtensionDrcNet }, + { NULL, NULL }, +} ; + + +/* + * loadWPiExtension: + * Load in a wiringPi extension + * The extensionData always starts with the name, a colon then the pinBase + * number. Other parameters after that are decoded by the module in question. + ********************************************************************************* + */ + +int loadWPiExtension (char *progName, char *extensionData, int printErrors) +{ + char *p ; + char *extension = extensionData ; + struct extensionFunctionStruct *extensionFn ; + unsigned pinBase = 0 ; + + verbose = printErrors ; + +// Get the extension name by finding the first colon + + p = extension ; + while (*p != ':') + { + if (!*p) // ran out of characters + { + verbError ("%s: extension name not terminated by a colon", progName) ; + return FALSE ; + } + ++p ; + } + *p++ = 0 ; + +// Simple ATOI code + + if (!isdigit (*p)) + { + verbError ("%s: decimal pinBase number expected after extension name", progName) ; + return FALSE ; + } + + while (isdigit (*p)) + { + if (pinBase > 2147483647) // 2^31-1 ... Lets be realistic here... + { + verbError ("%s: pinBase too large", progName) ; + return FALSE ; + } + + pinBase = pinBase * 10 + (*p - '0') ; + ++p ; + } + + if (pinBase < 64) + { + verbError ("%s: pinBase (%d) too small. Minimum is 64.", progName, pinBase) ; + return FALSE ; + } + +// Search for extensions: + + for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn) + { + if (strcmp (extensionFn->name, extension) == 0) + return extensionFn->function (progName, pinBase, p) ; + } + + fprintf (stderr, "%s: extension %s not found", progName, extension) ; + return FALSE ; +} diff --git a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h new file mode 100644 index 0000000..fcaec96 --- /dev/null +++ b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h @@ -0,0 +1,26 @@ +/* + * extensions.h: + * Part of the GPIO program to test, peek, poke and otherwise + * noodle with the GPIO hardware on 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 . + *********************************************************************** + */ + + +extern int loadWPiExtension (char *progName, char *extensionData, int verbose) ;