From 91cfa3aca855db069695df35379126c5cfd0e271 Mon Sep 17 00:00:00 2001 From: Micha Sende Date: Wed, 18 Dec 2024 08:37:32 +0100 Subject: [PATCH] fix(rotary_encoder): remove rotary_encoder_gpio_core --- rotary_encoder/_rotary_encoder.py | 14 +- rotary_encoder_gpio_core/.gitignore | 6 - rotary_encoder_gpio_core/LICENCE.txt | 20 - rotary_encoder_gpio_core/README.md | 7 - rotary_encoder_gpio_core/build.py | 32 - rotary_encoder_gpio_core/poetry.lock | 7 - rotary_encoder_gpio_core/pyproject.toml | 16 - .../rotary_encoder_gpio_core/__init__.py | 25 - rotary_encoder_gpio_core/source/c_gpio.c | 341 ------ rotary_encoder_gpio_core/source/c_gpio.h | 51 - rotary_encoder_gpio_core/source/common.c | 90 -- rotary_encoder_gpio_core/source/common.h | 44 - rotary_encoder_gpio_core/source/constants.c | 99 -- rotary_encoder_gpio_core/source/constants.h | 44 - rotary_encoder_gpio_core/source/cpuinfo.c | 273 ----- rotary_encoder_gpio_core/source/cpuinfo.h | 36 - rotary_encoder_gpio_core/source/event_gpio.c | 600 ---------- rotary_encoder_gpio_core/source/event_gpio.h | 36 - rotary_encoder_gpio_core/source/py_gpio.c | 1021 ----------------- .../test/issue_94_111_154.py | 36 - rotary_encoder_gpio_core/test/test.py | 805 ------------- 21 files changed, 6 insertions(+), 3597 deletions(-) delete mode 100755 rotary_encoder_gpio_core/.gitignore delete mode 100755 rotary_encoder_gpio_core/LICENCE.txt delete mode 100755 rotary_encoder_gpio_core/README.md delete mode 100755 rotary_encoder_gpio_core/build.py delete mode 100755 rotary_encoder_gpio_core/poetry.lock delete mode 100755 rotary_encoder_gpio_core/pyproject.toml delete mode 100755 rotary_encoder_gpio_core/rotary_encoder_gpio_core/__init__.py delete mode 100755 rotary_encoder_gpio_core/source/c_gpio.c delete mode 100755 rotary_encoder_gpio_core/source/c_gpio.h delete mode 100755 rotary_encoder_gpio_core/source/common.c delete mode 100755 rotary_encoder_gpio_core/source/common.h delete mode 100755 rotary_encoder_gpio_core/source/constants.c delete mode 100755 rotary_encoder_gpio_core/source/constants.h delete mode 100755 rotary_encoder_gpio_core/source/cpuinfo.c delete mode 100755 rotary_encoder_gpio_core/source/cpuinfo.h delete mode 100755 rotary_encoder_gpio_core/source/event_gpio.c delete mode 100755 rotary_encoder_gpio_core/source/event_gpio.h delete mode 100755 rotary_encoder_gpio_core/source/py_gpio.c delete mode 100755 rotary_encoder_gpio_core/test/issue_94_111_154.py delete mode 100755 rotary_encoder_gpio_core/test/test.py diff --git a/rotary_encoder/_rotary_encoder.py b/rotary_encoder/_rotary_encoder.py index 1c1a708..c843b99 100755 --- a/rotary_encoder/_rotary_encoder.py +++ b/rotary_encoder/_rotary_encoder.py @@ -14,7 +14,7 @@ class MissingGPIOLibraryError(Exception): try: - import rotary_encoder_gpio_core as gpio # type: ignore + import RPi.GPIO as gpio # type: ignore except ImportError as e: raise MissingGPIOLibraryError( "Could not import RPi.GPIO. If this code is running on a raspberry pi, " @@ -110,19 +110,17 @@ def _did_dial_move(self) -> bool: return True return False - def _on_clk_changed(self, channel: object, is_on: int) -> None: - self.clk_state = bool(is_on) + def _on_clk_changed(self, channel: object) -> None: + self.clk_state = self._get_clk_state() if self._did_dial_move() and self.on_counter_clockwise_turn is not None: self.callback_handler(self.on_counter_clockwise_turn) # type: ignore - def _on_dt_changed(self, channel: object, is_on: int) -> None: - self.dt_state = bool(is_on) + def _on_dt_changed(self, channel: object) -> None: + self.dt_state = self._get_dt_state() if self._did_dial_move() and self.on_clockwise_turn is not None: self.callback_handler(self.on_clockwise_turn) # type: ignore - def _on_sw_changed(self, channel: object, is_on: int) -> None: - # Here the is_on is unreliable because it's too fast, and the button - # might still be in the transition. + def _on_sw_changed(self, channel: object) -> None: is_on = gpio.input(self.sw_pin) if not is_on and self.on_button_down is not None: self.callback_handler(self.on_button_down) # type: ignore diff --git a/rotary_encoder_gpio_core/.gitignore b/rotary_encoder_gpio_core/.gitignore deleted file mode 100755 index 7a3fd56..0000000 --- a/rotary_encoder_gpio_core/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -__pycache__ -*.so -.vscode -*.egg-info -dist -build diff --git a/rotary_encoder_gpio_core/LICENCE.txt b/rotary_encoder_gpio_core/LICENCE.txt deleted file mode 100755 index 0c62fb1..0000000 --- a/rotary_encoder_gpio_core/LICENCE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/rotary_encoder_gpio_core/README.md b/rotary_encoder_gpio_core/README.md deleted file mode 100755 index 082f837..0000000 --- a/rotary_encoder_gpio_core/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# rotary_encoder_gpio_core - -Meany only as a core dependency of `rotary-encoder`. - -This is a fork of RPi.GPIO. For the original repo go to: -http://sourceforge.net/p/raspberry-gpio-python/ - diff --git a/rotary_encoder_gpio_core/build.py b/rotary_encoder_gpio_core/build.py deleted file mode 100755 index 62069da..0000000 --- a/rotary_encoder_gpio_core/build.py +++ /dev/null @@ -1,32 +0,0 @@ - - -from setuptools import Extension -from setuptools.command.build_ext import build_ext - - -ext_modules = [ - Extension( - 'rotary_encoder_gpio_core._gpio', - [ - 'source/py_gpio.c', - 'source/c_gpio.c', - 'source/cpuinfo.c', - 'source/event_gpio.c', - 'source/common.c', - 'source/constants.c', - ] - ) -] - - -def build(setup_kwargs: dict[str, object]) -> None: - """ - This function is mandatory in order to build the extensions. - """ - setup_kwargs.update( - { - "ext_modules": ext_modules, - "cmdclass": {"build_ext": build_ext}, - "zip_safe": False, - } - ) diff --git a/rotary_encoder_gpio_core/poetry.lock b/rotary_encoder_gpio_core/poetry.lock deleted file mode 100755 index 42d7d5e..0000000 --- a/rotary_encoder_gpio_core/poetry.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. -package = [] - -[metadata] -lock-version = "2.0" -python-versions = "^3.9" -content-hash = "c595a0588c25d58f3e3834ad7169126836d262b925fe6ca9b5d540dcf301d254" diff --git a/rotary_encoder_gpio_core/pyproject.toml b/rotary_encoder_gpio_core/pyproject.toml deleted file mode 100755 index 42d59a0..0000000 --- a/rotary_encoder_gpio_core/pyproject.toml +++ /dev/null @@ -1,16 +0,0 @@ -[tool.poetry] -name = "rotary-encoder-gpio-core" -version = "0.1.0" -description = "" -authors = ["None"] -license = "MIT" -readme = "README.md" -packages = [{include = "rotary_encoder_gpio_core"}] -build = "build.py" - -[tool.poetry.dependencies] -python = "^3.9" - -[build-system] -requires = ["setuptools", "poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/rotary_encoder_gpio_core/rotary_encoder_gpio_core/__init__.py b/rotary_encoder_gpio_core/rotary_encoder_gpio_core/__init__.py deleted file mode 100755 index 318e445..0000000 --- a/rotary_encoder_gpio_core/rotary_encoder_gpio_core/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2012-2021 Ben Croston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -"""This package provides a Python module to control the GPIO on a Raspberry Pi""" - -from rotary_encoder_gpio_core._gpio import * - -VERSION = '0.7.1' diff --git a/rotary_encoder_gpio_core/source/c_gpio.c b/rotary_encoder_gpio_core/source/c_gpio.c deleted file mode 100755 index 42390cf..0000000 --- a/rotary_encoder_gpio_core/source/c_gpio.c +++ /dev/null @@ -1,341 +0,0 @@ -/* -Copyright (c) 2012-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include -#include -#include -#include -#include -#include -#include "c_gpio.h" - -#define BCM2708_PERI_BASE_DEFAULT 0x20000000 -#define BCM2709_PERI_BASE_DEFAULT 0x3f000000 -#define BCM2710_PERI_BASE_DEFAULT 0x3f000000 -#define BCM2711_PERI_BASE_DEFAULT 0xfe000000 -#define GPIO_BASE_OFFSET 0x200000 -#define FSEL_OFFSET 0 // 0x0000 -#define SET_OFFSET 7 // 0x001c / 4 -#define CLR_OFFSET 10 // 0x0028 / 4 -#define PINLEVEL_OFFSET 13 // 0x0034 / 4 -#define EVENT_DETECT_OFFSET 16 // 0x0040 / 4 -#define RISING_ED_OFFSET 19 // 0x004c / 4 -#define FALLING_ED_OFFSET 22 // 0x0058 / 4 -#define HIGH_DETECT_OFFSET 25 // 0x0064 / 4 -#define LOW_DETECT_OFFSET 28 // 0x0070 / 4 -#define PULLUPDN_OFFSET 37 // 0x0094 / 4 -#define PULLUPDNCLK_OFFSET 38 // 0x0098 / 4 - -#define PULLUPDN_OFFSET_2711_0 57 -#define PULLUPDN_OFFSET_2711_1 58 -#define PULLUPDN_OFFSET_2711_2 59 -#define PULLUPDN_OFFSET_2711_3 60 - -#define PAGE_SIZE (4*1024) -#define BLOCK_SIZE (4*1024) - -static volatile uint32_t *gpio_map; - -void short_wait(void) -{ - int i; - - for (i=0; i<150; i++) { // wait 150 cycles - asm volatile("nop"); - } -} - -int setup(void) -{ - int mem_fd; - uint8_t *gpio_mem; - uint32_t peri_base = 0; - uint32_t gpio_base; - uint8_t ranges[12] = { 0 }; - uint8_t rev[4] = { 0 }; - uint32_t cpu = 0; - FILE *fp; - char buffer[1024]; - char hardware[1024]; - int found = 0; - - // try /dev/gpiomem first - this does not require root privs - if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0) - { - if ((gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0)) == MAP_FAILED) { - return SETUP_MMAP_FAIL; - } else { - return SETUP_OK; - } - } - - // revert to /dev/mem method - requires root privileges - - if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) - { - // get peri base from device tree - if (fread(ranges, 1, sizeof(ranges), fp) >= 8) { - peri_base = ranges[4] << 24 | ranges[5] << 16 | ranges[6] << 8 | ranges[7] << 0; - if (!peri_base) { - peri_base = ranges[8] << 24 | ranges[9] << 16 | ranges[10] << 8 | ranges[11] << 0; - } - } - if ((ranges[0] != 0x7e) || - (ranges[1] != 0x00) || - (ranges[2] != 0x00) || - (ranges[3] != 0x00) || - ((peri_base != BCM2708_PERI_BASE_DEFAULT) && - (peri_base != BCM2709_PERI_BASE_DEFAULT) && - (peri_base != BCM2711_PERI_BASE_DEFAULT))) { - // invalid ranges file - peri_base = 0; - } - fclose(fp); - } - - // guess peri_base based on /proc/device-tree/system/linux,revision - if (!peri_base) { - if ((fp = fopen("/proc/device-tree/system/linux,revision", "rb")) != NULL) { - if (fread(rev, 1, sizeof(rev), fp) == 4) { - cpu = (rev[2] >> 4) & 0xf; - switch (cpu) { - case 0 : peri_base = BCM2708_PERI_BASE_DEFAULT; - break; - case 1 : - case 2 : peri_base = BCM2709_PERI_BASE_DEFAULT; - break; - case 3 : peri_base = BCM2711_PERI_BASE_DEFAULT; - break; - } - } - fclose(fp); - } - } - - // guess peri_base based on /proc/cpuinfo hardware field - if (!peri_base) { - if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) - return SETUP_CPUINFO_FAIL; - - while(!feof(fp) && !found && fgets(buffer, sizeof(buffer), fp)) { - sscanf(buffer, "Hardware : %s", hardware); - if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) { - // pi 1 hardware - peri_base = BCM2708_PERI_BASE_DEFAULT; - } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) { - // pi 2 hardware - peri_base = BCM2709_PERI_BASE_DEFAULT; - } else if (strcmp(hardware, "BCM2710") == 0 || strcmp(hardware, "BCM2837") == 0) { - // pi 3 hardware - peri_base = BCM2710_PERI_BASE_DEFAULT; - } else if (strcmp(hardware, "BCM2711") == 0) { - // pi 4 hardware - peri_base = BCM2711_PERI_BASE_DEFAULT; - } - } - fclose(fp); - } - - if (!peri_base) - return SETUP_NO_PERI_ADDR; - - gpio_base = peri_base + GPIO_BASE_OFFSET; - - // mmap the GPIO memory registers - if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) - return SETUP_DEVMEM_FAIL; - - if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) - return SETUP_MALLOC_FAIL; - - if ((uint32_t)gpio_mem % PAGE_SIZE) - gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE); - - if ((gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base)) == MAP_FAILED) - return SETUP_MMAP_FAIL; - - return SETUP_OK; -} - -void clear_event_detect(int gpio) -{ - int offset = EVENT_DETECT_OFFSET + (gpio/32); - int shift = (gpio%32); - - *(gpio_map+offset) |= (1 << shift); - short_wait(); - *(gpio_map+offset) = 0; -} - -int eventdetected(int gpio) -{ - int offset, value, bit; - - offset = EVENT_DETECT_OFFSET + (gpio/32); - bit = (1 << (gpio%32)); - value = *(gpio_map+offset) & bit; - if (value) - clear_event_detect(gpio); - return value; -} - -void set_rising_event(int gpio, int enable) -{ - int offset = RISING_ED_OFFSET + (gpio/32); - int shift = (gpio%32); - - if (enable) - *(gpio_map+offset) |= 1 << shift; - else - *(gpio_map+offset) &= ~(1 << shift); - clear_event_detect(gpio); -} - -void set_falling_event(int gpio, int enable) -{ - int offset = FALLING_ED_OFFSET + (gpio/32); - int shift = (gpio%32); - - if (enable) { - *(gpio_map+offset) |= (1 << shift); - *(gpio_map+offset) = (1 << shift); - } else { - *(gpio_map+offset) &= ~(1 << shift); - } - clear_event_detect(gpio); -} - -void set_high_event(int gpio, int enable) -{ - int offset = HIGH_DETECT_OFFSET + (gpio/32); - int shift = (gpio%32); - - if (enable) - *(gpio_map+offset) |= (1 << shift); - else - *(gpio_map+offset) &= ~(1 << shift); - clear_event_detect(gpio); -} - -void set_low_event(int gpio, int enable) -{ - int offset = LOW_DETECT_OFFSET + (gpio/32); - int shift = (gpio%32); - - if (enable) - *(gpio_map+offset) |= 1 << shift; - else - *(gpio_map+offset) &= ~(1 << shift); - clear_event_detect(gpio); -} - -void set_pullupdn(int gpio, int pud) -{ - // Check GPIO register - int is2711 = *(gpio_map+PULLUPDN_OFFSET_2711_3) != 0x6770696f; - if (is2711) { - // Pi 4 Pull-up/down method - int pullreg = PULLUPDN_OFFSET_2711_0 + (gpio >> 4); - int pullshift = (gpio & 0xf) << 1; - unsigned int pullbits; - unsigned int pull = 0; - switch (pud) { - case PUD_OFF: pull = 0; break; - case PUD_UP: pull = 1; break; - case PUD_DOWN: pull = 2; break; - default: pull = 0; // switch PUD to OFF for other values - } - pullbits = *(gpio_map + pullreg); - pullbits &= ~(3 << pullshift); - pullbits |= (pull << pullshift); - *(gpio_map + pullreg) = pullbits; - } else { - // Legacy Pull-up/down method - int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32); - int shift = (gpio%32); - - if (pud == PUD_DOWN) { - *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN; - } else if (pud == PUD_UP) { - *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP; - } else { // pud == PUD_OFF - *(gpio_map+PULLUPDN_OFFSET) &= ~3; - } - short_wait(); - *(gpio_map+clk_offset) = 1 << shift; - short_wait(); - *(gpio_map+PULLUPDN_OFFSET) &= ~3; - *(gpio_map+clk_offset) = 0; - } -} - -void setup_gpio(int gpio, int direction, int pud) -{ - int offset = FSEL_OFFSET + (gpio/10); - int shift = (gpio%10)*3; - - set_pullupdn(gpio, pud); - if (direction == OUTPUT) - *(gpio_map+offset) = (*(gpio_map+offset) & ~(7< -int gpio_function(int gpio) -{ - int offset = FSEL_OFFSET + (gpio/10); - int shift = (gpio%10)*3; - int value = *(gpio_map+offset); - value >>= shift; - value &= 7; - return value; // 0=input, 1=output, 4=alt0 -} - -void output_gpio(int gpio, int value) -{ - int offset, shift; - - if (value) // value == HIGH - offset = SET_OFFSET + (gpio/32); - else // value == LOW - offset = CLR_OFFSET + (gpio/32); - - shift = (gpio%32); - - *(gpio_map+offset) = 1 << shift; -} - -int input_gpio(int gpio) -{ - int offset, value, mask; - - offset = PINLEVEL_OFFSET + (gpio/32); - mask = (1 << gpio%32); - value = *(gpio_map+offset) & mask; - return value; -} - -void cleanup(void) -{ - munmap((void *)gpio_map, BLOCK_SIZE); -} diff --git a/rotary_encoder_gpio_core/source/c_gpio.h b/rotary_encoder_gpio_core/source/c_gpio.h deleted file mode 100755 index e54b4c0..0000000 --- a/rotary_encoder_gpio_core/source/c_gpio.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -Copyright (c) 2012-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -int setup(void); -void setup_gpio(int gpio, int direction, int pud); -int gpio_function(int gpio); -void output_gpio(int gpio, int value); -int input_gpio(int gpio); -void set_rising_event(int gpio, int enable); -void set_falling_event(int gpio, int enable); -void set_high_event(int gpio, int enable); -void set_low_event(int gpio, int enable); -int eventdetected(int gpio); -void cleanup(void); - -#define SETUP_OK 0 -#define SETUP_DEVMEM_FAIL 1 -#define SETUP_MALLOC_FAIL 2 -#define SETUP_MMAP_FAIL 3 -#define SETUP_CPUINFO_FAIL 4 -#define SETUP_NO_PERI_ADDR 5 - -#define INPUT 1 // is really 0 for control register! -#define OUTPUT 0 // is really 1 for control register! -#define ALT0 4 - -#define HIGH 1 -#define LOW 0 - -#define PUD_OFF 0 -#define PUD_DOWN 1 -#define PUD_UP 2 diff --git a/rotary_encoder_gpio_core/source/common.c b/rotary_encoder_gpio_core/source/common.c deleted file mode 100755 index fd9e549..0000000 --- a/rotary_encoder_gpio_core/source/common.c +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright (c) 2013-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "Python.h" -#include "c_gpio.h" -#include "common.h" - -int gpio_mode = MODE_UNKNOWN; -const int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -const int pin_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -const int pin_to_gpio_rev3[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 }; -const int (*pin_to_gpio)[41]; -int gpio_direction[54]; -rpi_info rpiinfo; -int setup_error = 0; -int module_setup = 0; - -int check_gpio_priv(void) -{ - // check module has been imported cleanly - if (setup_error) - { - PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); - return 1; - } - - // check mmap setup has worked - if (!module_setup) - { - PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); - return 2; - } - return 0; -} - -int get_gpio_number(int channel, unsigned int *gpio) -{ - // check setmode() has been run - if (gpio_mode != BOARD && gpio_mode != BCM) - { - PyErr_SetString(PyExc_RuntimeError, "Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)"); - return 3; - } - - // check channel number is in range - if ( (gpio_mode == BCM && (channel < 0 || channel > 53)) - || (gpio_mode == BOARD && (channel < 1 || channel > 26) && rpiinfo.p1_revision != 3) - || (gpio_mode == BOARD && (channel < 1 || channel > 40) && rpiinfo.p1_revision == 3) ) - { - PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a Raspberry Pi"); - return 4; - } - - // convert channel to gpio - if (gpio_mode == BOARD) - { - if (*(*pin_to_gpio+channel) == -1) - { - PyErr_SetString(PyExc_ValueError, "The channel sent is invalid on a Raspberry Pi"); - return 5; - } else { - *gpio = *(*pin_to_gpio+channel); - } - } - else // gpio_mode == BCM - { - *gpio = channel; - } - - return 0; -} diff --git a/rotary_encoder_gpio_core/source/common.h b/rotary_encoder_gpio_core/source/common.h deleted file mode 100755 index e44eb41..0000000 --- a/rotary_encoder_gpio_core/source/common.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright (c) 2013-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "cpuinfo.h" - -#define MODE_UNKNOWN -1 -#define BOARD 10 -#define BCM 11 -#define SERIAL 40 -#define SPI 41 -#define I2C 42 -#define PWM 43 - -extern int gpio_mode; -extern const int pin_to_gpio_rev1[41]; -extern const int pin_to_gpio_rev2[41]; -extern const int pin_to_gpio_rev3[41]; -extern const int (*pin_to_gpio)[41]; -extern int gpio_direction[54]; -extern rpi_info rpiinfo; -extern int setup_error; -extern int module_setup; - -int check_gpio_priv(void); -int get_gpio_number(int channel, unsigned int *gpio); diff --git a/rotary_encoder_gpio_core/source/constants.c b/rotary_encoder_gpio_core/source/constants.c deleted file mode 100755 index 91f7684..0000000 --- a/rotary_encoder_gpio_core/source/constants.c +++ /dev/null @@ -1,99 +0,0 @@ -/* -Copyright (c) 2013-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "Python.h" -#include "constants.h" -#include "common.h" -#include "c_gpio.h" -#include "event_gpio.h" - -PyObject *high; -PyObject *low; -PyObject *input; -PyObject *output; -PyObject *pwm; -PyObject *serial; -PyObject *i2c; -PyObject *spi; -PyObject *unknown; -PyObject *board; -PyObject *bcm; -PyObject *pud_off; -PyObject *pud_up; -PyObject *pud_down; -PyObject *rising_edge; -PyObject *falling_edge; -PyObject *both_edge; - -void define_constants(PyObject *module) -{ - high = Py_BuildValue("i", HIGH); - PyModule_AddObject(module, "HIGH", high); - - low = Py_BuildValue("i", LOW); - PyModule_AddObject(module, "LOW", low); - - output = Py_BuildValue("i", OUTPUT); - PyModule_AddObject(module, "OUT", output); - - input = Py_BuildValue("i", INPUT); - PyModule_AddObject(module, "IN", input); - - pwm = Py_BuildValue("i", PWM); - PyModule_AddObject(module, "HARD_PWM", pwm); - - serial = Py_BuildValue("i", SERIAL); - PyModule_AddObject(module, "SERIAL", serial); - - i2c = Py_BuildValue("i", I2C); - PyModule_AddObject(module, "I2C", i2c); - - spi = Py_BuildValue("i", SPI); - PyModule_AddObject(module, "SPI", spi); - - unknown = Py_BuildValue("i", MODE_UNKNOWN); - PyModule_AddObject(module, "UNKNOWN", unknown); - - board = Py_BuildValue("i", BOARD); - PyModule_AddObject(module, "BOARD", board); - - bcm = Py_BuildValue("i", BCM); - PyModule_AddObject(module, "BCM", bcm); - - pud_off = Py_BuildValue("i", PUD_OFF + PY_PUD_CONST_OFFSET); - PyModule_AddObject(module, "PUD_OFF", pud_off); - - pud_up = Py_BuildValue("i", PUD_UP + PY_PUD_CONST_OFFSET); - PyModule_AddObject(module, "PUD_UP", pud_up); - - pud_down = Py_BuildValue("i", PUD_DOWN + PY_PUD_CONST_OFFSET); - PyModule_AddObject(module, "PUD_DOWN", pud_down); - - rising_edge = Py_BuildValue("i", RISING_EDGE + PY_EVENT_CONST_OFFSET); - PyModule_AddObject(module, "RISING", rising_edge); - - falling_edge = Py_BuildValue("i", FALLING_EDGE + PY_EVENT_CONST_OFFSET); - PyModule_AddObject(module, "FALLING", falling_edge); - - both_edge = Py_BuildValue("i", BOTH_EDGE + PY_EVENT_CONST_OFFSET); - PyModule_AddObject(module, "BOTH", both_edge); -} diff --git a/rotary_encoder_gpio_core/source/constants.h b/rotary_encoder_gpio_core/source/constants.h deleted file mode 100755 index cb0dc73..0000000 --- a/rotary_encoder_gpio_core/source/constants.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright (c) 2013-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#define PY_PUD_CONST_OFFSET 20 -#define PY_EVENT_CONST_OFFSET 30 - -extern PyObject *high; -extern PyObject *low; -extern PyObject *input; -extern PyObject *output; -extern PyObject *pwm; -extern PyObject *serial; -extern PyObject *i2c; -extern PyObject *spi; -extern PyObject *unknown; -extern PyObject *board; -extern PyObject *bcm; -extern PyObject *pud_off; -extern PyObject *pud_up; -extern PyObject *pud_down; -extern PyObject *rising_edge; -extern PyObject *falling_edge; -extern PyObject *both_edge; - -void define_constants(PyObject *module); diff --git a/rotary_encoder_gpio_core/source/cpuinfo.c b/rotary_encoder_gpio_core/source/cpuinfo.c deleted file mode 100755 index 426d4f6..0000000 --- a/rotary_encoder_gpio_core/source/cpuinfo.c +++ /dev/null @@ -1,273 +0,0 @@ -/* -Copyright (c) 2012-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/* See the following for up to date information: - *https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-revision-codes - */ - -#include -#include -#include -#include -#include -#include "cpuinfo.h" - -int get_rpi_info(rpi_info *info) -{ - FILE *fp; - char buffer[1024]; - char hardware[1024]; - char revision[1024]; - int found = 0; - int len; - - if ((fp = fopen("/proc/device-tree/system/linux,revision", "r"))) { - uint32_t n; - if (fread(&n, sizeof(n), 1, fp) != 1) { - fclose(fp); - return -1; - } - sprintf(revision, "%x", ntohl(n)); - found = 1; - } - else if ((fp = fopen("/proc/cpuinfo", "r"))) { - while(!feof(fp) && fgets(buffer, sizeof(buffer), fp)) { - sscanf(buffer, "Hardware : %s", hardware); - if (strcmp(hardware, "BCM2708") == 0 || - strcmp(hardware, "BCM2709") == 0 || - strcmp(hardware, "BCM2711") == 0 || - strcmp(hardware, "BCM2835") == 0 || - strcmp(hardware, "BCM2836") == 0 || - strcmp(hardware, "BCM2837") == 0 ) { - found = 1; - } - sscanf(buffer, "Revision : %s", revision); - } - } - else - return -1; - fclose(fp); - - if (!found) - return -1; - - if ((len = strlen(revision)) == 0) - return -1; - - if (len >= 6 && strtol((char[]){revision[len-6],0}, NULL, 16) & 8) { - // new scheme - //info->rev = revision[len-1]-'0'; - strcpy(info->revision, revision); - switch (revision[len-3]) { - case '0' : - switch (revision[len-2]) { - case '0': info->type = "Model A"; info->p1_revision = 2; break; - case '1': info->type = "Model B"; info->p1_revision = 2; break; - case '2': info->type = "Model A+"; info->p1_revision = 3; break; - case '3': info->type = "Model B+"; info->p1_revision = 3; break; - case '4': info->type = "Pi 2 Model B"; info->p1_revision = 3; break; - case '5': info->type = "Alpha"; info->p1_revision = 3; break; - case '6': info->type = "Compute Module 1"; info->p1_revision = 0; break; - case '8': info->type = "Pi 3 Model B"; info->p1_revision = 3; break; - case '9': info->type = "Zero"; info->p1_revision = 3; break; - case 'a': info->type = "Compute Module 3"; info->p1_revision = 0; break; - case 'c': info->type = "Zero W"; info->p1_revision = 3; break; - case 'd': info->type = "Pi 3 Model B+"; info->p1_revision = 3; break; - case 'e': info->type = "Pi 3 Model A+"; info->p1_revision = 3; break; - default : info->type = "Unknown"; info->p1_revision = 3; break; - } break; - case '1': - switch (revision[len-2]) { - case '0': info->type = "Compute Module 3+"; info->p1_revision = 0; break; - case '1': info->type = "Pi 4 Model B"; info->p1_revision = 3; break; - case '2': info->type = "Zero 2 W"; info->p1_revision = 3; break; - case '3': info->type = "Pi 400"; info->p1_revision = 3; break; - case '4': info->type = "Compute Module 4"; info->p1_revision = 0; break; - default : info->type = "Unknown"; info->p1_revision = 3; break; - } break; - default: info->type = "Unknown"; info->p1_revision = 3; break; - } - - switch (revision[len-4]) { - case '0': info->processor = "BCM2835"; break; - case '1': info->processor = "BCM2836"; break; - case '2': info->processor = "BCM2837"; break; - case '3': info->processor = "BCM2711"; break; - default : info->processor = "Unknown"; break; - } - switch (revision[len-5]) { - case '0': info->manufacturer = "Sony UK"; break; - case '1': info->manufacturer = "Egoman"; break; - case '2': info->manufacturer = "Embest"; break; - case '3': info->manufacturer = "Sony Japan"; break; - case '4': info->manufacturer = "Embest"; break; - case '5': info->manufacturer = "Stadium"; break; - default : info->manufacturer = "Unknown"; break; - } - switch (strtol((char[]){revision[len-6],0}, NULL, 16) & 7) { - case 0: info->ram = "256M"; break; - case 1: info->ram = "512M"; break; - case 2: info->ram = "1G"; break; - case 3: info->ram = "2G"; break; - case 4: info->ram = "4G"; break; - case 5: info->ram = "8G"; break; - default: info->ram = "Unknown"; break; - } - } else { - // old scheme - info->ram = "Unknown"; - info->manufacturer = "Unknown"; - info->processor = "Unknown"; - info->type = "Unknown"; - strcpy(info->revision, revision); - - uint64_t rev; - sscanf(revision, "%llx", &rev); - rev = rev & 0xefffffff; // ignore preceeding 1000 for overvolt - - if (rev == 0x0002 || rev == 0x0003) { - info->type = "Model B"; - info->p1_revision = 1; - info->ram = "256M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (rev == 0x0004) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x0005) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if (rev == 0x0006) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (rev == 0x0007) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (rev == 0x0008) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x0009) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if (rev == 0x000d) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (rev == 0x000e) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x000f) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if (rev == 0x0010) { - info->type = "Model B+"; - info->p1_revision = 3; - info->ram = "512M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x0011) { - info->type = "Compute Module 1"; - info->p1_revision = 0; - info->ram = "512M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x0012) { - info->type = "Model A+"; - info->p1_revision = 3; - info->ram = "256M"; - info->manufacturer = "Sony UK"; - info->processor = "BCM2835"; - } else if (rev == 0x0013) { - info->type = "Model B+"; - info->p1_revision = 3; - info->ram = "512M"; - info->manufacturer = "Embest"; - info->processor = "BCM2835"; - } else if (rev == 0x0014) { - info->type = "Compute Module 1"; - info->p1_revision = 0; - info->ram = "512M"; - info->manufacturer = "Embest"; - info->processor = "BCM2835"; - } else if (rev == 0x0015) { - info->type = "Model A+"; - info->p1_revision = 3; - info->ram = "Unknown"; - info->manufacturer = "Embest"; - info->processor = "BCM2835"; - } else { // don't know - assume revision 3 p1 connector - info->p1_revision = 3; - } - } - return 0; -} - -/* - -32 bits -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 -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 - -pi2 = 1<<23 | 2<<20 | 1<<12 | 4<<4 = 0xa01040 - --------------------- - -SRRR MMMM PPPP TTTT TTTT VVVV - -S scheme (0=old, 1=new) -R RAM (0=256, 1=512, 2=1024) -M manufacturer (0='SONY',1='EGOMAN',2='EMBEST',3='UNKNOWN',4='EMBEST') -P processor (0=2835, 1=2836 2=2837) -T type (0='A', 1='B', 2='A+', 3='B+', 4='Pi 2 B', 5='Alpha', 6='Compute Module') -V revision (0-15) - -*/ diff --git a/rotary_encoder_gpio_core/source/cpuinfo.h b/rotary_encoder_gpio_core/source/cpuinfo.h deleted file mode 100755 index 6f476b1..0000000 --- a/rotary_encoder_gpio_core/source/cpuinfo.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright (c) 2012-2015 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#ifndef CPUINFO_H -#define CPUINFO_H -typedef struct -{ - int p1_revision; - char *ram; - char *manufacturer; - char *processor; - char *type; - char revision[1024]; -} rpi_info; -#endif /* CPUINFO_H */ - -int get_rpi_info(rpi_info *info); diff --git a/rotary_encoder_gpio_core/source/event_gpio.c b/rotary_encoder_gpio_core/source/event_gpio.c deleted file mode 100755 index f0e745c..0000000 --- a/rotary_encoder_gpio_core/source/event_gpio.c +++ /dev/null @@ -1,600 +0,0 @@ -/* -Copyright (c) 2013-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "event_gpio.h" - -const char *stredge[4] = {"none", "rising", "falling", "both"}; - -struct gpios -{ - unsigned int gpio; - int value_fd; - int exported; - int edge; - int initial_thread; - int initial_wait; - int thread_added; - int bouncetime; - unsigned long long lastcall; - struct gpios *next; -}; -struct gpios *gpio_list = NULL; - -// event callbacks -struct callback -{ - unsigned int gpio; - void (*func)(unsigned int gpio, int state); - struct callback *next; -}; -struct callback *callbacks = NULL; - -int event_occurred[54] = { 0 }; -int thread_running = 0; -int epfd_thread = -1; -int epfd_blocking = -1; - -/************* /sys/class/gpio functions ************/ -#define x_write(fd, buf, len) do { \ - size_t x_write_len = (len); \ - \ - if ((size_t)write((fd), (buf), x_write_len) != x_write_len) { \ - close(fd); \ - return (-1); \ - } \ -} while (/* CONSTCOND */ 0) - -int gpio_export(unsigned int gpio) -{ - int fd, len; - char str_gpio[3]; - char filename[33]; - - snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d", gpio); - - /* return if gpio already exported */ - if (access(filename, F_OK) != -1) { - return 0; - } - - if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0) { - return -1; - } - - len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); - x_write(fd, str_gpio, len); - close(fd); - - return 0; -} - -int gpio_unexport(unsigned int gpio) -{ - int fd, len; - char str_gpio[3]; - - if ((fd = open("/sys/class/gpio/unexport", O_WRONLY)) < 0) - return -1; - - len = snprintf(str_gpio, sizeof(str_gpio), "%d", gpio); - x_write(fd, str_gpio, len); - close(fd); - - return 0; -} - -int gpio_set_direction(unsigned int gpio, unsigned int in_flag) -{ - int retry; - struct timespec delay; - int fd; - char filename[33]; - - snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); - - // retry waiting for udev to set correct file permissions - delay.tv_sec = 0; - delay.tv_nsec = 10000000L; // 10ms - for (retry=0; retry<100; retry++) { - if ((fd = open(filename, O_WRONLY)) >= 0) - break; - nanosleep(&delay, NULL); - } - if (retry >= 100) - return -1; - - if (in_flag) - x_write(fd, "in", 3); - else - x_write(fd, "out", 4); - - close(fd); - return 0; -} - -int gpio_set_edge(unsigned int gpio, unsigned int edge) -{ - int fd; - char filename[28]; - - snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/edge", gpio); - - if ((fd = open(filename, O_WRONLY)) < 0) - return -1; - - x_write(fd, stredge[edge], strlen(stredge[edge]) + 1); - close(fd); - return 0; -} - -int open_value_file(unsigned int gpio) -{ - int fd; - char filename[29]; - - // create file descriptor of value file - snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); - if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) - return -1; - return fd; -} - -/********* gpio list functions **********/ -struct gpios *get_gpio(unsigned int gpio) -{ - struct gpios *g = gpio_list; - while (g != NULL) { - if (g->gpio == gpio) - return g; - g = g->next; - } - return NULL; -} - -struct gpios *get_gpio_from_value_fd(int fd) -{ - struct gpios *g = gpio_list; - while (g != NULL) { - if (g->value_fd == fd) - return g; - g = g->next; - } - return NULL; -} - -struct gpios *new_gpio(unsigned int gpio) -{ - struct gpios *new_gpio; - - new_gpio = malloc(sizeof(struct gpios)); - if (new_gpio == 0) { - return NULL; // out of memory - } - - new_gpio->gpio = gpio; - if (gpio_export(gpio) != 0) { - free(new_gpio); - return NULL; - } - new_gpio->exported = 1; - - if (gpio_set_direction(gpio,1) != 0) { // 1==input - free(new_gpio); - return NULL; - } - - if ((new_gpio->value_fd = open_value_file(gpio)) == -1) { - gpio_unexport(gpio); - free(new_gpio); - return NULL; - } - - new_gpio->initial_thread = 1; - new_gpio->initial_wait = 1; - new_gpio->bouncetime = -666; - new_gpio->lastcall = 0; - new_gpio->thread_added = 0; - - if (gpio_list == NULL) { - new_gpio->next = NULL; - } else { - new_gpio->next = gpio_list; - } - gpio_list = new_gpio; - return new_gpio; -} - -void delete_gpio(unsigned int gpio) -{ - struct gpios *g = gpio_list; - struct gpios *prev = NULL; - - while (g != NULL) { - if (g->gpio == gpio) { - if (prev == NULL) - gpio_list = g->next; - else - prev->next = g->next; - free(g); - return; - } else { - prev = g; - g = g->next; - } - } -} - -int gpio_event_added(unsigned int gpio) -{ - struct gpios *g = gpio_list; - while (g != NULL) { - if (g->gpio == gpio) - return g->edge; - g = g->next; - } - return 0; -} - -/******* callback list functions ********/ -int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio, int state)) -{ - struct callback *cb = callbacks; - struct callback *new_cb; - - new_cb = malloc(sizeof(struct callback)); - if (new_cb == 0) - return -1; // out of memory - - new_cb->gpio = gpio; - new_cb->func = func; - new_cb->next = NULL; - - if (callbacks == NULL) { - // start new list - callbacks = new_cb; - } else { - // add to end of list - while (cb->next != NULL) - cb = cb->next; - cb->next = new_cb; - } - return 0; -} - -int callback_exists(unsigned int gpio) -{ - struct callback *cb = callbacks; - while (cb != NULL) { - if (cb->gpio == gpio) - return 1; - cb = cb->next; - } - return 0; -} - -void run_callbacks(unsigned int gpio, int state) -{ - struct callback *cb = callbacks; - while (cb != NULL) - { - if (cb->gpio == gpio) - cb->func(cb->gpio, state); - cb = cb->next; - } -} - -void remove_callbacks(unsigned int gpio) -{ - struct callback *cb = callbacks; - struct callback *temp; - struct callback *prev = NULL; - - while (cb != NULL) - { - if (cb->gpio == gpio) - { - if (prev == NULL) - callbacks = cb->next; - else - prev->next = cb->next; - temp = cb; - cb = cb->next; - free(temp); - } else { - prev = cb; - cb = cb->next; - } - } -} - -void *poll_thread(void *threadarg) -{ - struct epoll_event events; - char buf; - struct timeval tv_timenow; - unsigned long long timenow; - struct gpios *g; - int n; - - thread_running = 1; - while (thread_running) { - n = epoll_wait(epfd_thread, &events, 1, -1); - if (n > 0) { - lseek(events.data.fd, 0, SEEK_SET); - if (read(events.data.fd, &buf, 1) != 1) { - thread_running = 0; - pthread_exit(NULL); - } - g = get_gpio_from_value_fd(events.data.fd); - if (g->initial_thread) { // ignore first epoll trigger - g->initial_thread = 0; - } else { - gettimeofday(&tv_timenow, NULL); - timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; - if (g->bouncetime == -666 || timenow - g->lastcall > (unsigned int)g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) { - g->lastcall = timenow; - event_occurred[g->gpio] = 1; - run_callbacks(g->gpio, input_gpio(g->gpio)); - } - } - } else if (n == -1) { - /* If a signal is received while we are waiting, - epoll_wait will return with an EINTR error. - Just try again in that case. */ - if (errno == EINTR) { - continue; - } - thread_running = 0; - pthread_exit(NULL); - } - } - thread_running = 0; - pthread_exit(NULL); -} - -void remove_edge_detect(unsigned int gpio) -{ - struct epoll_event ev; - struct gpios *g = get_gpio(gpio); - - if (g == NULL) - return; - - // delete epoll of fd - - ev.events = EPOLLIN | EPOLLET | EPOLLPRI; - ev.data.fd = g->value_fd; - epoll_ctl(epfd_thread, EPOLL_CTL_DEL, g->value_fd, &ev); - - // delete callbacks for gpio - remove_callbacks(gpio); - - // btc fixme - check return result?? - gpio_set_edge(gpio, NO_EDGE); - g->edge = NO_EDGE; - - if (g->value_fd != -1) - close(g->value_fd); - - // btc fixme - check return result?? - gpio_unexport(gpio); - event_occurred[gpio] = 0; - - delete_gpio(gpio); -} - -int event_detected(unsigned int gpio) -{ - if (event_occurred[gpio]) { - event_occurred[gpio] = 0; - return 1; - } else { - return 0; - } -} - -void event_cleanup(int gpio) -// gpio of -666 means clean every channel used -{ - struct gpios *g = gpio_list; - struct gpios *next_gpio = NULL; - - while (g != NULL) { - next_gpio = g->next; - if ((gpio == -666) || ((int)g->gpio == gpio)) - remove_edge_detect(g->gpio); - g = next_gpio; - } - if (gpio_list == NULL) { - if (epfd_blocking != -1) { - close(epfd_blocking); - epfd_blocking = -1; - } - if (epfd_thread != -1) { - close(epfd_thread); - epfd_thread = -1; - } - thread_running = 0; - } -} - -void event_cleanup_all(void) -{ - event_cleanup(-666); -} - -int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime) -// return values: -// 0 - Success -// 1 - Edge detection already added -// 2 - Other error -{ - pthread_t threads; - struct epoll_event ev; - long t = 0; - struct gpios *g; - int i = -1; - - i = gpio_event_added(gpio); - if (i == 0) { // event not already added - if ((g = new_gpio(gpio)) == NULL) { - return 2; - } - - gpio_set_edge(gpio, edge); - g->edge = edge; - g->bouncetime = bouncetime; - } else if (i == (int)edge) { // get existing event - g = get_gpio(gpio); - if ((bouncetime != -666 && g->bouncetime != bouncetime) || // different event bouncetime used - (g->thread_added)) // event already added - return 1; - } else { - return 1; - } - - // create epfd_thread if not already open - if ((epfd_thread == -1) && ((epfd_thread = epoll_create(1)) == -1)) - return 2; - - // add to epoll fd - ev.events = EPOLLIN | EPOLLET | EPOLLPRI; - ev.data.fd = g->value_fd; - if (epoll_ctl(epfd_thread, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { - remove_edge_detect(gpio); - return 2; - } - g->thread_added = 1; - - // start poll thread if it is not already running - if (!thread_running) { - if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) { - remove_edge_detect(gpio); - return 2; - } - } - return 0; -} - -int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout) -// return values: -// 1 - Success (edge detected) -// 0 - Timeout -// -1 - Edge detection already added -// -2 - Other error -{ - int n, ed; - struct epoll_event events, ev; - char buf; - struct gpios *g = NULL; - struct timeval tv_timenow; - unsigned long long timenow; - int finished = 0; - int initial_edge = 1; - - if (callback_exists(gpio)) - return -1; - - // add gpio if it has not been added already - ed = gpio_event_added(gpio); - if (ed == (int)edge) { // get existing record - g = get_gpio(gpio); - if (g->bouncetime != -666 && g->bouncetime != bouncetime) { - return -1; - } - } else if (ed == NO_EDGE) { // not found so add event - if ((g = new_gpio(gpio)) == NULL) { - return -2; - } - gpio_set_edge(gpio, edge); - g->edge = edge; - g->bouncetime = bouncetime; - } else { // ed != edge - event for a different edge - g = get_gpio(gpio); - gpio_set_edge(gpio, edge); - g->edge = edge; - g->bouncetime = bouncetime; - g->initial_wait = 1; - } - - // create epfd_blocking if not already open - if ((epfd_blocking == -1) && ((epfd_blocking = epoll_create(1)) == -1)) { - return -2; - } - - // add to epoll fd - ev.events = EPOLLIN | EPOLLET | EPOLLPRI; - ev.data.fd = g->value_fd; - if (epoll_ctl(epfd_blocking, EPOLL_CTL_ADD, g->value_fd, &ev) == -1) { - return -2; - } - - // wait for edge - while (!finished) { - n = epoll_wait(epfd_blocking, &events, 1, timeout); - if (n == -1) { - /* If a signal is received while we are waiting, - epoll_wait will return with an EINTR error. - Just try again in that case. */ - if (errno == EINTR) { - continue; - } - epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); - return -2; - } - if (initial_edge) { // first time triggers with current state, so ignore - initial_edge = 0; - } else { - gettimeofday(&tv_timenow, NULL); - timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; - if (g->bouncetime == -666 || timenow - g->lastcall > (unsigned int)g->bouncetime*1000 || g->lastcall == 0 || g->lastcall > timenow) { - g->lastcall = timenow; - finished = 1; - } - } - } - - // check event was valid - if (n > 0) { - lseek(events.data.fd, 0, SEEK_SET); - if ((read(events.data.fd, &buf, 1) != 1) || (events.data.fd != g->value_fd)) { - epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); - return -2; - } - } - - epoll_ctl(epfd_blocking, EPOLL_CTL_DEL, g->value_fd, &ev); - if (n == 0) { - return 0; // timeout - } else { - return 1; // edge found - } -} diff --git a/rotary_encoder_gpio_core/source/event_gpio.h b/rotary_encoder_gpio_core/source/event_gpio.h deleted file mode 100755 index 64f2742..0000000 --- a/rotary_encoder_gpio_core/source/event_gpio.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright (c) 2013-2015 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#define NO_EDGE 0 -#define RISING_EDGE 1 -#define FALLING_EDGE 2 -#define BOTH_EDGE 3 - -int add_edge_detect(unsigned int gpio, unsigned int edge, int bouncetime); -void remove_edge_detect(unsigned int gpio); -int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio, int state)); -int event_detected(unsigned int gpio); -int gpio_event_added(unsigned int gpio); -int event_initialise(void); -void event_cleanup(int gpio); -void event_cleanup_all(void); -int blocking_wait_for_edge(unsigned int gpio, unsigned int edge, int bouncetime, int timeout); diff --git a/rotary_encoder_gpio_core/source/py_gpio.c b/rotary_encoder_gpio_core/source/py_gpio.c deleted file mode 100755 index 18d4afe..0000000 --- a/rotary_encoder_gpio_core/source/py_gpio.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* -Copyright (c) 2012-2021 Ben Croston - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "Python.h" -#include "c_gpio.h" -#include "event_gpio.h" -#include "cpuinfo.h" -#include "constants.h" -#include "common.h" - -static PyObject *rpi_revision; // deprecated -static PyObject *board_info; -static int gpio_warnings = 1; - -struct py_callback -{ - unsigned int gpio; - PyObject *py_cb; - struct py_callback *next; -}; -static struct py_callback *py_callbacks = NULL; - -static int mmap_gpio_mem(void) -{ - int result; - - if (module_setup) - return 0; - - result = setup(); - if (result == SETUP_DEVMEM_FAIL) - { - PyErr_SetString(PyExc_RuntimeError, "No access to /dev/mem. Try running as root!"); - return 1; - } else if (result == SETUP_MALLOC_FAIL) { - PyErr_NoMemory(); - return 2; - } else if (result == SETUP_MMAP_FAIL) { - PyErr_SetString(PyExc_RuntimeError, "Mmap of GPIO registers failed"); - return 3; - } else if (result == SETUP_CPUINFO_FAIL) { - PyErr_SetString(PyExc_RuntimeError, "Unable to open /proc/cpuinfo"); - return 4; - } else if (result == SETUP_NO_PERI_ADDR) { - PyErr_SetString(PyExc_RuntimeError, "Cannot determine SOC peripheral base address"); - return 5; - } else { // result == SETUP_OK - module_setup = 1; - return 0; - } -} - -// python function cleanup(channel=None) -static PyObject *py_cleanup(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int i; - int chancount = -666; - int found = 0; - int channel = -666; - unsigned int gpio; - PyObject *chanlist = NULL; - PyObject *chantuple = NULL; - PyObject *tempobj; - static char *kwlist[] = {"channel", NULL}; - - void cleanup_one(void) - { - // clean up any /sys/class exports - event_cleanup(gpio); - - // set everything back to input - if (gpio_direction[gpio] != -1) { - setup_gpio(gpio, INPUT, PUD_OFF); - gpio_direction[gpio] = -1; - found = 1; - } - } - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &chanlist)) - return NULL; - - if (chanlist == NULL) { // channel kwarg not set - // do nothing - } else if (PyLong_Check(chanlist)) { - channel = (int)PyLong_AsLong(chanlist); - if (PyErr_Occurred()) - return NULL; - chanlist = NULL; - } else if (PyList_Check(chanlist)) { - chancount = PyList_Size(chanlist); - } else if (PyTuple_Check(chanlist)) { - chantuple = chanlist; - chanlist = NULL; - chancount = PyTuple_Size(chantuple); - } else { - // raise exception - PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); - return NULL; - } - - if (module_setup && !setup_error) { - if (channel == -666 && chancount == -666) { // channel not set - cleanup everything - // clean up any /sys/class exports - event_cleanup_all(); - - // set everything back to input - for (i=0; i<54; i++) { - if (gpio_direction[i] != -1) { - setup_gpio(i, INPUT, PUD_OFF); - gpio_direction[i] = -1; - found = 1; - } - } - gpio_mode = MODE_UNKNOWN; - } else if (channel != -666) { // channel was an int indicating single channel - if (get_gpio_number(channel, &gpio)) - return NULL; - cleanup_one(); - } else { // channel was a list/tuple - for (i=0; i= 3 - if (PyLong_Check(chanlist)) { - channel = (int)PyLong_AsLong(chanlist); -#else - if (PyInt_Check(chanlist)) { - channel = (int)PyInt_AsLong(chanlist); -#endif - if (PyErr_Occurred()) - return NULL; - chanlist = NULL; - } else if (PyList_Check(chanlist)) { - // do nothing - } else if (PyTuple_Check(chanlist)) { - chantuple = chanlist; - chanlist = NULL; - } else { - PyErr_SetString(PyExc_ValueError, "Channel must be an integer or list/tuple of integers"); - return NULL; - } - -#if PY_MAJOR_VERSION >= 3 - if (PyLong_Check(valuelist)) { - value = (int)PyLong_AsLong(valuelist); -#else - if (PyInt_Check(valuelist)) { - value = (int)PyInt_AsLong(valuelist); -#endif - if (PyErr_Occurred()) - return NULL; - valuelist = NULL; - } else if (PyList_Check(valuelist)) { - // do nothing - } else if (PyTuple_Check(valuelist)) { - valuetuple = valuelist; - valuelist = NULL; - } else { - PyErr_SetString(PyExc_ValueError, "Value must be an integer/boolean or a list/tuple of integers/booleans"); - return NULL; - } - - if (chanlist) - chancount = PyList_Size(chanlist); - if (chantuple) - chancount = PyTuple_Size(chantuple); - if (valuelist) - valuecount = PyList_Size(valuelist); - if (valuetuple) - valuecount = PyTuple_Size(valuetuple); - if ((chancount != -1 && chancount != valuecount && valuecount != -1) || (chancount == -1 && valuecount != -1)) { - PyErr_SetString(PyExc_RuntimeError, "Number of channels != number of values"); - return NULL; - } - - if (chancount == -1) { - if (!output()) - return NULL; - Py_RETURN_NONE; - } - - for (i=0; i= 3 - if (PyLong_Check(tempobj)) { - channel = (int)PyLong_AsLong(tempobj); -#else - if (PyInt_Check(tempobj)) { - channel = (int)PyInt_AsLong(tempobj); -#endif - if (PyErr_Occurred()) - return NULL; - } else { - PyErr_SetString(PyExc_ValueError, "Channel must be an integer"); - return NULL; - } - - // get value - if (valuecount > 0) { - if (valuelist) { - if ((tempobj = PyList_GetItem(valuelist, i)) == NULL) { - return NULL; - } - } else { // assume valuetuple - if ((tempobj = PyTuple_GetItem(valuetuple, i)) == NULL) { - return NULL; - } - } -#if PY_MAJOR_VERSION >= 3 - if (PyLong_Check(tempobj)) { - value = (int)PyLong_AsLong(tempobj); -#else - if (PyInt_Check(tempobj)) { - value = (int)PyInt_AsLong(tempobj); -#endif - if (PyErr_Occurred()) - return NULL; - } else { - PyErr_SetString(PyExc_ValueError, "Value must be an integer or boolean"); - return NULL; - } - } - if (!output()) - return NULL; - } - - Py_RETURN_NONE; -} - -// python function value = input(channel) -static PyObject *py_input_gpio(PyObject *self, PyObject *args) -{ - unsigned int gpio; - int channel; - PyObject *value; - - if (!PyArg_ParseTuple(args, "i", &channel)) - return NULL; - - if (get_gpio_number(channel, &gpio)) - return NULL; - - // check channel is set up as an input or output - if (gpio_direction[gpio] != INPUT && gpio_direction[gpio] != OUTPUT) - { - PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel first"); - return NULL; - } - - if (check_gpio_priv()) - return NULL; - - if (input_gpio(gpio)) { - value = Py_BuildValue("i", HIGH); - } else { - value = Py_BuildValue("i", LOW); - } - return value; -} - -// python function setmode(mode) -static PyObject *py_setmode(PyObject *self, PyObject *args) -{ - int new_mode; - - if (!PyArg_ParseTuple(args, "i", &new_mode)) - return NULL; - - if (gpio_mode != MODE_UNKNOWN && new_mode != gpio_mode) - { - PyErr_SetString(PyExc_ValueError, "A different mode has already been set!"); - return NULL; - } - - if (setup_error) - { - PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); - return NULL; - } - - if (new_mode != BOARD && new_mode != BCM) - { - PyErr_SetString(PyExc_ValueError, "An invalid mode was passed to setmode()"); - return NULL; - } - - if (rpiinfo.p1_revision == 0 && new_mode == BOARD) - { - PyErr_SetString(PyExc_RuntimeError, "BOARD numbering system not applicable on compute module"); - return NULL; - } - - gpio_mode = new_mode; - Py_RETURN_NONE; -} - -// python function getmode() -static PyObject *py_getmode(PyObject *self, PyObject *args) -{ - PyObject *value; - - if (setup_error) - { - PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); - return NULL; - } - - if (gpio_mode == MODE_UNKNOWN) - Py_RETURN_NONE; - - value = Py_BuildValue("i", gpio_mode); - return value; -} - -static unsigned int chan_from_gpio(unsigned int gpio) -{ - int chan; - int chans; - - if (gpio_mode == BCM) - return gpio; - if (rpiinfo.p1_revision == 0) // not applicable for compute module - return -1; - else if (rpiinfo.p1_revision == 1 || rpiinfo.p1_revision == 2) - chans = 26; - else - chans = 40; - for (chan=1; chan<=chans; chan++) - if (*(*pin_to_gpio+chan) == (int)gpio) - return chan; - return -1; -} - -static void run_py_callbacks(unsigned int gpio, int state) -{ - PyObject *result; - PyGILState_STATE gstate; - struct py_callback *cb = py_callbacks; - - while (cb != NULL) - { - if (cb->gpio == gpio) { - // run callback - gstate = PyGILState_Ensure(); - result = PyObject_CallFunction(cb->py_cb, "ii", chan_from_gpio(gpio), state); - if (result == NULL && PyErr_Occurred()){ - PyErr_Print(); - PyErr_Clear(); - } - Py_XDECREF(result); - PyGILState_Release(gstate); - } - cb = cb->next; - } -} - -static int add_py_callback(unsigned int gpio, PyObject *cb_func) -{ - struct py_callback *new_py_cb; - struct py_callback *cb = py_callbacks; - - // add callback to py_callbacks list - new_py_cb = malloc(sizeof(struct py_callback)); - if (new_py_cb == 0) - { - PyErr_NoMemory(); - return -1; - } - new_py_cb->py_cb = cb_func; - Py_XINCREF(cb_func); // Add a reference to new callback - new_py_cb->gpio = gpio; - new_py_cb->next = NULL; - if (py_callbacks == NULL) { - py_callbacks = new_py_cb; - } else { - // add to end of list - while (cb->next != NULL) - cb = cb->next; - cb->next = new_py_cb; - } - add_edge_callback(gpio, run_py_callbacks); - return 0; -} - -// python function add_event_callback(gpio, callback) -static PyObject *py_add_event_callback(PyObject *self, PyObject *args, PyObject *kwargs) -{ - unsigned int gpio; - int channel; - PyObject *cb_func; - char *kwlist[] = {"gpio", "callback", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO|i", kwlist, &channel, &cb_func)) - return NULL; - - if (!PyCallable_Check(cb_func)) - { - PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); - return NULL; - } - - if (get_gpio_number(channel, &gpio)) - return NULL; - - // check channel is set up as an input - if (gpio_direction[gpio] != INPUT) - { - PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); - return NULL; - } - - if (!gpio_event_added(gpio)) - { - PyErr_SetString(PyExc_RuntimeError, "Add event detection using add_event_detect first before adding a callback"); - return NULL; - } - - if (add_py_callback(gpio, cb_func) != 0) - return NULL; - - Py_RETURN_NONE; -} - -// python function add_event_detect(gpio, edge, callback=None, bouncetime=None) -static PyObject *py_add_event_detect(PyObject *self, PyObject *args, PyObject *kwargs) -{ - unsigned int gpio; - int channel, edge, result; - int bouncetime = -666; - PyObject *cb_func = NULL; - char *kwlist[] = {"gpio", "edge", "callback", "bouncetime", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|Oi", kwlist, &channel, &edge, &cb_func, &bouncetime)) - return NULL; - - if (cb_func != NULL && !PyCallable_Check(cb_func)) - { - PyErr_SetString(PyExc_TypeError, "Parameter must be callable"); - return NULL; - } - - if (get_gpio_number(channel, &gpio)) - return NULL; - - // check channel is set up as an input - if (gpio_direction[gpio] != INPUT) - { - PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); - return NULL; - } - - // is edge valid value - edge -= PY_EVENT_CONST_OFFSET; - if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) - { - PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); - return NULL; - } - - if (bouncetime <= 0 && bouncetime != -666) - { - PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); - return NULL; - } - - if (check_gpio_priv()) - return NULL; - - if ((result = add_edge_detect(gpio, edge, bouncetime)) != 0) // starts a thread - { - if (result == 1) - { - PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection already enabled for this GPIO channel"); - return NULL; - } else { - PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection"); - return NULL; - } - } - - if (cb_func != NULL) - if (add_py_callback(gpio, cb_func) != 0) - return NULL; - - Py_RETURN_NONE; -} - -// python function remove_event_detect(gpio) -static PyObject *py_remove_event_detect(PyObject *self, PyObject *args) -{ - unsigned int gpio; - int channel; - struct py_callback *cb = py_callbacks; - struct py_callback *temp; - struct py_callback *prev = NULL; - - if (!PyArg_ParseTuple(args, "i", &channel)) - return NULL; - - if (get_gpio_number(channel, &gpio)) - return NULL; - - // remove all python callbacks for gpio - while (cb != NULL) - { - if (cb->gpio == gpio) - { - Py_XDECREF(cb->py_cb); - if (prev == NULL) - py_callbacks = cb->next; - else - prev->next = cb->next; - temp = cb; - cb = cb->next; - free(temp); - } else { - prev = cb; - cb = cb->next; - } - } - - if (check_gpio_priv()) - return NULL; - - remove_edge_detect(gpio); - - Py_RETURN_NONE; -} - -// python function value = event_detected(channel) -static PyObject *py_event_detected(PyObject *self, PyObject *args) -{ - unsigned int gpio; - int channel; - - if (!PyArg_ParseTuple(args, "i", &channel)) - return NULL; - - if (get_gpio_number(channel, &gpio)) - return NULL; - - if (event_detected(gpio)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -// python function channel = wait_for_edge(channel, edge, bouncetime=None, timeout=None) -static PyObject *py_wait_for_edge(PyObject *self, PyObject *args, PyObject *kwargs) -{ - unsigned int gpio; - int channel, edge, result; - int bouncetime = -666; // None - int timeout = -1; // None - - static char *kwlist[] = {"channel", "edge", "bouncetime", "timeout", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii", kwlist, &channel, &edge, &bouncetime, &timeout)) - return NULL; - - if (get_gpio_number(channel, &gpio)) - return NULL; - - // check channel is setup as an input - if (gpio_direction[gpio] != INPUT) - { - PyErr_SetString(PyExc_RuntimeError, "You must setup() the GPIO channel as an input first"); - return NULL; - } - - // is edge a valid value? - edge -= PY_EVENT_CONST_OFFSET; - if (edge != RISING_EDGE && edge != FALLING_EDGE && edge != BOTH_EDGE) - { - PyErr_SetString(PyExc_ValueError, "The edge must be set to RISING, FALLING or BOTH"); - return NULL; - } - - if (bouncetime <= 0 && bouncetime != -666) - { - PyErr_SetString(PyExc_ValueError, "Bouncetime must be greater than 0"); - return NULL; - } - - if (timeout <= 0 && timeout != -1) - { - PyErr_SetString(PyExc_ValueError, "Timeout must be greater than 0"); - return NULL; - } - - if (check_gpio_priv()) - return NULL; - - Py_BEGIN_ALLOW_THREADS // disable GIL - result = blocking_wait_for_edge(gpio, edge, bouncetime, timeout); - Py_END_ALLOW_THREADS // enable GIL - - if (result == 0) { - Py_RETURN_NONE; - } else if (result == -1) { - PyErr_SetString(PyExc_RuntimeError, "Conflicting edge detection events already exist for this GPIO channel"); - return NULL; - } else if (result == -2) { - PyErr_SetString(PyExc_RuntimeError, "Error waiting for edge"); - return NULL; - } else { - return Py_BuildValue("i", channel); - } - -} - -// python function value = gpio_function(channel) -static PyObject *py_gpio_function(PyObject *self, PyObject *args) -{ - unsigned int gpio; - int channel; - int f; - PyObject *func; - - if (!PyArg_ParseTuple(args, "i", &channel)) - return NULL; - - if (get_gpio_number(channel, &gpio)) - return NULL; - - if (mmap_gpio_mem()) - return NULL; - - f = gpio_function(gpio); - switch (f) - { - case 0 : f = INPUT; break; - case 1 : f = OUTPUT; break; - - // ALT 0 - case 4 : switch (gpio) - { - case 0 : - case 1 : - case 2 : - case 3 : f = I2C; break; - - case 7 : - case 8 : - case 9 : - case 10 : - case 11 : f = SPI; break; - - case 12 : - case 13 : f = PWM; break; - - case 14 : - case 15 : f = SERIAL; break; - - case 28 : - case 29 : f = I2C; break; - - default : f = MODE_UNKNOWN; break; - } - break; - - // ALT 5 - case 2 : if (gpio == 18 || gpio == 19) f = PWM; else f = MODE_UNKNOWN; - break; - - // ALT 4 - case 3 : switch (gpio) - - { - case 16 : - case 17 : - case 18 : - case 19 : - case 20 : - case 21 : f = SPI; break; - default : f = MODE_UNKNOWN; break; - } - break; - - default : f = MODE_UNKNOWN; break; - - } - func = Py_BuildValue("i", f); - return func; -} - -// python function setwarnings(state) -static PyObject *py_setwarnings(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, "i", &gpio_warnings)) - return NULL; - - if (setup_error) - { - PyErr_SetString(PyExc_RuntimeError, "Module not imported correctly!"); - return NULL; - } - - Py_RETURN_NONE; -} - -static const char moduledocstring[] = "GPIO functionality of a Raspberry Pi using Python"; - -PyMethodDef rpi_gpio_methods[] = { - {"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up a GPIO channel or list of channels with a direction and (optional) pull/up down control\nchannel - either board pin number or BCM number depending on which mode is set.\ndirection - IN or OUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel"}, - {"cleanup", (PyCFunction)py_cleanup, METH_VARARGS | METH_KEYWORDS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection\n[channel] - individual channel or list/tuple of channels to clean up. Default - clean every channel that has been used."}, - {"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel or list of channels\nchannel - either board pin number or BCM number depending on which mode is set.\nvalue - 0/1 or False/True or LOW/HIGH"}, - {"input", py_input_gpio, METH_VARARGS, "Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False\nchannel - either board pin number or BCM number depending on which mode is set."}, - {"setmode", py_setmode, METH_VARARGS, "Set up numbering mode to use for channels.\nBOARD - Use Raspberry Pi board numbers\nBCM - Use Broadcom GPIO 00..nn numbers"}, - {"getmode", py_getmode, METH_VARARGS, "Get numbering mode used for channel numbers.\nReturns BOARD, BCM or None"}, - {"add_event_detect", (PyCFunction)py_add_event_detect, METH_VARARGS | METH_KEYWORDS, "Enable edge detection events for a particular GPIO channel.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[callback] - A callback function for the event (optional)\n[bouncetime] - Switch bounce timeout in ms for callback"}, - {"remove_event_detect", py_remove_event_detect, METH_VARARGS, "Remove edge detection for a particular GPIO channel\nchannel - either board pin number or BCM number depending on which mode is set."}, - {"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occurred on a given GPIO. You need to enable edge detection using add_event_detect() first.\nchannel - either board pin number or BCM number depending on which mode is set."}, - {"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\nchannel - either board pin number or BCM number depending on which mode is set.\ncallback - a callback function"}, - {"wait_for_edge", (PyCFunction)py_wait_for_edge, METH_VARARGS | METH_KEYWORDS, "Wait for an edge. Returns the channel number or None on timeout.\nchannel - either board pin number or BCM number depending on which mode is set.\nedge - RISING, FALLING or BOTH\n[bouncetime] - time allowed between calls to allow for switchbounce\n[timeout] - timeout in ms"}, - {"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI)\nchannel - either board pin number or BCM number depending on which mode is set."}, - {"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, - {NULL, NULL, 0, NULL} -}; - -static struct PyModuleDef rpigpiomodule = { - PyModuleDef_HEAD_INIT, - "RPi._GPIO", // name of module - moduledocstring, // module documentation, may be NULL - -1, // size of per-interpreter state of the module, or -1 if the module keeps state in global variables. - rpi_gpio_methods -}; - -PyMODINIT_FUNC PyInit__gpio(void) -{ - int i; - PyObject *module = NULL; - - if ((module = PyModule_Create(&rpigpiomodule)) == NULL) - return NULL; - - define_constants(module); - - for (i=0; i<54; i++) - gpio_direction[i] = -1; - - // detect board revision and set up accordingly - if (get_rpi_info(&rpiinfo)) - { - PyErr_SetString(PyExc_RuntimeError, "This module can only be run on a Raspberry Pi!"); - setup_error = 1; - return NULL; - } - board_info = Py_BuildValue("{sissssssssss}", - "P1_REVISION",rpiinfo.p1_revision, - "REVISION",&rpiinfo.revision, - "TYPE",rpiinfo.type, - "MANUFACTURER",rpiinfo.manufacturer, - "PROCESSOR",rpiinfo.processor, - "RAM",rpiinfo.ram); - PyModule_AddObject(module, "RPI_INFO", board_info); - - if (rpiinfo.p1_revision == 1) { - pin_to_gpio = &pin_to_gpio_rev1; - } else if (rpiinfo.p1_revision == 2) { - pin_to_gpio = &pin_to_gpio_rev2; - } else { // assume model B+ or A+ or 2B - pin_to_gpio = &pin_to_gpio_rev3; - } - - rpi_revision = Py_BuildValue("i", rpiinfo.p1_revision); // deprecated - PyModule_AddObject(module, "RPI_REVISION", rpi_revision); // deprecated - - -#if PY_MINOR_VERSION < 7 - if (!PyEval_ThreadsInitialized()) - PyEval_InitThreads(); -#endif - - // register exit functions - last declared is called first - if (Py_AtExit(cleanup) != 0) - { - setup_error = 1; - cleanup(); - return NULL; - } - - if (Py_AtExit(event_cleanup_all) != 0) - { - setup_error = 1; - cleanup(); - return NULL; - } - - return module; -} diff --git a/rotary_encoder_gpio_core/test/issue_94_111_154.py b/rotary_encoder_gpio_core/test/issue_94_111_154.py deleted file mode 100755 index 1e06b51..0000000 --- a/rotary_encoder_gpio_core/test/issue_94_111_154.py +++ /dev/null @@ -1,36 +0,0 @@ -import time -import RPi.GPIO as GPIO - -LED_PIN = 12 - -def issue_154(): - # fails with led off at around 400 - count = 0 - pinRef = GPIO.PWM(LED_PIN,50) # create new PWM instance - while True: - pinRef.start(10) # update PWM value - time.sleep(0.05) - pinRef.stop() - GPIO.output(LED_PIN,0) - time.sleep(0.05) - count = count + 1 - print count - -def issue_94(cycles): - # led flickers. Bug = LED stays off at around cycle 400 - pwm = GPIO.PWM(LED_PIN, 1) - for i in xrange(cycles): - print(i) - pwm.ChangeFrequency(25) - pwm.start(50) - time.sleep(1) - pwm.stop() - -if __name__ == '__main__': - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.OUT) - try: -# issue_94(1000) - issue_154() - finally: - GPIO.cleanup() diff --git a/rotary_encoder_gpio_core/test/test.py b/rotary_encoder_gpio_core/test/test.py deleted file mode 100755 index 46a4889..0000000 --- a/rotary_encoder_gpio_core/test/test.py +++ /dev/null @@ -1,805 +0,0 @@ -# Copyright (c) 2013-2021 Ben Croston -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import print_function -if hasattr(__builtins__, 'raw_input'): - input = raw_input - -"""RPi.GPIO unit tests - -This test suite assumes the following circuit is connected: -GND_PIN = 6 -LED_PIN = 12 (with resistor to 0v) -SWITCH_PIN = 18 (with 0.1 uF capacitor around switch) to 0v -LOOP_IN = 16 connected with 1K resistor to LOOP_OUT -LOOP_OUT = 22 -NC_PIN = 24 not connected to anything -""" - -import os -import subprocess -import sys -import warnings -import time -from threading import Timer -import RPi.GPIO as GPIO -if sys.version[:3] == '2.6': - import unittest2 as unittest -else: - import unittest - -GND_PIN = 6 -LED_PIN = 12 -LED_PIN_BCM = 18 -SWITCH_PIN = 18 -SWITCH_PIN_BCM = 24 -LOOP_IN = 16 -LOOP_IN_BCM = 23 -LOOP_OUT = 22 -NC_PIN = 24 - -non_interactive = False -for i,val in enumerate(sys.argv): - if val == '--non_interactive': - non_interactive = True - sys.argv.pop(i) - -# Test starts with 'AAA' so that it is run first -class TestAAASetup(unittest.TestCase): - def runTest(self): - # Test mode not set (BOARD or BCM) exception - with self.assertRaises(RuntimeError) as e: - GPIO.setup(LED_PIN, GPIO.OUT) - self.assertEqual(str(e.exception), 'Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)') - - # Test trying to change mode after it has been set - GPIO.setmode(GPIO.BCM) - with self.assertRaises(ValueError) as e: - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN_BCM, GPIO.IN) - GPIO.cleanup() - - # Test setting an invalid mode - with self.assertRaises(ValueError): - GPIO.setmode(666) - - # Test getmode() - self.assertEqual(GPIO.getmode(), None) - GPIO.setmode(GPIO.BCM) - self.assertEqual(GPIO.getmode(), GPIO.BCM) - GPIO.setup(LED_PIN_BCM, GPIO.IN) - GPIO.cleanup() - GPIO.setmode(GPIO.BOARD) - self.assertEqual(GPIO.getmode(), GPIO.BOARD) - - # Test not set as OUTPUT message - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(RuntimeError) as e: - GPIO.output(LED_PIN, GPIO.HIGH) - self.assertEqual(str(e.exception), 'The GPIO channel has not been set up as an OUTPUT') - - # Test setup(..., pull_up_down=GPIO.HIGH) raises exception - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError): - GPIO.setup(LED_PIN, GPIO.IN, pull_up_down=GPIO.HIGH) - - # Test not valid on a raspi exception - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError) as e: - GPIO.setup(GND_PIN, GPIO.OUT) - self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') - - # Test 'already in use' warning - GPIO.setmode(GPIO.BOARD) - with open('/sys/class/gpio/export','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - time.sleep(0.2) # wait for udev to set permissions - with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: - f.write(b'out') - time.sleep(0.2) - with warnings.catch_warnings(record=True) as w: - GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning - self.assertEqual(w[0].category, RuntimeWarning) - with open('/sys/class/gpio/unexport','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - GPIO.cleanup() - - # test initial value of high reads back as high - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.HIGH) - self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) - GPIO.cleanup() - - # test initial value of low reads back as low - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.OUT, initial=GPIO.LOW) - self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) - GPIO.cleanup() - - # test pull up/down works - GPIO.setmode(GPIO.BOARD) - for i in range(1000): - GPIO.setup(NC_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) - time.sleep(0.001) - self.assertEqual(GPIO.input(NC_PIN), GPIO.LOW) - GPIO.setup(NC_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) - time.sleep(0.001) - self.assertEqual(GPIO.input(NC_PIN), GPIO.HIGH) - GPIO.cleanup() - - # test setup of a list of channels - GPIO.setmode(GPIO.BOARD) - GPIO.setup( [LED_PIN, LOOP_OUT], GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - GPIO.cleanup() - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError) as e: - GPIO.setup( [LED_PIN, GND_PIN], GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - self.assertEqual(str(e.exception), 'The channel sent is invalid on a Raspberry Pi') - GPIO.cleanup() - - # test setup of a tuple of channels - GPIO.setmode(GPIO.BOARD) - GPIO.setup( (LED_PIN, LOOP_OUT), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - GPIO.cleanup() - - # test warning when using pull up/down on i2c channels - GPIO.setmode(GPIO.BOARD) - if GPIO.RPI_INFO['P1_REVISION'] == 0: # compute module - pass # test not vailid - else: # revision 1, 2 or A+/B+ - with warnings.catch_warnings(record=True) as w: - GPIO.setup(3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) - self.assertEqual(w[0].category, RuntimeWarning) - with warnings.catch_warnings(record=True) as w: - GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) - self.assertEqual(w[0].category, RuntimeWarning) - GPIO.cleanup() - - # test non integer channel - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError): - GPIO.setup('d', GPIO.OUT) - with self.assertRaises(ValueError): - GPIO.setup(('d',LED_PIN), GPIO.OUT) - - # test setting pull_up_down on an output - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError): - GPIO.setup(LOOP_OUT, GPIO.OUT, pull_up_down=GPIO.PUD_DOWN) - - # test setting initial on an input - GPIO.setmode(GPIO.BOARD) - with self.assertRaises(ValueError): - GPIO.setup(LOOP_IN, GPIO.IN, initial=GPIO.LOW) - -class TestInputOutput(unittest.TestCase): - def setUp(self): - GPIO.setmode(GPIO.BOARD) - - def test_outputread(self): - """Test that an output() can be input()""" - GPIO.setup(LED_PIN, GPIO.OUT) - GPIO.output(LED_PIN, GPIO.HIGH) - self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) - GPIO.output(LED_PIN, GPIO.LOW) - self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) - - def test_loopback(self): - """Test output loops back to another input""" - GPIO.setup(LOOP_IN, GPIO.IN, pull_up_down=GPIO.PUD_OFF) - GPIO.setup(LOOP_OUT, GPIO.OUT, initial=GPIO.LOW) - self.assertEqual(GPIO.input(LOOP_IN), GPIO.LOW) - GPIO.output(LOOP_OUT, GPIO.HIGH) - self.assertEqual(GPIO.input(LOOP_IN), GPIO.HIGH) - - def test_output_on_input(self): - """Test output() can not be done on input""" - GPIO.setup(SWITCH_PIN, GPIO.IN) - with self.assertRaises(RuntimeError): - GPIO.output(SWITCH_PIN, GPIO.LOW) - - def test_output_list(self): - """Test output() using lists""" - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - - GPIO.output( [LOOP_OUT, LED_PIN], GPIO.HIGH) - self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) - self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) - - GPIO.output( (LOOP_OUT, LED_PIN), GPIO.LOW) - self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) - self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) - - GPIO.output( [LOOP_OUT, LED_PIN], [GPIO.HIGH, GPIO.LOW] ) - self.assertEqual(GPIO.input(LOOP_OUT), GPIO.HIGH) - self.assertEqual(GPIO.input(LED_PIN), GPIO.LOW) - - GPIO.output( (LOOP_OUT, LED_PIN), (GPIO.LOW, GPIO.HIGH) ) - self.assertEqual(GPIO.input(LOOP_OUT), GPIO.LOW) - self.assertEqual(GPIO.input(LED_PIN), GPIO.HIGH) - - with self.assertRaises(RuntimeError): - GPIO.output( [LOOP_OUT, LED_PIN], [0,0,0] ) - - with self.assertRaises(RuntimeError): - GPIO.output( [LOOP_OUT, LED_PIN], (0,) ) - - with self.assertRaises(RuntimeError): - GPIO.output(LOOP_OUT, (0,0)) - - with self.assertRaises(ValueError): - GPIO.output( [LOOP_OUT, 'x'], (0,0) ) - - with self.assertRaises(ValueError): - GPIO.output( [LOOP_OUT, LED_PIN], (0,'x') ) - - with self.assertRaises(ValueError): - GPIO.output( [LOOP_OUT, GND_PIN], (0,0) ) - - with self.assertRaises(RuntimeError): - GPIO.output( [LOOP_OUT, LOOP_IN], (0,0) ) - - def tearDown(self): - GPIO.cleanup() - -class TestSoftPWMExists(unittest.TestCase): - def runTest(self): - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.OUT) - pwm = GPIO.PWM(LED_PIN, 50) - with self.assertRaises(RuntimeError): - pwm2 = GPIO.PWM(LED_PIN, 49) - GPIO.cleanup() - -class TestSoftPWM(unittest.TestCase): - @unittest.skipIf(non_interactive, 'Non interactive mode') - def runTest(self): - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.OUT) - pwm = GPIO.PWM(LED_PIN, 50) - pwm.start(100) - print("\nPWM tests") - response = input('Is the LED on (y/n) ? ').upper() - self.assertEqual(response,'Y') - pwm.start(0) - response = input('Is the LED off (y/n) ? ').upper() - self.assertEqual(response,'Y') - print("LED Brighten/fade test...") - for i in range(0,3): - for x in range(0,101,5): - pwm.ChangeDutyCycle(x) - time.sleep(0.1) - for x in range(100,-1,-5): - pwm.ChangeDutyCycle(x) - time.sleep(0.1) - pwm.stop() - response = input('Did it work (y/n) ? ').upper() - self.assertEqual(response,'Y') - GPIO.cleanup() - -class TestSetWarnings(unittest.TestCase): - def test_alreadyinuse(self): - """Test 'already in use' warning""" - GPIO.setmode(GPIO.BOARD) - GPIO.setwarnings(False) - with open('/sys/class/gpio/export','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - time.sleep(0.2) # wait for udev to set permissions - with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: - f.write(b'out') - with warnings.catch_warnings(record=True) as w: - GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning - self.assertEqual(len(w),0) # should be no warnings - with open('/sys/class/gpio/unexport','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - GPIO.cleanup() - - GPIO.setmode(GPIO.BOARD) - GPIO.setwarnings(True) - with open('/sys/class/gpio/export','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - time.sleep(0.2) # wait for udev to set permissions - with open('/sys/class/gpio/gpio%s/direction'%LED_PIN_BCM,'wb') as f: - f.write(b'out') - with warnings.catch_warnings(record=True) as w: - GPIO.setup(LED_PIN, GPIO.OUT) # generate 'already in use' warning - self.assertEqual(w[0].category, RuntimeWarning) - with open('/sys/class/gpio/unexport','wb') as f: - f.write(str(LED_PIN_BCM).encode()) - GPIO.cleanup() - - def test_cleanupwarning(self): - """Test initial GPIO.cleanup() produces warning""" - GPIO.setwarnings(False) - GPIO.setmode(GPIO.BOARD) - GPIO.setup(SWITCH_PIN, GPIO.IN) - with warnings.catch_warnings(record=True) as w: - GPIO.cleanup() - self.assertEqual(len(w),0) # no warnings - GPIO.cleanup() - self.assertEqual(len(w),0) # no warnings - - GPIO.setwarnings(True) - GPIO.setmode(GPIO.BOARD) - GPIO.setup(SWITCH_PIN, GPIO.IN) - with warnings.catch_warnings(record=True) as w: - GPIO.cleanup() - self.assertEqual(len(w),0) # no warnings - GPIO.cleanup() - self.assertEqual(w[0].category, RuntimeWarning) # a warning - -class TestVersions(unittest.TestCase): - def test_rpi_info(self): - print('RPi Board Information') - print('---------------------') - for key,val in list(GPIO.RPI_INFO.items()): - print('%s => %s'%(key,val)) - response = input('\nIs this board info correct (y/n) ? ').upper() - self.assertEqual(response, 'Y') - - def test_gpio_version(self): - response = input('\nRPi.GPIO version %s - is this correct (y/n) ? '%GPIO.VERSION).upper() - self.assertEqual(response, 'Y') - -class TestGPIOFunction(unittest.TestCase): - def runTest(self): - GPIO.setmode(GPIO.BCM) - GPIO.setup(LED_PIN_BCM, GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.IN) - GPIO.setup(LED_PIN_BCM, GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN_BCM), GPIO.OUT) - GPIO.cleanup() - - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LED_PIN, GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - GPIO.setup(LED_PIN, GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - - def tearDown(self): - GPIO.cleanup() - -class TestSwitchBounce(unittest.TestCase): - def __init__(self, *a, **k): - unittest.TestCase.__init__(self, *a, **k) - self.switchcount = 0 - - def cb(self,chan): - self.switchcount += 1 - print('Button press',self.switchcount) - - def setUp(self): - GPIO.setmode(GPIO.BOARD) - GPIO.setup(SWITCH_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) - - @unittest.skipIf(non_interactive, 'Non interactive mode') - def test_switchbounce(self): - self.switchcount = 0 - print("\nSwitch bounce test. Press switch at least 10 times and count...") - GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, callback=self.cb, bouncetime=200) - while self.switchcount < 10: - time.sleep(1) - GPIO.remove_event_detect(SWITCH_PIN) - - @unittest.skipIf(non_interactive, 'Non interactive mode') - def test_event_detected(self): - self.switchcount = 0 - print("\nGPIO.event_detected() switch bounce test. Press switch at least 10 times and count...") - GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING, bouncetime=200) - while self.switchcount < 10: - if GPIO.event_detected(SWITCH_PIN): - self.switchcount += 1 - print('Button press',self.switchcount) - GPIO.remove_event_detect(SWITCH_PIN) - - def tearDown(self): - GPIO.cleanup() - -class TestEdgeDetection(unittest.TestCase): - def setUp(self): - GPIO.setmode(GPIO.BOARD) - GPIO.setup(LOOP_IN, GPIO.IN) - GPIO.setup(LOOP_OUT, GPIO.OUT) - - # Running a shell command with os.sytem has caused problems - # with sending SIGCHLD to the polling thread, causing it - # to exit. Test for that. - def testShellCmdWithWaitForEdge(self): - self.finished = False - def shellcmd(): - for i in range(50): - os.system('sleep 0') - subprocess.call('sleep 0', shell=True) - self.finished = True - def makehigh(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - - GPIO.output(LOOP_OUT, GPIO.LOW) - t1 = Timer(0.1, shellcmd) - t2 = Timer(0.5, makehigh) - t1.start() - t2.start() - starttime = time.time() - channel = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=1000) - endtime = time.time() - self.assertGreater(endtime - starttime, 0.5) - self.assertLess(endtime - starttime, 0.6) - self.assertEqual(channel, LOOP_IN) - - # make sure tasks in this test have finished before continuing - while not self.finished: - time.sleep(0.1) - - def testShellCmdWithEventCallback(self): - self.run_cb = False - - def cb(channel): - self.run_cb = True - - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) - time.sleep(0.01) - - for i in range(50): - os.system('sleep 0') - subprocess.call('sleep 0', shell=True) - - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - GPIO.remove_event_detect(LOOP_IN) - self.assertEqual(self.run_cb, True) - - def testWaitForEdgeInLoop(self): - def makelow(): - GPIO.output(LOOP_OUT, GPIO.LOW) - - count = 0 - timestart = time.time() - GPIO.output(LOOP_OUT, GPIO.HIGH) - while True: - t = Timer(0.1, makelow) - t.start() - starttime = time.time() - channel = GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING, timeout=200) - endtime = time.time() - self.assertLess(endtime-starttime, 0.12) - self.assertEqual(channel, LOOP_IN) - GPIO.output(LOOP_OUT, GPIO.HIGH) - count += 1 - if time.time() - timestart > 5 or count > 150: - break - - def testWaitForEdgeWithCallback(self): - def cb(): - raise Exception("Callback should not be called") - def makehigh(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - - GPIO.output(LOOP_OUT, GPIO.LOW) - t = Timer(0.1, makehigh) - - GPIO.add_event_detect(LOOP_IN, GPIO.RISING) - t.start() - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) - - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_callback(LOOP_IN, callback=cb) - with self.assertRaises(RuntimeError): # conflicting edge exception - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) - - GPIO.remove_event_detect(LOOP_IN) - - def testWaitForEventSwitchbounce(self): - self.finished = False - def bounce(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.2) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.LOW) - self.finished = True - - GPIO.output(LOOP_OUT, GPIO.LOW) - t1 = Timer(0.1, bounce) - t1.start() - - starttime = time.time() - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=100) - finishtime = time.time() - self.assertGreater(finishtime-starttime, 0.2) - while not self.finished: - time.sleep(0.1) - - def testInvalidBouncetime(self): - with self.assertRaises(ValueError): - GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=-1) - with self.assertRaises(ValueError): - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=-1) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING, bouncetime=123) - with self.assertRaises(RuntimeError): - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, bouncetime=321) - GPIO.remove_event_detect(LOOP_IN) - - def testAlreadyAdded(self): - GPIO.add_event_detect(LOOP_IN, GPIO.RISING) - with self.assertRaises(RuntimeError): - GPIO.add_event_detect(LOOP_IN, GPIO.RISING) - GPIO.remove_event_detect(LOOP_IN) - - def testHighLowEvent(self): - with self.assertRaises(ValueError): - GPIO.add_event_detect(LOOP_IN, GPIO.LOW) - with self.assertRaises(ValueError): - GPIO.add_event_detect(LOOP_IN, GPIO.HIGH) - - def testFallingEventDetected(self): - GPIO.output(LOOP_OUT, GPIO.HIGH) - GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), True) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.remove_event_detect(LOOP_IN) - - def testRisingEventDetected(self): - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), True) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.remove_event_detect(LOOP_IN) - - def testBothEventDetected(self): - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.BOTH) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), True) - self.assertEqual(GPIO.event_detected(LOOP_IN), False) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.01) - self.assertEqual(GPIO.event_detected(LOOP_IN), True) - GPIO.remove_event_detect(LOOP_IN) - - def testWaitForRising(self): - def makehigh(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - GPIO.output(LOOP_OUT, GPIO.LOW) - t = Timer(0.1, makehigh) - t.start() - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) - - def testWaitForFalling(self): - def makelow(): - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.output(LOOP_OUT, GPIO.HIGH) - t = Timer(0.1, makelow) - t.start() - GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) - - def testExceptionInCallback(self): - self.run_cb = False - def cb(channel): - with self.assertRaises(ZeroDivisionError): - self.run_cb = True - a = 1/0 - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) - time.sleep(0.01) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.01) - self.assertEqual(self.run_cb, True) - GPIO.remove_event_detect(LOOP_IN) - - def testAddEventCallback(self): - def cb(channel): - self.callback_count += 1 - - # falling test - self.callback_count = 0 - GPIO.output(LOOP_OUT, GPIO.HIGH) - GPIO.add_event_detect(LOOP_IN, GPIO.FALLING) - GPIO.add_event_callback(LOOP_IN, cb) - time.sleep(0.01) - for i in range(2048): - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.001) - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.001) - GPIO.remove_event_detect(LOOP_IN) - self.assertEqual(self.callback_count, 2048) - - # rising test - self.callback_count = 0 - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING, callback=cb) - time.sleep(0.01) - for i in range(2048): - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.001) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.001) - GPIO.remove_event_detect(LOOP_IN) - self.assertEqual(self.callback_count, 2048) - - # both test - self.callback_count = 0 - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.add_event_detect(LOOP_IN, GPIO.BOTH, callback=cb) - time.sleep(0.01) - for i in range(2048): - GPIO.output(LOOP_OUT, GPIO.HIGH) - time.sleep(0.001) - GPIO.output(LOOP_OUT, GPIO.LOW) - time.sleep(0.001) - GPIO.remove_event_detect(LOOP_IN) - self.assertEqual(self.callback_count, 4096) - - def testEventOnOutput(self): - with self.assertRaises(RuntimeError): - GPIO.add_event_detect(LOOP_OUT, GPIO.FALLING) - - def testAlternateWaitForEdge(self): - def makehigh(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - def makelow(): - GPIO.output(LOOP_OUT, GPIO.LOW) - GPIO.output(LOOP_OUT, GPIO.LOW) - t = Timer(0.1, makehigh) - t2 = Timer(0.15, makelow) - t.start() - t2.start() - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING) - GPIO.wait_for_edge(LOOP_IN, GPIO.FALLING) - - def testWaitForEdgeTimeout(self): - def makehigh(): - GPIO.output(LOOP_OUT, GPIO.HIGH) - def makelow(): - GPIO.output(LOOP_OUT, GPIO.LOW) - - with self.assertRaises(TypeError): - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout="beer") - - with self.assertRaises(ValueError): - GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=-1234) - - makelow() - chan = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=200) - self.assertEqual(chan, None) - - t = Timer(0.1, makehigh) - t.start() - chan = GPIO.wait_for_edge(LOOP_IN, GPIO.RISING, timeout=200) - self.assertEqual(chan, LOOP_IN) - - def tearDown(self): - GPIO.cleanup() - -class TestCleanup(unittest.TestCase): - def setUp(self): - GPIO.setmode(GPIO.BOARD) - - def test_cleanall(self): - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup() - GPIO.setmode(GPIO.BOARD) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - - def test_cleanone(self): - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - GPIO.setup(SWITCH_PIN, GPIO.IN) - GPIO.setup(LOOP_IN, GPIO.IN) - GPIO.add_event_detect(SWITCH_PIN, GPIO.FALLING) - GPIO.add_event_detect(LOOP_IN, GPIO.RISING) - time.sleep(0.2) # wait for udev to set permissions - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(SWITCH_PIN), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LOOP_IN), GPIO.IN) - self.assertTrue(os.path.exists('/sys/class/gpio/gpio%s'%SWITCH_PIN_BCM)) - self.assertTrue(os.path.exists('/sys/class/gpio/gpio%s'%LOOP_IN_BCM)) - GPIO.cleanup(SWITCH_PIN) - time.sleep(0.2) # wait for udev to set permissions - self.assertFalse(os.path.exists('/sys/class/gpio/gpio%s'%SWITCH_PIN_BCM)) - self.assertTrue(os.path.exists('/sys/class/gpio/gpio%s'%LOOP_IN_BCM)) - GPIO.cleanup(LOOP_IN) - time.sleep(0.2) # wait for udev to set permissions - self.assertFalse(os.path.exists('/sys/class/gpio/gpio%s'%SWITCH_PIN_BCM)) - self.assertFalse(os.path.exists('/sys/class/gpio/gpio%s'%LOOP_IN_BCM)) - GPIO.cleanup(LOOP_OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup(LED_PIN) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - - def test_cleantuple(self): - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup((LOOP_OUT,)) - GPIO.setmode(GPIO.BOARD) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup((LED_PIN,)) - GPIO.setmode(GPIO.BOARD) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - GPIO.cleanup((LOOP_OUT,LED_PIN)) - GPIO.setmode(GPIO.BOARD) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - - def test_cleanlist(self): - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.OUT) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup([LOOP_OUT]) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.OUT) - GPIO.cleanup([LED_PIN]) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - GPIO.setup(LOOP_OUT, GPIO.OUT) - GPIO.setup(LED_PIN, GPIO.OUT) - GPIO.cleanup([LOOP_OUT,LED_PIN]) - self.assertEqual(GPIO.gpio_function(LOOP_OUT), GPIO.IN) - self.assertEqual(GPIO.gpio_function(LED_PIN), GPIO.IN) - -if __name__ == '__main__': - unittest.main()