From 335e105bc1208fd3a99c419a448792dd5f95ca5d Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 8 Nov 2017 17:43:19 -0600 Subject: [PATCH 001/157] Comment out debug log in gpio hotpath #188 Signed-off-by: Drew Fustini --- source/event_gpio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/event_gpio.c b/source/event_gpio.c index 08bcec1..3dc8714 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -196,7 +196,7 @@ int open_value_file(unsigned int gpio) if ((gpio >= USR_LED_GPIO_MIN) && (gpio <= USR_LED_GPIO_MAX)) { snprintf(filename, sizeof(filename), "/sys/class/leds/beaglebone:green:usr%d/brightness", gpio - USR_LED_GPIO_MIN); } else if (beaglebone_blue()) { - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: beaglebone_blue() is true\n"); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: beaglebone_blue() is true\n"); switch(gpio) { case USR_LED_RED: snprintf(filename, sizeof(filename), "/sys/class/leds/red/brightness"); @@ -224,10 +224,10 @@ int open_value_file(unsigned int gpio) break; } } else { - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: default gpio path\n"); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: default gpio path\n"); snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: filename=%s\n", filename); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio open_value_file: filename=%s\n", filename); // if(gpio == USR_LED_RED) { // red LED // snprintf(filename, sizeof(filename), "/sys/class/leds/red/brightness"); @@ -327,7 +327,7 @@ BBIO_err gpio_set_direction(unsigned int gpio, unsigned int in_flag) return BBIO_SYSFS; } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_direction: %u OK", gpio); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_direction: %u OK", gpio); return BBIO_OK; } @@ -359,7 +359,7 @@ BBIO_err gpio_get_direction(unsigned int gpio, unsigned int *value) *value = INPUT; } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_get_direction: %u OK", gpio); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_get_direction: %u OK", gpio); return BBIO_OK; } @@ -396,14 +396,14 @@ BBIO_err gpio_set_value(unsigned int gpio, unsigned int value) char *usr_led_trigger[] = { "heartbeat", "mmc0", "cpu0", "mmc1" }; int led = gpio - USR_LED_GPIO_MIN; - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: USR LED path\n"); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: USR LED path\n"); snprintf(filename, sizeof(filename), "/sys/class/leds/beaglebone:green:usr%d/brightness", led); if (access(filename, W_OK) < 0) { snprintf(filename, sizeof(filename), "/sys/class/leds/beaglebone:green:%s/brightness", usr_led_trigger[led]); } } else if (beaglebone_blue()) { - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: beaglebone_blue() is true\n"); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: beaglebone_blue() is true\n"); switch(gpio) { case USR_LED_RED: snprintf(filename, sizeof(filename), "/sys/class/leds/red/brightness"); @@ -431,10 +431,10 @@ BBIO_err gpio_set_value(unsigned int gpio, unsigned int value) break; } } else { - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: default gpio path\n"); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: default gpio path\n"); snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/value", gpio); } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: filename=%s\n", filename); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: filename=%s\n", filename); fd = open(filename, O_WRONLY); if (fd < 0) { @@ -457,7 +457,7 @@ BBIO_err gpio_set_value(unsigned int gpio, unsigned int value) return BBIO_SYSFS; } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: %u %u OK", gpio, value); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_set_value: %u %u OK", gpio, value); return BBIO_OK; } @@ -489,7 +489,7 @@ BBIO_err gpio_get_value(unsigned int gpio, unsigned int *value) *value = 0; } - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_get_value: %u OK", gpio); + //syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_get_value: %u OK", gpio); return BBIO_OK; } From 792386cc9461baaa26490f31be2e01db6f61dfd8 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 10:58:40 +0100 Subject: [PATCH 002/157] Copy Encoder module comments to README.md --- Adafruit_BBIO/README.md | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Adafruit_BBIO/README.md diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md new file mode 100644 index 0000000..288b43b --- /dev/null +++ b/Adafruit_BBIO/README.md @@ -0,0 +1,51 @@ +# =========================================================================== +# Adafruit_BBIO.Encoder Class +# =========================================================================== +# refers to graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py + +# BeagleBone must boot with cape-universal enabled +# and load the cape-universala overlay in order to +# use all the eQEP pins +# +# Install the latest Device Tree overlays: +# ======================================== +# sudo apt-get upgrade bb-cape-overlays +# +# File: /boot/uEnv.txt +# ==================== +# uname_r=4.4.62-ti-r99 +# cmdline=coherent_pool=1M quiet cape_universal=enable +# cape_enable=bone_capemgr.enable_partno=cape-universala +# +# File: /sys/devices/platform/bone_capemgr/slots +# ============================================== +# 0: PF---- -1 +# 1: PF---- -1 +# 2: PF---- -1 +# 3: PF---- -1 +# 4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universala +# +# eqep0: P9_27, P9_92 +# =================== +# config-pin P9_27 qep +# config-pin P9_92 qep # alias for P9_42.1 +# cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position +# +# eqep1: P8.33, P8.35 +# =================== +# config-pin P8.33 qep +# config-pin P8.35 qep +# cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position +# +# eqep2: P8.11, P8.12 +# =================== +# config-pin P8.11 qep +# config-pin P8.12 qep +# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position +# +# alternate pins for eqep2 (mutually exclusive) +# eqep2b: P8.41, P8.42 +# ==================== +# config-pin P8.41 qep +# config-pin P8.42 qep +# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position From ce7b8e3a5db4acfac8dad8699b6f87d88813c4bc Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:14:47 +0100 Subject: [PATCH 003/157] Formatted Encoder README in markdown --- Adafruit_BBIO/README.md | 127 ++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 288b43b..2eaa2a4 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -1,51 +1,78 @@ -# =========================================================================== # Adafruit_BBIO.Encoder Class -# =========================================================================== -# refers to graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py - -# BeagleBone must boot with cape-universal enabled -# and load the cape-universala overlay in order to -# use all the eQEP pins -# -# Install the latest Device Tree overlays: -# ======================================== -# sudo apt-get upgrade bb-cape-overlays -# -# File: /boot/uEnv.txt -# ==================== -# uname_r=4.4.62-ti-r99 -# cmdline=coherent_pool=1M quiet cape_universal=enable -# cape_enable=bone_capemgr.enable_partno=cape-universala -# -# File: /sys/devices/platform/bone_capemgr/slots -# ============================================== -# 0: PF---- -1 -# 1: PF---- -1 -# 2: PF---- -1 -# 3: PF---- -1 -# 4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universala -# -# eqep0: P9_27, P9_92 -# =================== -# config-pin P9_27 qep -# config-pin P9_92 qep # alias for P9_42.1 -# cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position -# -# eqep1: P8.33, P8.35 -# =================== -# config-pin P8.33 qep -# config-pin P8.35 qep -# cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position -# -# eqep2: P8.11, P8.12 -# =================== -# config-pin P8.11 qep -# config-pin P8.12 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# alternate pins for eqep2 (mutually exclusive) -# eqep2b: P8.41, P8.42 -# ==================== -# config-pin P8.41 qep -# config-pin P8.42 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position + +Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. + +## Prerequisites + +These instructions are based on a 4.4.x Linux kernel. + +In order to use all eQEP pins the BeagleBone must: + +- boot with cape-universal enabled, and +- load the cape-universala overlay + + +### Install/upgrade the latest Device Tree overlays + +``` +sudo apt-get upgrade bb-cape-overlays +``` + +### Load the universal cape + +Modify the `/boot/uEnv.txt` file to contain these two lines: + +``` +cmdline=coherent_pool=1M net.ifnames=0 quiet cape_universal=enable +``` + +``` +cape_enable=bone_capemgr.enable_partno=cape-universala +``` + +### Check slots + +TBD + +## eQEP configuraton + +### eQEP0 + +Pins: `P9_27`, `P9_92` + +``` +$ config-pin P9_27 qep +$ config-pin P9_92 qep # alias for P9_42.1 +$ cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position +``` + +### eQEP1 + +Pins: `P8.33`, `P8.35` + +``` +$ config-pin P8.33 qep +$ config-pin P8.35 qep +$ cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position +``` + +### eQEP2 + +Pins: `P8.11, P8.12 + +``` +$ config-pin P8.11 qep +$ config-pin P8.12 qep +$ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position +``` + +### eQEP2b + +Note: alternate pins for eQEP2 (mutually exclusive) +Pins: `P8.11, P8.12 + +``` +$ config-pin P8.41 qep +$ config-pin P8.42 qep +$ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position +``` From f1bfb1e1fddc4d0851fe98faa6c099d8db9ad1d1 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:16:35 +0100 Subject: [PATCH 004/157] Fixed Encoder README formatting --- Adafruit_BBIO/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 2eaa2a4..9d1449b 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -58,7 +58,7 @@ $ cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position ### eQEP2 -Pins: `P8.11, P8.12 +Pins: `P8.11`, `P8.12` ``` $ config-pin P8.11 qep @@ -69,7 +69,8 @@ $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position ### eQEP2b Note: alternate pins for eQEP2 (mutually exclusive) -Pins: `P8.11, P8.12 + +Pins: `P8.11`, `P8.12` ``` $ config-pin P8.41 qep From df87be60102a04ec18d920731e18c944f6c64c52 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:18:39 +0100 Subject: [PATCH 005/157] Removed QEP instructions from Encoder module --- Adafruit_BBIO/Encoder.py | 52 ---------------------------------------- 1 file changed, 52 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 9f73675..5155246 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -1,57 +1,5 @@ #!/usr/bin/python -# =========================================================================== -# Adafruit_BBIO.Encoder Class -# =========================================================================== -# refers to graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py - -# BeagleBone must boot with cape-universal enabled -# and load the cape-universala overlay in order to -# use all the eQEP pins -# -# Install the latest Device Tree overlays: -# ======================================== -# sudo apt-get upgrade bb-cape-overlays -# -# File: /boot/uEnv.txt -# ==================== -# uname_r=4.4.62-ti-r99 -# cmdline=coherent_pool=1M quiet cape_universal=enable -# cape_enable=bone_capemgr.enable_partno=cape-universala -# -# File: /sys/devices/platform/bone_capemgr/slots -# ============================================== -# 0: PF---- -1 -# 1: PF---- -1 -# 2: PF---- -1 -# 3: PF---- -1 -# 4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universala -# -# eqep0: P9_27, P9_92 -# =================== -# config-pin P9_27 qep -# config-pin P9_92 qep # alias for P9_42.1 -# cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position -# -# eqep1: P8.33, P8.35 -# =================== -# config-pin P8.33 qep -# config-pin P8.35 qep -# cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position -# -# eqep2: P8.11, P8.12 -# =================== -# config-pin P8.11 qep -# config-pin P8.12 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# alternate pins for eqep2 (mutually exclusive) -# eqep2b: P8.41, P8.42 -# ==================== -# config-pin P8.41 qep -# config-pin P8.42 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position - from subprocess import call import os From 0d299c067c33ba645aeaf50f04b8a0e0abf617b0 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:25:25 +0100 Subject: [PATCH 006/157] Fixes to Encoder README --- Adafruit_BBIO/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 9d1449b..7235845 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -1,7 +1,9 @@ -# Adafruit_BBIO.Encoder Class +# Adafruit_BBIO.Encoder module Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. +This module enables access to the Beaglebone's enhanced Quadrature Encoder Pulse (eQEP) inputs. + ## Prerequisites These instructions are based on a 4.4.x Linux kernel. @@ -70,7 +72,7 @@ $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position Note: alternate pins for eQEP2 (mutually exclusive) -Pins: `P8.11`, `P8.12` +Pins: `P8.41`, `P8.42` ``` $ config-pin P8.41 qep From 14a79df98097847df635dc9ce43bcf3ce9025ccd Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:46:47 +0100 Subject: [PATCH 007/157] Updated Encoder README --- Adafruit_BBIO/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 7235845..bb1c9ff 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -2,7 +2,7 @@ Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. -This module enables access to the Beaglebone's enhanced Quadrature Encoder Pulse (eQEP) inputs. +This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2. ## Prerequisites @@ -38,6 +38,8 @@ TBD ## eQEP configuraton +Note: if either eQEP 1 or eQEP 2 are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. + ### eQEP0 Pins: `P9_27`, `P9_92` @@ -60,6 +62,8 @@ $ cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position ### eQEP2 +#### eQEP2 + Pins: `P8.11`, `P8.12` ``` @@ -68,7 +72,7 @@ $ config-pin P8.12 qep $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position ``` -### eQEP2b +#### eQEP2b Note: alternate pins for eQEP2 (mutually exclusive) From b30c17ab86c17fdb4c3e9ad3ce1ba3da0b086e0e Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 11:52:06 +0100 Subject: [PATCH 008/157] Encoder README: added info on dedicated overlays --- Adafruit_BBIO/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index bb1c9ff..f65b0c0 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -13,6 +13,7 @@ In order to use all eQEP pins the BeagleBone must: - boot with cape-universal enabled, and - load the cape-universala overlay +Note: an alternative option to the `cape-universala` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). ### Install/upgrade the latest Device Tree overlays @@ -83,3 +84,7 @@ $ config-pin P8.41 qep $ config-pin P8.42 qep $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position ``` +## Further reading + +- [Beaglebone encoder inputs](https://github.com/Teknoman117/beaglebot/tree/master/encoders) +- [Beaglebone eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts) From 8c1b1106daa66a4cb49f0cd94cf0f16ced4c3e14 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 12:05:50 +0100 Subject: [PATCH 009/157] Encoder README: updated info on pre-requisites --- Adafruit_BBIO/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index f65b0c0..9f96975 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -10,10 +10,12 @@ These instructions are based on a 4.4.x Linux kernel. In order to use all eQEP pins the BeagleBone must: -- boot with cape-universal enabled, and -- load the cape-universala overlay +1. boot with cape-universal enabled, and +2. load the cape-universala overlay -Note: an alternative option to the `cape-universala` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). +Notes: +- It would seem that `cape_universal` is [enabled by default already](https://groups.google.com/d/msg/beagleboard/2D5Pz3r7ZZ8/bLKcvHbGDgAJ) from kernel 4.1.x onwards. As such, the first step is not necessary. +- An alternative option to the `cape-universala` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). ### Install/upgrade the latest Device Tree overlays From 40c2f77970fdbcd5b1c27fd3d01cb5ad33db6d6c Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 19:11:46 +0100 Subject: [PATCH 010/157] Encoder README update --- Adafruit_BBIO/README.md | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 9f96975..72dec45 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -1,21 +1,21 @@ # Adafruit_BBIO.Encoder module -Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. - This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2. +Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. + ## Prerequisites These instructions are based on a 4.4.x Linux kernel. -In order to use all eQEP pins the BeagleBone must: +In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the cape-universal overlay -1. boot with cape-universal enabled, and -2. load the cape-universala overlay +``` +enable_uboot_cape_universal=1 +``` Notes: -- It would seem that `cape_universal` is [enabled by default already](https://groups.google.com/d/msg/beagleboard/2D5Pz3r7ZZ8/bLKcvHbGDgAJ) from kernel 4.1.x onwards. As such, the first step is not necessary. -- An alternative option to the `cape-universala` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). +- An alternative option to the `cape-universal` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). ### Install/upgrade the latest Device Tree overlays @@ -25,23 +25,27 @@ sudo apt-get upgrade bb-cape-overlays ### Load the universal cape -Modify the `/boot/uEnv.txt` file to contain these two lines: +If it doesn't already contain it, modify the `/boot/uEnv.txt` file to contain this line: ``` -cmdline=coherent_pool=1M net.ifnames=0 quiet cape_universal=enable +enable_uboot_cape_universal=1 ``` -``` -cape_enable=bone_capemgr.enable_partno=cape-universala -``` +Notes: -### Check slots +- Some older documentation recommends using these two lines instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. -TBD + ``` + cmdline=cape_universal=enable # Plus some other options + ``` + ``` + cape_enable=bone_capemgr.enable_partno=cape-universala + ``` +- TBD: check the overlays that are currently loaded ## eQEP configuraton -Note: if either eQEP 1 or eQEP 2 are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. +Note: if either eQEP1 or eQEP2b are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. ### eQEP0 From 059d0f9669fbfdd2bb6bb0d8f56a11a10290a403 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 16 Nov 2017 19:22:16 +0100 Subject: [PATCH 011/157] Encoder README update --- Adafruit_BBIO/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 72dec45..aa3642b 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -15,6 +15,7 @@ enable_uboot_cape_universal=1 ``` Notes: +- It seems that the `cape-universal` cape _does only enable access to eQEP0 and eQEP2_. TBD: check how to load [`cape-universala`](https://github.com/cdsteinkuehler/beaglebone-universal-io/pull/30) - An alternative option to the `cape-universal` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). ### Install/upgrade the latest Device Tree overlays From 082bfff556578ab35b941997a5707f7d375c3c68 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 17 Nov 2017 03:29:05 +0100 Subject: [PATCH 012/157] Add logging support, turn off unconditional debug output --- Adafruit_BBIO/Encoder.py | 159 +++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 66 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 5155246..1c23091 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -1,7 +1,9 @@ #!/usr/bin/python -from subprocess import call +from subprocess import check_output, STDOUT, CalledProcessError import os +import logging + class QEP : @@ -48,37 +50,53 @@ class RotaryEncoder(object): EQEP1 = 1 EQEP2 = 2 EQEP2b = 3 - + + def _run_cmd(self, cmd): + '''Runs a command. If not successful (i.e. error code different than zero), + print the stderr output as a warning. + ''' + + try: + output = check_output(cmd, stderr=STDOUT) + self._logger.info("_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), 0, output)) + except CalledProcessError as e: + self._logger.warning( + "_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), e.returncode, e.output)) + def config_pin(self, pin): ''' config_pin() Config pin for QEP ''' - result = call(["config-pin", pin, "qep"]) - print("config_pin> pin={0} result={1}".format(pin, result)) - return result - + + self._run_cmd(["config-pin", pin, "qep"]) + def cat_file(self, path): ''' cat_file() Print contents of file ''' - result = call(["cat", path]) - print("cat_file> path={0} result={1}".format(path, result)) - return result - + + self._run_cmd(["cat", path]) + def __init__(self, eqep_num): ''' RotaryEncoder(eqep_num) - Creates an instance of the class RotaryEncoder. - eqep_num determines which eQEP pins are set up. + Creates an instance of the class RotaryEncoder. + eqep_num determines which eQEP pins are set up. eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ the rotary encoder is connected to. ''' - print(">>>>>>>> TEST CALL BEGIN") - ################################### - print(">>>>>> eqep0: P9_27, P9_92") + self._logger = logging.getLogger(__name__) + self._logger.addHandler(logging.NullHandler()) + #self._logger.setLevel(logging.DEBUG) + + # Configure eqep0 + self._logger.info("Configuring eqep0, pins: P9.27, P9.92") + pin = "P9_27" self.config_pin(pin) @@ -86,10 +104,10 @@ def __init__(self, eqep_num): self.config_pin(pin) path = "/sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position" - self.cat_file(path); + self.cat_file(path) - ################################### - print(">>>>>>> eqep1: P8.33, P8.35") + # Configure eqep1 + self._logger.info("Configuring eqep1, pins: P8.33, P8.35") pin = "P8.33" self.config_pin(pin) @@ -100,8 +118,8 @@ def __init__(self, eqep_num): path = "/sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position" self.cat_file(path); - ################################### - print(">>>>>>> eqep2: P8.11, P8.12") + # Configure eqep2 + self._logger.info("Configuring eqep2, pins: P8.11, P8.12") pin = "P8.11" self.config_pin(pin) @@ -112,8 +130,8 @@ def __init__(self, eqep_num): path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" self.cat_file(path); - ################################### - print(">>>>>>> eqep2b: P8.41, P8.42") + # Configure eqep2b + self._logger.info("Configuring eqep2, pins: P8.41, P8.42") pin = "P8.41" self.config_pin(pin) @@ -124,17 +142,17 @@ def __init__(self, eqep_num): path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" self.cat_file(path); - ################################### - print(">>>>>>>> TEST CALL END") + self._logger.debug("RotaryEncoder(): eqep_num: {0}".format(eqep_num)) + self._logger.debug("RotaryEncoder(): self._eqep_dirs[0]: {0}".format(self._eqep_dirs[0])) + self._logger.debug("RotaryEncoder(): self._eqep_dirs[1]: {0}".format(self._eqep_dirs[1])) + self._logger.debug("RotaryEncoder(): self._eqep_dirs[2]: {0}".format(self._eqep_dirs[2])) + self._logger.debug("RotaryEncoder(): self._eqep_dirs[eqep_num: {0}]: {1}".format(eqep_num, self._eqep_dirs[eqep_num])) - print("RotaryEncoder(): eqep_num: {0}".format(eqep_num)) - print("RotaryEncoder(): self._eqep_dirs[0]: {0}".format(self._eqep_dirs[0])) - print("RotaryEncoder(): self._eqep_dirs[1]: {0}".format(self._eqep_dirs[1])) - print("RotaryEncoder(): self._eqep_dirs[2]: {0}".format(self._eqep_dirs[2])) - print("RotaryEncoder(): self._eqep_dirs[eqep_num: {0}]: {1}".format(eqep_num, self._eqep_dirs[eqep_num])) assert 0 <= eqep_num <= 3 , "eqep_num must be between 0 and 3" + self.base_dir = self._eqep_dirs[eqep_num] - print("RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + self._logger.debug("RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + self.enable() def enable(self): @@ -143,32 +161,35 @@ def enable(self): Turns the eQEP hardware ON ''' enable_file = "%s/enabled" % self.base_dir - print("enable(): enable_file: {0}".format(enable_file)) - print("enable(): TODO: write 1 to enable_file") - #return sysfs.kernelFileIO(enable_file, '1') - + self._logger.debug("enable(): enable_file: {0}".format(enable_file)) + self._logger.warning( + "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) + #return sysfs.kernelFileIO(enable_file, '1') + def disable(self): ''' disable() Turns the eQEP hardware OFF ''' enable_file = "%s/enabled" % self.base_dir - print("disable(): enable_file: {0}".format(enable_file)) - print("disable(): TODO: write 0 to enable_file") + self._logger.debug("disable(): enable_file: {0}".format(enable_file)) + self._logger.warning( + "disable(): TODO: not implemented, write 0 to {}".format(enable_file)) #return sysfs.kernelFileIO(enable_file, '0') def setAbsolute(self): ''' setAbsolute() Set mode as Absolute - The position starts at zero and is incremented or + The position starts at zero and is incremented or decremented by the encoder's movement ''' mode_file = "%s/mode" % self.base_dir - print("setAbsolute(): mode_file: {0}".format(mode_file)) - print("setAbsolute(): TODO: write 0 to mode_file") + self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) + self._logger.warning( + "setAbsolute(): TODO: not implemented, write 0 to {}".format(mode_file)) #return sysfs.kernelFileIO(mode_file, '0') - + def setRelative(self): ''' setRelative() @@ -176,60 +197,66 @@ def setRelative(self): The position is reset when the unit timer overflows. ''' mode_file = "%s/mode" % self.base_dir - print("setRelative(): mode_file: {0}".format(mode_file)) - print("setRelative(): TODO: write 1 to mode_file") + self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) + self._logger.warning( + "setRelative(): TODO: not implemented, write 1 to {}".format(mode_file)) #return sysfs.kernelFileIO(mode_file, '1') - + def getMode(self): ''' getMode() Returns the mode the eQEP hardware is in. ''' mode_file = "%s/mode" % self.base_dir - print("getMode(): mode_file: {0}".format(mode_file)) - print("getMode(): TODO: read mode_file") + self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) + self._logger.warning("getMode(): TODO: read mode_file") #return sysfs.kernelFileIO(mode_file) def getPosition(self): ''' getPosition() Get the current position of the encoder. - In absolute mode, this attribute represents the current position - of the encoder. - In relative mode, this attribute represents the position of the + In absolute mode, this attribute represents the current position + of the encoder. + In relative mode, this attribute represents the position of the encoder at the last unit timer overflow. ''' position_file = "%s/position" % self.base_dir - print("getPosition(): position_file: {0}".format(position_file)) + self._logger.debug("getPosition(): position_file: {0}".format(position_file)) position_handle = open(position_file, 'r') - print("getPosition(): position_handle: {0}".format(position_handle)) + self._logger.debug("getPosition(): position_handle: {0}".format(position_handle)) position = position_handle.read() - print("getPosition(): position: {0}".format(position)) + self._logger.debug("getPosition(): position: {0}".format(position)) #return sysfs.kernelFileIO(position_file) + return position - - def setFrequency(self,freq): + + def setFrequency(self, freq): ''' setFrequency(freq) Set the frequency in Hz at which the driver reports new positions. ''' period_file = "%s/period" % self.base_dir - print("setFrequency(): period_file: {0}".format(period_file)) - print("setFrequency(): freq: {0}".format(period_file)) - print("setFrequency(): freq: {0}".format(freq)) - print("setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) - print("setFrequency(): str(1000000000/freq)): {0}".format(str(1000000000/freq))) - print("setFrequency(): TODO: set period_file: {0}".format(str(1000000000/freq))) + self._logger.debug("setFrequency(): period_file: {0}".format(period_file)) + self._logger.debug("setFrequency(): freq: {0}".format(freq)) + self._logger.debug("setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) + self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format(str(1000000000/freq))) + self._logger.warning( + "setFrequency(): TODO: not implemented, set {} to {}".format( + period_file, str(1000000000/freq))) #return sysfs.kernelFileIO(period_file, str(1000000000/freq)) - - def setPosition(self,val): - ''' + + def setPosition(self, val): + ''' setPosition(value) Give a new value to the current position ''' position_file = "%s/position" % self.base_dir + self._logger.warning( + "setPosition(): TODO: not implemented, write position to {}".format( + position_file)) #return sysfs.kernelFileIO(position_file, str(val)) - + def zero(self): ''' zero()s @@ -239,7 +266,7 @@ def zero(self): #""" -# encoder_test.py +# encoder_test.py # Rekha Seethamraju # An example to demonstrate the use of the eQEP library # for PyBBIO. @@ -253,9 +280,9 @@ def zero(self): #def setup(): # encoder.setAbsolute() # encoder.zero() -# +# #def loop(): # print("encoder position : "+encoder.getPosition()) # delay(1000) -# +# #run(setup, loop) From 6f19946a0714b11164b4b1e9c207aac340143ad2 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 17 Nov 2017 03:42:46 +0100 Subject: [PATCH 013/157] Encoder: remove unused logging code --- Adafruit_BBIO/Encoder.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 1c23091..596f0c2 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -92,7 +92,6 @@ def __init__(self, eqep_num): self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) - #self._logger.setLevel(logging.DEBUG) # Configure eqep0 self._logger.info("Configuring eqep0, pins: P9.27, P9.92") From b328cddd13504c137265a417dce28353b07119eb Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 17 Nov 2017 03:15:58 -0600 Subject: [PATCH 014/157] Fix PocketBeagle PWM pin typo (#192) ehrpwm0 channel 1 is P1_33 on a the PocketBeagle Signed-off-by: Drew Fustini --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index 1a9cf31..e000a66 100644 --- a/source/common.c +++ b/source/common.c @@ -301,7 +301,7 @@ pwm_t pwm_table[] = { { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_8"}, { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_36"}, { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_10"}, - { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_13"}, + { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_33"}, { "ehrpwm1", 3, 0, 6, "ehrpwm.1:0", "EHRPWM1A", "48302000", "48302200", "P2_1"}, { "ehrpwm2", 6, 1, 3, "ehrpwm.2:1", "EHRPWM2B", "48304000", "48304200", "P2_3"}, { NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } From 32814797ffeafccdc07491243deca5760759ab54 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 19 Nov 2017 05:17:22 +0000 Subject: [PATCH 015/157] cache board type to avoid poor performance (#196) cache board type to avoid poor performance in functions that are called frequently like gpio_set_value() in source/event_gpio.c Signed-off-by: Drew Fustini --- source/common.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/source/common.c b/source/common.c index e000a66..d940042 100644 --- a/source/common.c +++ b/source/common.c @@ -601,23 +601,30 @@ int pocketbeagle(void) { */ int beaglebone_blue(void) { const char *cmd = "/bin/grep -c 'TI AM335x BeagleBone Blue' /proc/device-tree/model"; - char blue; + // cache the value to avoid poor performance + // in functions that are called frequently like + // gpio_set_value() in source/event_gpio.c + static int initialized = 0; + static int retval = 0; FILE *file = NULL; - file = popen(cmd, "r"); - if (file == NULL) { - fprintf(stderr, "error: beaglebone_blue() failed to run cmd=%s\n", cmd); - syslog(LOG_ERR, "Adafruit_BBIO: error: beaglebone_blue() failed to run cmd=%s\n", cmd); - return -1; + //fprintf(stderr, "beaglebone_blue(): initialized=[%d] retval=[%d]\n", initialized, retval); + if(!initialized) { + initialized = 1; + //fprintf(stderr, "beaglebone_blue(): not initialized\n"); + file = popen(cmd, "r"); + if (file == NULL) { + fprintf(stderr, "Adafruit_BBIO: error in beaglebone_blue(): failed to run cmd=%s\n", cmd); + syslog(LOG_ERR, "Adafruit_BBIO: error in beaglebone_blue(): failed to run cmd=%s\n", cmd); + return -1; + } + if( fgetc(file) == '1' ) { + retval = 1; + } + pclose(file); } - blue = fgetc(file); - pclose(file); - if(blue == '1') { - return 1; - } else { - return 0; - } + return retval; } From 353acf8472b12182a2def84c605e697a9602551f Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 19 Nov 2017 23:12:45 +0000 Subject: [PATCH 016/157] create release 1.0.8 Release 1.0.8: ============== Fixes: Issue #196: cache board type to avoid poor performance Issue #192: fix PocketBeagle PWM pin typo Issue #191: turn off RotaryEncoder's debug output by default Issue #188: GPIO is extremely slow (20ms to toggle) Issue #186: problems with UART shortlog: David Planella (12): Copy Encoder module comments to README.md Formatted Encoder README in markdown Fixed Encoder README formatting Removed QEP instructions from Encoder module Fixes to Encoder README Updated Encoder README Encoder README: added info on dedicated overlays Encoder README: updated info on pre-requisites Encoder README update Encoder README update Add logging support, turn off unconditional debug output Encoder: remove unused logging code Drew Fustini (3): Merge pull request #195 from dplanella/master Fix PocketBeagle PWM pin typo (#192) cache board type to avoid poor performance (#196) Signed-off-by: Drew Fustini --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3cdcd6..636f8a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +1.0.8 +---- +**Fixes:** +* Issue #196: cache board type to avoid poor performance +* Issue #192: fix PocketBeagle PWM pin typo +* Issue #191: turn off RotaryEncoder's debug output by default +* Issue #188: GPIO is extremely slow (20ms to toggle) +* Issue #186: problems with UART + +**shortlog:** +* David Planella (12): + * Copy Encoder module comments to README.md + * Formatted Encoder README in markdown + * Fixed Encoder README formatting + * Removed QEP instructions from Encoder module + * Fixes to Encoder README + * Updated Encoder README + * Encoder README: added info on dedicated overlays + * Encoder README: updated info on pre-requisites + * Encoder README update + * Encoder README update + * Add logging support, turn off unconditional debug output + * Encoder: remove unused logging code + +* Drew Fustini (3): + * Merge pull request #195 from dplanella/master + * Fix PocketBeagle PWM pin typo (#192) + * cache board type to avoid poor performance (#196) + 1.0.7 ---- **Fixes:** diff --git a/setup.py b/setup.py index 3e9b78b..991b476 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.0.7', + version = '1.0.8', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From a0c7f1c2cb050ae4788e3accc144a846fd62bfc5 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 22 Nov 2017 01:16:08 -0600 Subject: [PATCH 017/157] use https for DEFAULT_URL in distribute_setup.py (#198) From issue #198, volinthius writes: > distribute_setup.py has obsolete DEFAULT_URL, which I think is related to this > https://mail.python.org/pipermail/distutils-sig/2017-October/031712.html Signed-off-by: Drew Fustini --- distribute_setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distribute_setup.py b/distribute_setup.py index c67b752..5b31634 100644 --- a/distribute_setup.py +++ b/distribute_setup.py @@ -50,7 +50,7 @@ def quote(arg): return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 DEFAULT_VERSION = "0.6.45" -DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" +DEFAULT_URL = "https://pypi.python.org/packages/source/d/distribute/" SETUPTOOLS_FAKED_VERSION = "0.6c11" SETUPTOOLS_PKG_INFO = """\ From cd6b0a721a74260d881364298104317656f28115 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 22 Nov 2017 03:23:31 -0600 Subject: [PATCH 018/157] fix except syntax for Python 3 Signed-off-by: Drew Fustini --- test/test_led.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_led.py b/test/test_led.py index fa197a2..29560e4 100644 --- a/test/test_led.py +++ b/test/test_led.py @@ -25,7 +25,7 @@ def set_brightness(self, state, led, name): def read_led_file(self, path): try: return open(path).read() - except IOError, e: + except (IOError, e): if e.errno == errno.ENOENT: return -1 From 2f54b4e788fb0a41cfbb325d837359d51eefa26d Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 22 Nov 2017 03:26:11 -0600 Subject: [PATCH 019/157] use dict.items() instead of dict.iteritems() for Python 3 from: https://wiki.python.org/moin/Python3.0 > Remove dict.iteritems(), dict.iterkeys(), and dict.itervalues(). > Instead: use dict.items(), dict.keys(), and dict.values() respectively. Signed-off-by: Drew Fustini --- test/test_led.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_led.py b/test/test_led.py index 29560e4..ed8f57d 100644 --- a/test/test_led.py +++ b/test/test_led.py @@ -34,7 +34,7 @@ def set_all_leds(self, state): "USR1": "mmc0", \ "USR2": "cpu0", \ "USR3": "mmc1" } - for led, name in test_leds.iteritems(): + for led, name in test_leds.items(): self.set_brightness(state, led, name) GPIO.cleanup() From fff7617a15c39e5f5e20f0a340e71a28a02c8235 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 22 Nov 2017 03:30:22 -0600 Subject: [PATCH 020/157] fix error in set_brightness() Resolve error that occurs in set_brightness(): E TypeError: unorderable types: str() < int() Signed-off-by: Drew Fustini --- test/test_led.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_led.py b/test/test_led.py index ed8f57d..97dca13 100644 --- a/test/test_led.py +++ b/test/test_led.py @@ -14,7 +14,7 @@ def set_brightness(self, state, led, name): prefix = "/sys/class/leds/beaglebone:green:{0}/brightness" path = prefix.format(led.lower()) value = self.read_led_file(path) - if value < 0: + if value == "": path = prefix.format(name) value = self.read_led_file(path) if state == 1: @@ -27,7 +27,7 @@ def read_led_file(self, path): return open(path).read() except (IOError, e): if e.errno == errno.ENOENT: - return -1 + return "" def set_all_leds(self, state): test_leds = { "USR0": "heartbeat", \ From f82ba3a1ec706c1ba0b93c406268a0e65a29c512 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 22 Nov 2017 04:31:00 -0600 Subject: [PATCH 021/157] close enable_fd when stopping PWM output (#197) Issue #197: JesseMcL raised the issue that running PWM.start() and PWM.start() in a loop will eventually exhaust the number of open file descriptors and PWM.start() will raise the error: RuntimeError: problem with sysfs file. The file descriptor for the enable file should be closed in pwm_disable() to avoid the leak Signed-off-by: Drew Fustini --- source/c_pwm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/c_pwm.c b/source/c_pwm.c index 55afd09..ccf4a0c 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -717,6 +717,9 @@ BBIO_err pwm_disable(const char *key) #endif //close the fd +#ifdef BBBVERSION41 + close(pwm->enable_fd); +#endif close(pwm->period_fd); close(pwm->duty_fd); close(pwm->polarity_fd); From 9dc57bf4daf584d5eaee57a6351f210b3c3ad615 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 24 Nov 2017 02:11:54 +0100 Subject: [PATCH 022/157] Encoder: initialize only the given channel --- Adafruit_BBIO/Encoder.py | 165 +++++++++++++++------------------------ 1 file changed, 65 insertions(+), 100 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 596f0c2..e978c90 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -3,53 +3,62 @@ from subprocess import check_output, STDOUT, CalledProcessError import os import logging - - -class QEP : - - def __init__(self, channel=1, debug=False): - self.channel = channel - self.debug = debug - - def errMsg(self): - print("Error accessing 0x%02X: Check your QEP channel" % self.address) - return -1 - -# example method from Adafruit_I2C -# TODO: delete this -# def write8(self, reg, value): -# "Writes an 8-bit value to the specified register/address" -# try: -# self.bus.write_byte_data(self.address, reg, value) -# if self.debug: -# print("Rotary: Wrote 0x%02X to register 0x%02X" % (value, reg)) -# except IOError as err: -# return self.errMsg() -# -# -#if __name__ == '__main__': -# try: -# qep = Adafruit_BBIO.Encoder.QEP() -# print("Default QEP channel is accessible") -# except: -# print("Error accessing default Rotary bus") - +import itertools + +eQEP0 = 0 +eQEP1 = 1 +eQEP2 = 2 +eQEP2b = 3 + +_OCP_PATH = "/sys/devices/platform/ocp" +_eQEP_DEFS = [ + {'channel': 'eQEP0', 'pin_A': 'P9_92', 'pin_B': 'P9_27', + 'sys_path': os.path.join(_OCP_PATH, '48300000.epwmss/48300180.eqep')}, + {'channel': 'eQEP1', 'pin_A': 'P8_35', 'pin_B': 'P8_33', + 'sys_path': os.path.join(_OCP_PATH, '48302000.epwmss/48302180.eqep')}, + {'channel': 'eQEP2', 'pin_A': 'P8_12', 'pin_B': 'P8_11', + 'sys_path': os.path.join(_OCP_PATH, '48304000.epwmss/48304180.eqep')}, + {'channel': 'eQEP2b', 'pin_A': 'P8_41', 'pin_B': 'P8_42', + 'sys_path': os.path.join(_OCP_PATH, '48304000.epwmss/48304180.eqep')} +] + + +class eQEP(object): + '''Enhanced Quadrature Encoder Pulse (eQEP) module class. Abstraction + for either of the three available channels (eQEP0, eQEP1, eQEP2) on + the Beaglebone''' + + @classmethod + def fromdict(cls, d): + '''Creates a class instance from a dictionary''' + + allowed = ('channel', 'pin_A', 'pin_B', 'sys_path') + df = {k: v for k, v in d.iteritems() if k in allowed} + return cls(**df) + + def __init__(self, channel, pin_A, pin_B, sys_path): + '''Initialize the eQEP module + + Attributes: + channel (str): eQEP channel name. E.g. "eQEP0", "eQEP1", etc. + Note that "eQEP2" and "eQEP2b" are channel aliases for the + same module, but on different (mutually-exclusive) sets of + pins + pin_A (str): physical input pin for the A signal of the + rotary encoder + pin_B (str): physical input pin for the B signal of the + rotary encoder + sys_path (str): sys filesystem path to access the attributes + of this eQEP module + + ''' + self.channel = channel + self.pin_A = pin_A + self.pin_B = pin_B + self.sys_path = sys_path class RotaryEncoder(object): - # TODO: check that kernel 4.1+ - # TODO: use config-pin to set qep mode - OCP_PATH = "/sys/devices/platform/ocp" - _eqep_dirs = [ - '%s/48300000.epwmss/48300180.eqep' % OCP_PATH, - '%s/48302000.epwmss/48302180.eqep' % OCP_PATH, - '%s/48304000.epwmss/48304180.eqep' % OCP_PATH - ] - - EQEP0 = 0 - EQEP1 = 1 - EQEP2 = 2 - EQEP2b = 3 def _run_cmd(self, cmd): '''Runs a command. If not successful (i.e. error code different than zero), @@ -93,64 +102,19 @@ def __init__(self, eqep_num): self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) - # Configure eqep0 - self._logger.info("Configuring eqep0, pins: P9.27, P9.92") - - pin = "P9_27" - self.config_pin(pin) - - pin = "P9_92" - self.config_pin(pin) - - path = "/sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position" - self.cat_file(path) - - # Configure eqep1 - self._logger.info("Configuring eqep1, pins: P8.33, P8.35") - - pin = "P8.33" - self.config_pin(pin) - - pin = "P8.35" - self.config_pin(pin) - - path = "/sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position" - self.cat_file(path); - - # Configure eqep2 - self._logger.info("Configuring eqep2, pins: P8.11, P8.12") - - pin = "P8.11" - self.config_pin(pin) - - pin = "P8.12" - self.config_pin(pin) - - path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" - self.cat_file(path); - - # Configure eqep2b - self._logger.info("Configuring eqep2, pins: P8.41, P8.42") - - pin = "P8.41" - self.config_pin(pin) - - pin = "P8.42" - self.config_pin(pin) - - path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" - self.cat_file(path); - - self._logger.debug("RotaryEncoder(): eqep_num: {0}".format(eqep_num)) - self._logger.debug("RotaryEncoder(): self._eqep_dirs[0]: {0}".format(self._eqep_dirs[0])) - self._logger.debug("RotaryEncoder(): self._eqep_dirs[1]: {0}".format(self._eqep_dirs[1])) - self._logger.debug("RotaryEncoder(): self._eqep_dirs[2]: {0}".format(self._eqep_dirs[2])) - self._logger.debug("RotaryEncoder(): self._eqep_dirs[eqep_num: {0}]: {1}".format(eqep_num, self._eqep_dirs[eqep_num])) + # Configure eqep module + self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) + self._logger.info( + "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( + self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, + self._eqep.sys_path)) - assert 0 <= eqep_num <= 3 , "eqep_num must be between 0 and 3" + self.config_pin(self._eqep.pin_A) + self.config_pin(self._eqep.pin_B) - self.base_dir = self._eqep_dirs[eqep_num] - self._logger.debug("RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + self.base_dir = self._eqep.sys_path + self._logger.debug( + "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) self.enable() @@ -220,6 +184,7 @@ def getPosition(self): In relative mode, this attribute represents the position of the encoder at the last unit timer overflow. ''' + self._logger.debug("Channel: {}".format(self._eqep.channel)) position_file = "%s/position" % self.base_dir self._logger.debug("getPosition(): position_file: {0}".format(position_file)) position_handle = open(position_file, 'r') From 503e8397e64e20befdf5231485c693be39d263fc Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 24 Nov 2017 00:29:04 -0600 Subject: [PATCH 023/157] Fix leak of pwm enable file descriptor (#197) Make sure that the file descriptor for pwm enable is closed along with the other pwm file descriptors Signed-off-by: Drew Fustini --- source/c_pwm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/c_pwm.c b/source/c_pwm.c index ccf4a0c..e6bc7b0 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -553,6 +553,9 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri close(period_fd); close(duty_fd); close(polarity_fd); +#ifdef BBBVERSION41 + close(enable_fd); +#endif syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't malloc pwm_exp: %i-%s", key, errno, strerror(errno)); return BBIO_MEM; // out of memory From f8c730ee591ce691acfe4c555606dc2a179eeacb Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 24 Nov 2017 12:02:45 +0100 Subject: [PATCH 024/157] Encoder: do kernel check, PEP8 cleanup - Added a check for kernels >= 4.4 - Cleaned up formatting for the module to be PEP8-compliant --- Adafruit_BBIO/Encoder.py | 373 +++++++++++++++++++-------------------- 1 file changed, 183 insertions(+), 190 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index e978c90..4c65c8a 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -4,6 +4,13 @@ import os import logging import itertools +import platform + +if not platform.release().startswith('4.4'): + raise ImportError( + 'The Encoder module requires Linux kernel version >= 4.4.x.\n' + 'Please upgrade your kernel to use this module.\n' + 'Your Linux kernel version is {}.'.format(platform.release())) eQEP0 = 0 eQEP1 = 1 @@ -60,193 +67,179 @@ def __init__(self, channel, pin_A, pin_B, sys_path): class RotaryEncoder(object): - def _run_cmd(self, cmd): - '''Runs a command. If not successful (i.e. error code different than zero), - print the stderr output as a warning. - ''' - - try: - output = check_output(cmd, stderr=STDOUT) - self._logger.info("_run_cmd(): cmd='{}' return code={} output={}".format( - " ".join(cmd), 0, output)) - except CalledProcessError as e: - self._logger.warning( - "_run_cmd(): cmd='{}' return code={} output={}".format( - " ".join(cmd), e.returncode, e.output)) - - def config_pin(self, pin): - ''' - config_pin() - Config pin for QEP - ''' - - self._run_cmd(["config-pin", pin, "qep"]) - - def cat_file(self, path): - ''' - cat_file() - Print contents of file - ''' - - self._run_cmd(["cat", path]) - - def __init__(self, eqep_num): - ''' - RotaryEncoder(eqep_num) - Creates an instance of the class RotaryEncoder. - eqep_num determines which eQEP pins are set up. - eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ - the rotary encoder is connected to. - ''' - - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - # Configure eqep module - self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) - self._logger.info( - "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( - self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, - self._eqep.sys_path)) - - self.config_pin(self._eqep.pin_A) - self.config_pin(self._eqep.pin_B) - - self.base_dir = self._eqep.sys_path - self._logger.debug( - "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) - - self.enable() - - def enable(self): - ''' - enable() - Turns the eQEP hardware ON - ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("enable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) - #return sysfs.kernelFileIO(enable_file, '1') - - def disable(self): - ''' - disable() - Turns the eQEP hardware OFF - ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("disable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "disable(): TODO: not implemented, write 0 to {}".format(enable_file)) - #return sysfs.kernelFileIO(enable_file, '0') - - def setAbsolute(self): - ''' - setAbsolute() - Set mode as Absolute - The position starts at zero and is incremented or - decremented by the encoder's movement - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setAbsolute(): TODO: not implemented, write 0 to {}".format(mode_file)) - #return sysfs.kernelFileIO(mode_file, '0') - - def setRelative(self): - ''' - setRelative() - Set mode as Relative - The position is reset when the unit timer overflows. - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setRelative(): TODO: not implemented, write 1 to {}".format(mode_file)) - #return sysfs.kernelFileIO(mode_file, '1') - - def getMode(self): - ''' - getMode() - Returns the mode the eQEP hardware is in. - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) - self._logger.warning("getMode(): TODO: read mode_file") - #return sysfs.kernelFileIO(mode_file) - - def getPosition(self): - ''' - getPosition() - Get the current position of the encoder. - In absolute mode, this attribute represents the current position - of the encoder. - In relative mode, this attribute represents the position of the - encoder at the last unit timer overflow. - ''' - self._logger.debug("Channel: {}".format(self._eqep.channel)) - position_file = "%s/position" % self.base_dir - self._logger.debug("getPosition(): position_file: {0}".format(position_file)) - position_handle = open(position_file, 'r') - self._logger.debug("getPosition(): position_handle: {0}".format(position_handle)) - position = position_handle.read() - self._logger.debug("getPosition(): position: {0}".format(position)) - #return sysfs.kernelFileIO(position_file) - - return position - - def setFrequency(self, freq): - ''' - setFrequency(freq) - Set the frequency in Hz at which the driver reports new positions. - ''' - period_file = "%s/period" % self.base_dir - self._logger.debug("setFrequency(): period_file: {0}".format(period_file)) - self._logger.debug("setFrequency(): freq: {0}".format(freq)) - self._logger.debug("setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) - self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format(str(1000000000/freq))) - self._logger.warning( - "setFrequency(): TODO: not implemented, set {} to {}".format( - period_file, str(1000000000/freq))) - #return sysfs.kernelFileIO(period_file, str(1000000000/freq)) - - def setPosition(self, val): - ''' - setPosition(value) - Give a new value to the current position - ''' - position_file = "%s/position" % self.base_dir - self._logger.warning( - "setPosition(): TODO: not implemented, write position to {}".format( - position_file)) - #return sysfs.kernelFileIO(position_file, str(val)) - - def zero(self): - ''' - zero()s - Set the current position to 0 - ''' - return self.setPosition(0) - - -#""" -# encoder_test.py -# Rekha Seethamraju -# An example to demonstrate the use of the eQEP library -# for PyBBIO. -# This example program is in the public domain. -#""" -#from bbio import * -#from bbio.libraries.RotaryEncoder import RotaryEncoder -# -#encoder = RotaryEncoder(RotaryEncoder.EQEP2b) -# -#def setup(): -# encoder.setAbsolute() -# encoder.zero() -# -#def loop(): -# print("encoder position : "+encoder.getPosition()) -# delay(1000) -# -#run(setup, loop) + def _run_cmd(self, cmd): + '''Runs a command. If not successful (i.e. error code different than + zero), print the stderr output as a warning. + ''' + + try: + output = check_output(cmd, stderr=STDOUT) + self._logger.info( + "_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), 0, output)) + except CalledProcessError as e: + self._logger.warning( + "_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), e.returncode, e.output)) + + def config_pin(self, pin): + ''' + config_pin() + Config pin for QEP + ''' + + self._run_cmd(["config-pin", pin, "qep"]) + + def cat_file(self, path): + ''' + cat_file() + Print contents of file + ''' + + self._run_cmd(["cat", path]) + + def __init__(self, eqep_num): + ''' + RotaryEncoder(eqep_num) + Creates an instance of the class RotaryEncoder. + eqep_num determines which eQEP pins are set up. + eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ + the rotary encoder is connected to. + ''' + + self._logger = logging.getLogger(__name__) + self._logger.addHandler(logging.NullHandler()) + + # Configure eqep module + self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) + self._logger.info( + "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( + self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, + self._eqep.sys_path)) + + self.config_pin(self._eqep.pin_A) + self.config_pin(self._eqep.pin_B) + + self.base_dir = self._eqep.sys_path + self._logger.debug( + "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + + self.enable() + + def enable(self): + ''' + enable() + Turns the eQEP hardware ON + ''' + enable_file = "%s/enabled" % self.base_dir + self._logger.debug("enable(): enable_file: {0}".format(enable_file)) + self._logger.warning( + "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) + # return sysfs.kernelFileIO(enable_file, '1') + + def disable(self): + ''' + disable() + Turns the eQEP hardware OFF + ''' + enable_file = "%s/enabled" % self.base_dir + self._logger.debug("disable(): enable_file: {0}".format(enable_file)) + self._logger.warning( + "disable(): TODO: not implemented, write 0 to {}".format( + enable_file)) + # return sysfs.kernelFileIO(enable_file, '0') + + def setAbsolute(self): + ''' + setAbsolute() + Set mode as Absolute + The position starts at zero and is incremented or + decremented by the encoder's movement + ''' + mode_file = "%s/mode" % self.base_dir + self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) + self._logger.warning( + "setAbsolute(): TODO: not implemented, write 0 to {}".format( + mode_file)) + # return sysfs.kernelFileIO(mode_file, '0') + + def setRelative(self): + ''' + setRelative() + Set mode as Relative + The position is reset when the unit timer overflows. + ''' + mode_file = "%s/mode" % self.base_dir + self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) + self._logger.warning( + "setRelative(): TODO: not implemented, write 1 to {}".format( + mode_file)) + # return sysfs.kernelFileIO(mode_file, '1') + + def getMode(self): + ''' + getMode() + Returns the mode the eQEP hardware is in. + ''' + mode_file = "%s/mode" % self.base_dir + self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) + self._logger.warning("getMode(): TODO: read mode_file") + # return sysfs.kernelFileIO(mode_file) + + def getPosition(self): + ''' + getPosition() + Get the current position of the encoder. + In absolute mode, this attribute represents the current position + of the encoder. + In relative mode, this attribute represents the position of the + encoder at the last unit timer overflow. + ''' + self._logger.debug("Channel: {}".format(self._eqep.channel)) + position_file = "%s/position" % self.base_dir + self._logger.debug( + "getPosition(): position_file: {0}".format(position_file)) + position_handle = open(position_file, 'r') + self._logger.debug( + "getPosition(): position_handle: {0}".format(position_handle)) + position = position_handle.read() + self._logger.debug("getPosition(): position: {0}".format(position)) + # return sysfs.kernelFileIO(position_file) + + return position + + def setFrequency(self, freq): + ''' + setFrequency(freq) + Set the frequency in Hz at which the driver reports new positions. + ''' + period_file = "%s/period" % self.base_dir + self._logger.debug( + "setFrequency(): period_file: {0}".format(period_file)) + self._logger.debug("setFrequency(): freq: {0}".format(freq)) + self._logger.debug( + "setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) + self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format( + str(1000000000/freq))) + self._logger.warning( + "setFrequency(): TODO: not implemented, set {} to {}".format( + period_file, str(1000000000/freq))) + # return sysfs.kernelFileIO(period_file, str(1000000000/freq)) + + def setPosition(self, val): + ''' + setPosition(value) + Give a new value to the current position + ''' + position_file = "%s/position" % self.base_dir + self._logger.warning( + "setPosition(): TODO: not implemented, write position to {}".format( + position_file)) + # return sysfs.kernelFileIO(position_file, str(val)) + + def zero(self): + ''' + zero()s + Set the current position to 0 + ''' + return self.setPosition(0) From 07b6c14de5ead30144bc43e77847a7b1bf57c947 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 24 Nov 2017 14:30:00 +0100 Subject: [PATCH 025/157] Encoder: added sysfs module --- Adafruit_BBIO/sysfs.py | 116 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Adafruit_BBIO/sysfs.py diff --git a/Adafruit_BBIO/sysfs.py b/Adafruit_BBIO/sysfs.py new file mode 100644 index 0000000..a79cfb9 --- /dev/null +++ b/Adafruit_BBIO/sysfs.py @@ -0,0 +1,116 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2014 MIT OpenCourseWare +# +# 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. +# +# Code originally published at http://stackoverflow.com/questions/4648792/ and +# subsequently forked at https://github.com/ponycloud/python-sysfs +# +# Original author: Benedikt Reinartz +# Contributors: +# - Jan Dvořák +# - Jonathon Reinhart https://github.com/JonathonReinhart +# - Ondřej Koch +# - David Planella + +""" +Simplistic Python SysFS interface. + +Usage examples:: + from sysfs import sys + + # Print all block devices in /sys, with their sizes + for block_dev in sys.block: + print block_dev, str(int(block_dev.size) / 1048576) + ' M' + + >>> import sysfs + >>> # Read/write Beaglebone Black's eQEP module attributes + >>> eqep0 = sysfs.Node("/sys/devices/platform/ocp/48300000.epwmss/48300180.eqep") + >>> # Read eqep attributes + >>> eqep0.enabled + '1' + >>> eqep0.mode + '0' + >>> eqep0.period + '1000000000' + >>> eqep0.position + '0' + >>> # Write eqep attributes. They should be strings. + >>> eqep0.position = str(2) + >>> eqep0.position + '2' +""" + +from os import listdir +from os.path import isdir, isfile, join, realpath, basename + +__all__ = ['sys', 'Node'] + + +class Node(object): + __slots__ = ['_path_', '__dict__'] + + def __init__(self, path='/sys'): + self._path_ = realpath(path) + if not self._path_.startswith('/sys/') and not '/sys' == self._path_: + raise RuntimeError('Using this on non-sysfs files is dangerous!') + + self.__dict__.update(dict.fromkeys(listdir(self._path_))) + + def __repr__(self): + return '' % self._path_ + + def __str__(self): + return basename(self._path_) + + def __setattr__(self, name, val): + if name.startswith('_'): + return object.__setattr__(self, name, val) + + path = realpath(join(self._path_, name)) + if isfile(path): + with open(path, 'w') as fp: + fp.write(val) + else: + raise RuntimeError('Cannot write to non-files.') + + def __getattribute__(self, name): + if name.startswith('_'): + return object.__getattribute__(self, name) + + path = realpath(join(self._path_, name)) + if isfile(path): + with open(path, 'r') as fp: + return fp.read().strip() + elif isdir(path): + return Node(path) + + def __setitem__(self, name, val): + return setattr(self, name, val) + + def __getitem__(self, name): + return getattr(self, name) + + def __iter__(self): + return iter(getattr(self, name) for name in listdir(self._path_)) + + +sys = Node() From 1fdedc59e1eebf17737f5706bc2eaa9e50d4a331 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 24 Nov 2017 14:32:21 +0100 Subject: [PATCH 026/157] Encoder: use sysfs to write QEP attributes --- Adafruit_BBIO/Encoder.py | 201 +++++++++++++++++++-------------------- 1 file changed, 97 insertions(+), 104 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 4c65c8a..35e3efb 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -4,6 +4,7 @@ import os import logging import itertools +import sysfs import platform if not platform.release().startswith('4.4'): @@ -57,12 +58,15 @@ def __init__(self, channel, pin_A, pin_B, sys_path): rotary encoder sys_path (str): sys filesystem path to access the attributes of this eQEP module + node (str): sys filesystem device node that contains the + readable or writable attributes to control the QEP channel ''' self.channel = channel self.pin_A = pin_A self.pin_B = pin_B self.sys_path = sys_path + self.node = sysfs.Node(sys_path) class RotaryEncoder(object): @@ -90,156 +94,145 @@ def config_pin(self, pin): self._run_cmd(["config-pin", pin, "qep"]) - def cat_file(self, path): - ''' - cat_file() - Print contents of file - ''' - - self._run_cmd(["cat", path]) - def __init__(self, eqep_num): - ''' - RotaryEncoder(eqep_num) - Creates an instance of the class RotaryEncoder. - eqep_num determines which eQEP pins are set up. - eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ - the rotary encoder is connected to. - ''' + '''Creates an instance of the class RotaryEncoder. + Arguments: + eqep_num: determines which eQEP pins are set up. + Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, + based on which pins the physical rotary encoder + is connected to. + + ''' + # Set up logging at the module level self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) - # Configure eqep module + # Initialize the eQEP channel structures self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) self._logger.info( "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, self._eqep.sys_path)) + # Configure the pins for the given channel self.config_pin(self._eqep.pin_A) self.config_pin(self._eqep.pin_B) - self.base_dir = self._eqep.sys_path self._logger.debug( - "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + "RotaryEncoder(): sys node: {0}".format(self._eqep.sys_path)) + # Enable the channel upon initialization self.enable() - def enable(self): - ''' - enable() - Turns the eQEP hardware ON + def _setEnable(self, value): + '''Turns the eQEP hardware ON or OFF + + value (int): 1 represents enabled, 0 is disabled ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("enable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) - # return sysfs.kernelFileIO(enable_file, '1') + if value < 0 or value > 1: + raise ValueError( + 'The "enabled" attribute can only be set to 0 or 1. ' + 'You attempted to set it to {}.'.format(value)) + + self._eqep.node.enabled = str(int(value)) + self._logger.info("Channel: {}, enabled: {}".format( + self._eqep.channel, self._eqep.node.enabled)) + + def enable(self): + '''Turns the eQEP hardware ON''' + + self._setEnable(1) def disable(self): + '''Turns the eQEP hardware OFF''' + + self._setEnable(0) + + def _setMode(self, value): + '''Sets the eQEP mode as absolute (0) or relative (1). + See the setAbsolute() and setRelative() methods for + more information. + ''' - disable() - Turns the eQEP hardware OFF - ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("disable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "disable(): TODO: not implemented, write 0 to {}".format( - enable_file)) - # return sysfs.kernelFileIO(enable_file, '0') + if value < 0 or value > 1: + raise ValueError( + 'The "mode" attribute can only be set to 0 or 1. ' + 'You attempted to set it to {}.'.format(value)) + + self._eqep.node.mode = str(int(value)) + self._logger.debug("Mode set to: {}".format( + self._eqep.node.mode)) def setAbsolute(self): - ''' - setAbsolute() - Set mode as Absolute + '''Sets the eQEP mode as Absolute: The position starts at zero and is incremented or decremented by the encoder's movement + ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setAbsolute(): TODO: not implemented, write 0 to {}".format( - mode_file)) - # return sysfs.kernelFileIO(mode_file, '0') + self._setMode(0) def setRelative(self): - ''' - setRelative() - Set mode as Relative + '''Sets the eQEP mode as Relative: The position is reset when the unit timer overflows. + ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setRelative(): TODO: not implemented, write 1 to {}".format( - mode_file)) - # return sysfs.kernelFileIO(mode_file, '1') + self._setMode(1) def getMode(self): + '''Returns the mode the eQEP hardware is in (absolute or relative). + ''' - getMode() - Returns the mode the eQEP hardware is in. - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) - self._logger.warning("getMode(): TODO: read mode_file") - # return sysfs.kernelFileIO(mode_file) + + mode = int(self._eqep.node.mode) + + if mode == 0: + mode_name = "absolute" + elif mode == 1: + mode_name = "relative" + else: + mode_name = "invalid" + + self._logger.debug("getMode(): Channel {}, mode: {} ({})".format( + self._eqep.channel, mode, mode_name)) + + return mode def getPosition(self): - ''' - getPosition() - Get the current position of the encoder. + '''Returns the current position of the encoder. In absolute mode, this attribute represents the current position of the encoder. In relative mode, this attribute represents the position of the encoder at the last unit timer overflow. + ''' - self._logger.debug("Channel: {}".format(self._eqep.channel)) - position_file = "%s/position" % self.base_dir - self._logger.debug( - "getPosition(): position_file: {0}".format(position_file)) - position_handle = open(position_file, 'r') - self._logger.debug( - "getPosition(): position_handle: {0}".format(position_handle)) - position = position_handle.read() - self._logger.debug("getPosition(): position: {0}".format(position)) - # return sysfs.kernelFileIO(position_file) + position = self._eqep.node.position + + self._logger.debug("getPosition(): Channel {}, position: {}".format( + self._eqep.channel, position)) - return position + return int(position) def setFrequency(self, freq): + '''Sets the frequency in Hz at which the driver reports + new positions. + ''' - setFrequency(freq) - Set the frequency in Hz at which the driver reports new positions. - ''' - period_file = "%s/period" % self.base_dir - self._logger.debug( - "setFrequency(): period_file: {0}".format(period_file)) - self._logger.debug("setFrequency(): freq: {0}".format(freq)) + ns_factor = 1000000000 + period = ns_factor/freq # Period in nanoseconds + self._eqep.node.period = str(period) self._logger.debug( - "setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) - self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format( - str(1000000000/freq))) - self._logger.warning( - "setFrequency(): TODO: not implemented, set {} to {}".format( - period_file, str(1000000000/freq))) - # return sysfs.kernelFileIO(period_file, str(1000000000/freq)) - - def setPosition(self, val): - ''' - setPosition(value) - Give a new value to the current position - ''' - position_file = "%s/position" % self.base_dir - self._logger.warning( - "setPosition(): TODO: not implemented, write position to {}".format( - position_file)) - # return sysfs.kernelFileIO(position_file, str(val)) + "setFrequency(): Channel {}, frequency: {} Hz, " + "period: {} ns".format( + self._eqep.channel, freq, period)) + + def setPosition(self, position): + '''Sets the current position to a new value''' + + position = int(position) + self._eqep.node.position = str(position) def zero(self): - ''' - zero()s - Set the current position to 0 - ''' + '''Resets the current position to 0''' + return self.setPosition(0) From a666e500dfcd4e71d44f9f28589a4012be31a153 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sat, 25 Nov 2017 05:04:55 -0600 Subject: [PATCH 027/157] remove test_rotary.py as not valid for pytest --- test/test_rotary.py | 74 --------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100755 test/test_rotary.py diff --git a/test/test_rotary.py b/test/test_rotary.py deleted file mode 100755 index 2292cd0..0000000 --- a/test/test_rotary.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/python -# -# BeagleBone must boot with cape-universal enabled -# and load the cape-universala overlay in order to -# use all the eQEP pins -# -# Install the latest Device Tree overlays: -# ======================================== -# sudo apt-get upgrade bb-cape-overlays -# -# File: /boot/uEnv.txt -# ==================== -# uname_r=4.4.62-ti-r99 -# cmdline=coherent_pool=1M quiet cape_universal=enable -# cape_enable=bone_capemgr.enable_partno=cape-universala -# -# File: /sys/devices/platform/bone_capemgr/slots -# ============================================== -# 0: PF---- -1 -# 1: PF---- -1 -# 2: PF---- -1 -# 3: PF---- -1 -# 4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universala -# -# eqep0: P9_27, P9_92 -# =================== -# config-pin P9_27 qep -# config-pin P9_92 qep # alias for P9_42.1 -# cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position -# -# eqep1: P8.33, P8.35 -# =================== -# config-pin P8.33 qep -# config-pin P8.35 qep -# cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position -# -# eqep2: P8.11, P8.12 -# =================== -# config-pin P8.11 qep -# config-pin P8.12 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# alternate pins for eqep2 (mutually exclusive) -# eqep2b: P8.41, P8.42 -# ==================== -# config-pin P8.41 qep -# config-pin P8.42 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# -# How To Run This Test: -# debian@beaglebone:~/ssh/adafruit-beaglebone-io-python$ sudo python ./setup.py install &> /dev/null && sudo python ./test/test_rotary.py -# -# - -import Adafruit_BBIO.Encoder as Encoder - -qep = Encoder.RotaryEncoder(0) -print("qep.getPosition(): {0}".format(qep.getPosition())) - -qep = Encoder.RotaryEncoder(1) -print("qep.getPosition(): {0}".format(qep.getPosition())) - -qep = Encoder.RotaryEncoder(2) -print("qep.getPosition(): {0}".format(qep.getPosition())) - - -#qep.getMode() -#qep.setAbsolute() -#qep.setRelative() -#qep.setFrequency(5000) -#qep.setPosition(100) -#qep.disable() -#print("qep.enable(): {0}".format(qep.enable())) From a22cd5fd241b2a36e748efc231f815750cd7c077 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sat, 25 Nov 2017 05:24:44 -0600 Subject: [PATCH 028/157] Fix seg fault of PWM in Python 3.6 (#189) PWM.set_frequency() and PWM.set_duty_cycle() were resulting in a seg fault inside the call to PyArg_ParseTupleAndKeywords(). Signed-off-by: Drew Fustini --- source/py_pwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/py_pwm.c b/source/py_pwm.c index 49c539b..55f50f9 100644 --- a/source/py_pwm.c +++ b/source/py_pwm.c @@ -217,8 +217,8 @@ static const char moduledocstring[] = "PWM functionality of a BeagleBone using P PyMethodDef pwm_methods[] = { {"start", (PyCFunction)py_start_channel, METH_VARARGS | METH_KEYWORDS, "Set up and start the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, {"stop", (PyCFunction)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, - { "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, - { "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, + { "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS | METH_KEYWORDS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, + { "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS | METH_KEYWORDS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, {"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"}, //{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, {NULL, NULL, 0, NULL} From 2d54d001eb5493f56a07a6e3a52de4edecb52489 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 25 Nov 2017 19:59:41 +0100 Subject: [PATCH 029/157] Encoder: corrected kernel check logic --- Adafruit_BBIO/Encoder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 4c65c8a..83fc057 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -6,7 +6,8 @@ import itertools import platform -if not platform.release().startswith('4.4'): +(major, minor, patch) = platform.release().split("-")[0].split(".") +if not (int(major) >= 4 and int(minor) >= 4): raise ImportError( 'The Encoder module requires Linux kernel version >= 4.4.x.\n' 'Please upgrade your kernel to use this module.\n' From 0e593a186952da962b5ca9af37a4b80de1495e6e Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 27 Nov 2017 22:52:23 -0600 Subject: [PATCH 030/157] Clarify there is no 0 prefix for pin lables (#180) Please note that there is no '0' prefix for the pin numbers. For example, pin 7 on header P8 is "P8_7" --- README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/README.md b/README.md index 32da985..6445bcf 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,22 @@ sudo pip install --upgrade Adafruit_BBIO Using the library is very similar to the excellent RPi.GPIO library used on the Raspberry Pi. Below are some examples. +### Pin Numbers + +Please note that there is no '0' prefix for the pin numbers. For example, pin 7 on header P8 is `P8_7`. + +**Correct:** +``` +GPIO.setup("P8_7", OUT ) +``` + +**INCORRECT:** +``` +GPIO.setup("P8_07", OUT ) +``` + +Refer to `pins_t table[]` in [common.c](https://github.com/adafruit/adafruit-beaglebone-io-python/blob/master/source/common.c#L73) all the pin labels. + ### config-pin [config-pin](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) is now used on the official BeagleBoard.org Debian Jessie and Stretch images to control pin mode (e.g. pin mux). From c7e5c9416541a2bc8b85daeace11a7aebf7e75e4 Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 28 Nov 2017 12:10:57 +0100 Subject: [PATCH 031/157] Encoder: convert get/set methods to properties, update apidoc strings --- Adafruit_BBIO/Encoder.py | 166 ++++++++++++++++++++++++++------------- 1 file changed, 113 insertions(+), 53 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 5c872d4..83c7a9f 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -14,11 +14,16 @@ 'Please upgrade your kernel to use this module.\n' 'Your Linux kernel version is {}.'.format(platform.release())) + +# eQEP module channel identifiers +# eQEP 2 and 2b are the same channel, exposed on two different sets of pins, +# which are mutually exclusive eQEP0 = 0 eQEP1 = 1 eQEP2 = 2 eQEP2b = 3 +# Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" _eQEP_DEFS = [ {'channel': 'eQEP0', 'pin_A': 'P9_92', 'pin_B': 'P9_27', @@ -71,12 +76,31 @@ def __init__(self, channel, pin_A, pin_B, sys_path): class RotaryEncoder(object): + ''' + Rotary encoder class abstraction to control a given QEP channel. + + Constructor: + eqep_num: QEP object that determines which channel to control + + Properties: + position: current position of the encoder + frequency: frequency at which the encoder reports new positions + enabled: (read only) true if the module is enabled, false otherwise + mode: current mode of the encoder (absolute: 0, relative: 1) + + Methods: + enable: enable the QEP channel + disable: disable the QEP channel + setAbsolute: shortcut for setting the mode to absolute + setRelative: shortcut for setting the mode to relative + zero: shortcut for setting the position to 0 + ''' def _run_cmd(self, cmd): '''Runs a command. If not successful (i.e. error code different than zero), print the stderr output as a warning. - ''' + ''' try: output = check_output(cmd, stderr=STDOUT) self._logger.info( @@ -87,11 +111,8 @@ def _run_cmd(self, cmd): "_run_cmd(): cmd='{}' return code={} output={}".format( " ".join(cmd), e.returncode, e.output)) - def config_pin(self, pin): - ''' - config_pin() - Config pin for QEP - ''' + def _config_pin(self, pin): + '''Configures a pin in QEP mode using the `config-pin` binary''' self._run_cmd(["config-pin", pin, "qep"]) @@ -103,8 +124,11 @@ def __init__(self, eqep_num): Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, based on which pins the physical rotary encoder is connected to. - + ''' + # nanoseconds factor to convert period to frequency and back + self._NS_FACTOR = 1000000000 + # Set up logging at the module level self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) @@ -117,8 +141,8 @@ def __init__(self, eqep_num): self._eqep.sys_path)) # Configure the pins for the given channel - self.config_pin(self._eqep.pin_A) - self.config_pin(self._eqep.pin_B) + self._config_pin(self._eqep.pin_A) + self._config_pin(self._eqep.pin_B) self._logger.debug( "RotaryEncoder(): sys node: {0}".format(self._eqep.sys_path)) @@ -126,19 +150,32 @@ def __init__(self, eqep_num): # Enable the channel upon initialization self.enable() - def _setEnable(self, value): + @property + def enabled(self): + '''Returns the enabled status of the module: + + true: module is enabled + false: module is disabled + ''' + isEnabled = bool(int(self._eqep.node.enabled)) + + return isEnabled + + def _setEnable(self, enabled): '''Turns the eQEP hardware ON or OFF value (int): 1 represents enabled, 0 is disabled + ''' - if value < 0 or value > 1: + enabled = int(enabled) + if enabled < 0 or enabled > 1: raise ValueError( 'The "enabled" attribute can only be set to 0 or 1. ' - 'You attempted to set it to {}.'.format(value)) + 'You attempted to set it to {}.'.format(enabled)) - self._eqep.node.enabled = str(int(value)) + self._eqep.node.enabled = str(enabled) self._logger.info("Channel: {}, enabled: {}".format( - self._eqep.channel, self._eqep.node.enabled)) + self._eqep.channel, self._eqep.node.enabled)) def enable(self): '''Turns the eQEP hardware ON''' @@ -150,20 +187,41 @@ def disable(self): self._setEnable(0) - def _setMode(self, value): + @property + def mode(self): + '''Returns the mode the eQEP hardware is in (absolute or relative). + + ''' + mode = int(self._eqep.node.mode) + + if mode == 0: + mode_name = "absolute" + elif mode == 1: + mode_name = "relative" + else: + mode_name = "invalid" + + self._logger.debug("getMode(): Channel {}, mode: {} ({})".format( + self._eqep.channel, mode, mode_name)) + + return mode + + @mode.setter + def mode(self, mode): '''Sets the eQEP mode as absolute (0) or relative (1). See the setAbsolute() and setRelative() methods for more information. ''' - if value < 0 or value > 1: + mode = int(mode) + if mode < 0 or mode > 1: raise ValueError( 'The "mode" attribute can only be set to 0 or 1. ' - 'You attempted to set it to {}.'.format(value)) + 'You attempted to set it to {}.'.format(mode)) - self._eqep.node.mode = str(int(value)) + self._eqep.node.mode = str(mode) self._logger.debug("Mode set to: {}".format( - self._eqep.node.mode)) + self._eqep.node.mode)) def setAbsolute(self): '''Sets the eQEP mode as Absolute: @@ -171,35 +229,17 @@ def setAbsolute(self): decremented by the encoder's movement ''' - self._setMode(0) + self.mode = 0 def setRelative(self): '''Sets the eQEP mode as Relative: The position is reset when the unit timer overflows. ''' - self._setMode(1) - - def getMode(self): - '''Returns the mode the eQEP hardware is in (absolute or relative). - - ''' + self.mode = 1 - mode = int(self._eqep.node.mode) - - if mode == 0: - mode_name = "absolute" - elif mode == 1: - mode_name = "relative" - else: - mode_name = "invalid" - - self._logger.debug("getMode(): Channel {}, mode: {} ({})".format( - self._eqep.channel, mode, mode_name)) - - return mode - - def getPosition(self): + @property + def position(self): '''Returns the current position of the encoder. In absolute mode, this attribute represents the current position of the encoder. @@ -209,31 +249,51 @@ def getPosition(self): ''' position = self._eqep.node.position - self._logger.debug("getPosition(): Channel {}, position: {}".format( + self._logger.debug("Get position: Channel {}, position: {}".format( self._eqep.channel, position)) return int(position) - def setFrequency(self, freq): + @position.setter + def position(self, position): + '''Sets the current position to a new value''' + + position = int(position) + self._eqep.node.position = str(position) + + self._logger.debug("Set position: Channel {}, position: {}".format( + self._eqep.channel, position)) + + + @property + def frequency(self): '''Sets the frequency in Hz at which the driver reports new positions. ''' - ns_factor = 1000000000 - period = ns_factor/freq # Period in nanoseconds - self._eqep.node.period = str(period) + frequency = self._eqep.node.period / self._NS_FACTOR + self._logger.debug( - "setFrequency(): Channel {}, frequency: {} Hz, " + "Set frequency(): Channel {}, frequency: {} Hz, " "period: {} ns".format( - self._eqep.channel, freq, period)) + self._eqep.channel, frequency, period)) - def setPosition(self, position): - '''Sets the current position to a new value''' + return frequency - position = int(position) - self._eqep.node.position = str(position) + @frequency.setter + def frequency(self, frequency): + '''Sets the frequency in Hz at which the driver reports + new positions. + + ''' + period = self._NS_FACTOR / frequency # Period in nanoseconds + self._eqep.node.period = str(period) + self._logger.debug( + "Set frequency(): Channel {}, frequency: {} Hz, " + "period: {} ns".format( + self._eqep.channel, frequency, period)) def zero(self): '''Resets the current position to 0''' - return self.setPosition(0) + self.position = 0 From 6c04e3f63a92e513c9361eb00b0050ab25d56d13 Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 28 Nov 2017 12:30:22 +0100 Subject: [PATCH 032/157] Encoder: updated README --- Adafruit_BBIO/README.md | 60 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index aa3642b..000b6a8 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -1,52 +1,47 @@ -# Adafruit_BBIO.Encoder module +# Adafruit_BBIO.Encoder -This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2. - -Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. +This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2/eQEP2b. ## Prerequisites -These instructions are based on a 4.4.x Linux kernel. - -In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the cape-universal overlay - -``` -enable_uboot_cape_universal=1 -``` +These instructions are based on: -Notes: -- It seems that the `cape-universal` cape _does only enable access to eQEP0 and eQEP2_. TBD: check how to load [`cape-universala`](https://github.com/cdsteinkuehler/beaglebone-universal-io/pull/30) -- An alternative option to the `cape-universal` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). +- Linux kernel: 4.4.x or later +- `bb-cape-overlays` package: version 4.4.20171120.0-0rcnee1~stretch+20171120 or later +- `bb-customizations` package: version 1.20171123-0rcnee0~stretch+20171123 or later -### Install/upgrade the latest Device Tree overlays +It's recommended to run the following command to ensure you have the latest required packages: ``` -sudo apt-get upgrade bb-cape-overlays +sudo apt upgrade bb-cape-overlays bb-customizations ``` -### Load the universal cape +In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the `cape-universal` overlay. -If it doesn't already contain it, modify the `/boot/uEnv.txt` file to contain this line: +This is the default, thus **no further steps are initially required to use eQEP0 and eQEP2**. Simply double-check that the following line is present and not commented out on your `/boot/uEnv.txt` file: ``` enable_uboot_cape_universal=1 ``` -Notes: +Note: Some older documentation recommends using the `cmdline` and `cape_enable` options instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. + +### Enabling additional eQEP modules -- Some older documentation recommends using these two lines instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. +The `cape-universal` overlay will enable access to the eQEP0 and eQEP2 modules. As it does not expose pins that are shared with the HDMI interface, eQEP1 and eQEP2b will **not** be available. - ``` - cmdline=cape_universal=enable # Plus some other options - ``` - ``` - cape_enable=bone_capemgr.enable_partno=cape-universala - ``` -- TBD: check the overlays that are currently loaded +To disable the HDMI interface and gain access to the pins and peripherals that share its pins, comment out the following line on the `/boot/uEnv.txt` file and reboot: + +``` +disable_uboot_overlay_video=1 +``` ## eQEP configuraton -Note: if either eQEP1 or eQEP2b are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. +Notes: + +- If either eQEP1 or eQEP2b are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. +- eQEP2 and eQEP2b are the same module, but with the alternative of accessing it via two sets of pins. These are mutually exclusive. ### eQEP0 @@ -91,7 +86,12 @@ $ config-pin P8.41 qep $ config-pin P8.42 qep $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position ``` + +## Credits + +Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. + ## Further reading -- [Beaglebone encoder inputs](https://github.com/Teknoman117/beaglebot/tree/master/encoders) -- [Beaglebone eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts) +1. [Beaglebone encoder inputs](https://github.com/Teknoman117/beaglebot/tree/master/encoders) +1. [Beaglebone eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts) From 48f35d6c4a19a5b3915a076ae3f12d759a80bb15 Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 28 Nov 2017 12:31:22 +0100 Subject: [PATCH 033/157] Encoder: add README apt install clarification --- Adafruit_BBIO/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 000b6a8..d58a9b7 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -10,9 +10,10 @@ These instructions are based on: - `bb-cape-overlays` package: version 4.4.20171120.0-0rcnee1~stretch+20171120 or later - `bb-customizations` package: version 1.20171123-0rcnee0~stretch+20171123 or later -It's recommended to run the following command to ensure you have the latest required packages: +It's recommended to run the following commands to ensure you have the latest required packages: ``` +sudo apt update sudo apt upgrade bb-cape-overlays bb-customizations ``` From 9c08cda98f6b4b43af9afa1646276845fe4e6649 Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 28 Nov 2017 12:39:49 +0100 Subject: [PATCH 034/157] Encoder: copyright assignment note, updated comments --- Adafruit_BBIO/sysfs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Adafruit_BBIO/sysfs.py b/Adafruit_BBIO/sysfs.py index a79cfb9..e6802f0 100644 --- a/Adafruit_BBIO/sysfs.py +++ b/Adafruit_BBIO/sysfs.py @@ -2,6 +2,8 @@ # -*- coding: utf-8 -*- # Copyright (c) 2014 MIT OpenCourseWare +# TODO: the copyright assignment above is boiler plate. Copyright needs to be +# properly assigned. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -32,7 +34,8 @@ # - David Planella """ -Simplistic Python SysFS interface. +Simplistic Python SysFS interface. It enables access to the sys filesystem device +nodes and to get and set their exposed attributes. Usage examples:: from sysfs import sys From b23a861de38e2e3ceb71456601dc4efad85abb8e Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 28 Nov 2017 12:46:51 +0100 Subject: [PATCH 035/157] Encoder: added usage notes --- Adafruit_BBIO/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index d58a9b7..8bb4d7d 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -2,6 +2,30 @@ This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2/eQEP2b. +## Usage + +On a recent Beaglebone Debian image, access to the eQEP0 and eQEP2 channels should work out of the box: + +```python +import Adafruit_BBIO.Encoder as Encoder + +''' +Each channel can be accessed and initialized using its corresponding +channel name constants: + + Encoder.eQEP0 + Encoder.eQEP1 # Pins only available when video is disabled + Encoder.eQEP2 + Encoder.eQEP2b # Pins only available when video is disabled +''' + +# Instantiate the class to access channel eQEP2, and only initialize +# that channel +myEncoder = Encoder.RotaryEncoder(Encoder.eQEP2) +``` + +If you need to use further channels, read on the prerequisites in the following section. + ## Prerequisites These instructions are based on: From 3b5814fc3ea096ecbced0dad68489ea2d16ffd16 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Nov 2017 20:47:24 -0600 Subject: [PATCH 036/157] assign copyright for new file to Adafruit Industries Signed-off-by: Drew Fustini --- Adafruit_BBIO/sysfs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Adafruit_BBIO/sysfs.py b/Adafruit_BBIO/sysfs.py index e6802f0..43fd078 100644 --- a/Adafruit_BBIO/sysfs.py +++ b/Adafruit_BBIO/sysfs.py @@ -2,8 +2,7 @@ # -*- coding: utf-8 -*- # Copyright (c) 2014 MIT OpenCourseWare -# TODO: the copyright assignment above is boiler plate. Copyright needs to be -# properly assigned. +# Copyright (c) 2017 Adafruit Industries # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal From 773f9bd4e52014ff751ec4d433040c6851dd89f9 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 30 Nov 2017 02:13:28 -0600 Subject: [PATCH 037/157] Add bash scripts to help install and test Add useful bash scripts to install and run pytest for all versions of Python that I'm currently running on my BeagleBone. "python" package in Debian 9.2: Python 2.7.13 "python3" package in Debian 9.2: Python 3.5.3 compiled from source by myself on a beaglebone: Python 3.6.3 Example usage: debian@beaglebone:~/ssh/adafruit-beaglebone-io-python$ sudo ./install_all_python_versions.sh && ./pytest_all_versions.sh Signed-off-by: Drew Fustini --- install_all_python_versions.sh | 9 +++++++++ pytest_all_versions.sh | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100755 install_all_python_versions.sh create mode 100755 pytest_all_versions.sh diff --git a/install_all_python_versions.sh b/install_all_python_versions.sh new file mode 100755 index 0000000..932c462 --- /dev/null +++ b/install_all_python_versions.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# useful for testing changes against all versions of python +make clean +echo "Install Python 2.7" +python2.7 ./setup.py install +echo "Install Python 3.5" +python3.5 ./setup.py install +echo "Install Python 3.6" +python3.6 ./setup.py install diff --git a/pytest_all_versions.sh b/pytest_all_versions.sh new file mode 100755 index 0000000..dca6919 --- /dev/null +++ b/pytest_all_versions.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# useful for testing changes against all versions of python + +cd test +echo "Testing Python 2.7" +python2.7 -mpytest +echo "Testing Python 3.5" +python3.5 -mpytest +echo "Testing Python 3.6" +python3.6 -mpytest +cd .. From cfe05edac6465d7685cec2d7b38dd570c5e147ab Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 15:24:14 +0100 Subject: [PATCH 038/157] Encoder: improved usage documentation --- Adafruit_BBIO/README.md | 48 +++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 8bb4d7d..153a423 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -7,21 +7,57 @@ This module enables access to the Beaglebone Black enhanced Quadrature Encoder P On a recent Beaglebone Debian image, access to the eQEP0 and eQEP2 channels should work out of the box: ```python -import Adafruit_BBIO.Encoder as Encoder +from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 ''' Each channel can be accessed and initialized using its corresponding channel name constants: - Encoder.eQEP0 - Encoder.eQEP1 # Pins only available when video is disabled - Encoder.eQEP2 - Encoder.eQEP2b # Pins only available when video is disabled + eQEP0 + eQEP1 # Pins only available when video is disabled + eQEP2 + eQEP2b # Pins only available when video is disabled ''' # Instantiate the class to access channel eQEP2, and only initialize # that channel -myEncoder = Encoder.RotaryEncoder(Encoder.eQEP2) +myEncoder = RotaryEncoder(eQEP2) + +# Get the current position +cur_position = myEncoder.position + +# Position can also be set as a property +next_position = 15 +myEncoder.position = 15 + +# Reset position to 0 +myEncoder.zero() + +# Change mode to relative (default is absolute) +# You can use setAbsolute() to change back to absolute +# Absolute: the position starts at zero and is incremented or +# decremented by the encoder's movement +# Relative: the position is reset when the unit timer overflows. +myEncoder.setRelative() + +# Read the current mode (0: absolute, 1: relative) +# Mode can also be set as a property +mode = myEncoder.mode + +# Read the current frequency of update +# Returned value is in Hz +# If you want to set the frequency, specify it also in Hz +freq = myEncoder.frequency + +# Disable your eQEP channel +myEncoder.disable() + +# Check if the channel is enabled +# The 'enabled' property is read-only +# Use the enable() and disable() methods to +# safely enable or disable the module +isEnabled = myEncoder.enabled + ``` If you need to use further channels, read on the prerequisites in the following section. From 3d7fba989b8d415d3e580345eefdd980cdd918b0 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 15:26:56 +0100 Subject: [PATCH 039/157] Encoder: minor fix to usage example --- Adafruit_BBIO/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 153a423..95919ec 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -28,7 +28,7 @@ cur_position = myEncoder.position # Position can also be set as a property next_position = 15 -myEncoder.position = 15 +myEncoder.position = next_position # Reset position to 0 myEncoder.zero() From 11e08372588fdd7e3d31a723229b17b55490f4c4 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 20:47:41 +0100 Subject: [PATCH 040/157] Encoder: added a note about permissions --- Adafruit_BBIO/README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 95919ec..819dd24 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -4,7 +4,7 @@ This module enables access to the Beaglebone Black enhanced Quadrature Encoder P ## Usage -On a recent Beaglebone Debian image, access to the eQEP0 and eQEP2 channels should work out of the box: +On a recent Beaglebone Debian image, access to the eQEP0 and eQEP2 channels should work out of the box, at least as root user. To ensure you can run the code as a regular user, read on the prerequisites section below. ```python from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 @@ -64,6 +64,8 @@ If you need to use further channels, read on the prerequisites in the following ## Prerequisites +### Kernel and packages + These instructions are based on: - Linux kernel: 4.4.x or later @@ -77,6 +79,23 @@ sudo apt update sudo apt upgrade bb-cape-overlays bb-customizations ``` +### User permissions + +In order to be able to run code that accesses the eQEP modules as a regular user, as opposed to root, that user must be part of the `eqep` group. + +To check which users are part of the `eqep` group: + +``` +cat /etc/group | grep eqep +``` + +To add user `userName` to the `eqep` group (run this command as root): +``` +usermod -a -G eqep userName +``` + +### Capes + In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the `cape-universal` overlay. This is the default, thus **no further steps are initially required to use eQEP0 and eQEP2**. Simply double-check that the following line is present and not commented out on your `/boot/uEnv.txt` file: @@ -87,7 +106,7 @@ enable_uboot_cape_universal=1 Note: Some older documentation recommends using the `cmdline` and `cape_enable` options instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. -### Enabling additional eQEP modules +#### Enabling additional eQEP modules The `cape-universal` overlay will enable access to the eQEP0 and eQEP2 modules. As it does not expose pins that are shared with the HDMI interface, eQEP1 and eQEP2b will **not** be available. From d1eb617c68e706088fae292c5291f53be32bf5c2 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 22:28:35 +0100 Subject: [PATCH 041/157] Encoder: switched sysfs to be a relative import compatible with Python 2 and 3 --- Adafruit_BBIO/Encoder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 83c7a9f..5caa166 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -4,7 +4,7 @@ import os import logging import itertools -import sysfs +from .sysfs import Node import platform (major, minor, patch) = platform.release().split("-")[0].split(".") @@ -72,7 +72,7 @@ def __init__(self, channel, pin_A, pin_B, sys_path): self.pin_A = pin_A self.pin_B = pin_B self.sys_path = sys_path - self.node = sysfs.Node(sys_path) + self.node = Node(sys_path) class RotaryEncoder(object): From 6909243cb502a139c0e3870a4775b4ba4ec93361 Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 22:31:06 +0100 Subject: [PATCH 042/157] Encoder: use items() instead of iteritems() to be Python 3 compatible --- Adafruit_BBIO/Encoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 5caa166..0e94fa6 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -47,7 +47,7 @@ def fromdict(cls, d): '''Creates a class instance from a dictionary''' allowed = ('channel', 'pin_A', 'pin_B', 'sys_path') - df = {k: v for k, v in d.iteritems() if k in allowed} + df = {k: v for k, v in d.items() if k in allowed} return cls(**df) def __init__(self, channel, pin_A, pin_B, sys_path): From a27cb61de1f73b4762fbc3231d0f9b6cd325784e Mon Sep 17 00:00:00 2001 From: David Planella Date: Thu, 30 Nov 2017 23:18:31 +0100 Subject: [PATCH 043/157] Encoder: fix frequency getter This change fixes the following: - Correct calculation of the frequency from period on the property getter - Cast the string returned from sysfs to int to perform the calculation - Fix the period variable for logging and debug properties --- Adafruit_BBIO/Encoder.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 0e94fa6..35fd26f 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -271,12 +271,13 @@ def frequency(self): new positions. ''' - frequency = self._eqep.node.period / self._NS_FACTOR + frequency = self._NS_FACTOR / int(self._eqep.node.period) self._logger.debug( "Set frequency(): Channel {}, frequency: {} Hz, " "period: {} ns".format( - self._eqep.channel, frequency, period)) + self._eqep.channel, frequency, + self._eqep.node.period)) return frequency From f64382b8db1206739755419f5e48fdd0f27e92c9 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 30 Nov 2017 20:30:01 -0600 Subject: [PATCH 044/157] create release 1.0.9 Features: * Issue #194: Encoder position cannot be set * PR #205: Encoder: add support for reading/writing sysfs attributes Fixes: * Issue #198: use https for DEFAULT_URL in distribute_setup.py * Issue #197: Fix leak of pwm enable file descriptor * Issue #189: Fix seg fault of PWM in Python 3.6 * Issue #180: Clarify there is no 0 prefix for pin lables * PR #201: Encoder: do kernel check, PEP8 cleanup * PR #202: Encoder: corrected kernel check logic * PR #207: Encoder: improved usage adocumentation * PR #210: Encoder: fix sysfs import, make code Python 3 compatible * PR #212: Encoder: fix Python 3 compatibility * PR #213: Encoder: fix frequency calculation from period shortlog: * David Planella (18): * Encoder: initialize only the given channel * Sync from master * Encoder: do kernel check, PEP8 cleanup * Encoder: added sysfs module * Encoder: use sysfs to write QEP attributes * Encoder: corrected kernel check logic * Merge pull request #2 from adafruit/master * Encoder: convert get/set methods to properties, update apidoc strings * Encoder: updated README * Encoder: add README apt install clarification * Encoder: copyright assignment note, updated comments * Encoder: added usage notes * Encoder: improved usage documentation * Encoder: minor fix to usage example * Encoder: added a note about permissions * Encoder: switched sysfs to be a relative import compatible with Python 2 and 3 * Encoder: use items() instead of iteritems() to be Python 3 compatible * Encoder: fix frequency getter * Drew Fustini (18): * use https for DEFAULT_URL in distribute_setup.py (#198) * fix except syntax for Python 3 * use dict.items() instead of dict.iteritems() for Python 3 * fix error in set_brightness() * close enable_fd when stopping PWM output (#197) * Merge pull request #199 from dplanella/patch-1 * Fix leak of pwm enable file descriptor (#197) * Merge pull request #201 from dplanella/encoder-cleanup * remove test_rotary.py as not valid for pytest * Fix seg fault of PWM in Python 3.6 (#189) * Merge pull request #202 from dplanella/patch-2 * Clarify there is no 0 prefix for pin lables (#180) * Merge pull request #205 from dplanella/encoder-sysfs * assign copyright for new file to Adafruit Industries * Add bash scripts to help install and test * Merge pull request #212 from dplanella/patch-4 * Merge pull request #207 from dplanella/patch-3 * Merge pull request #213 from dplanella/fix-encoder-frequency Signed-off-by: Drew Fustini --- CHANGELOG.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 636f8a4..5cd59eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,62 @@ +1.0.9 +---- +**Features:** +* Issue #194: Encoder position cannot be set +* PR #205: Encoder: add support for reading/writing sysfs attributes + +**Fixes:** +* Issue #198: use https for DEFAULT_URL in distribute_setup.py +* Issue #197: Fix leak of pwm enable file descriptor +* Issue #189: Fix seg fault of PWM in Python 3.6 +* Issue #180: Clarify there is no 0 prefix for pin lables +* PR #201: Encoder: do kernel check, PEP8 cleanup +* PR #202: Encoder: corrected kernel check logic +* PR #207: Encoder: improved usage documentation +* PR #210: Encoder: fix sysfs import, make code Python 3 compatible +* PR #212: Encoder: fix Python 3 compatibility +* PR #213: Encoder: fix frequency calculation from period + +**shortlog:** +* David Planella (18): + * Encoder: initialize only the given channel + * Sync from master + * Encoder: do kernel check, PEP8 cleanup + * Encoder: added sysfs module + * Encoder: use sysfs to write QEP attributes + * Encoder: corrected kernel check logic + * Merge pull request #2 from adafruit/master + * Encoder: convert get/set methods to properties, update apidoc strings + * Encoder: updated README + * Encoder: add README apt install clarification + * Encoder: copyright assignment note, updated comments + * Encoder: added usage notes + * Encoder: improved usage documentation + * Encoder: minor fix to usage example + * Encoder: added a note about permissions + * Encoder: switched sysfs to be a relative import compatible with Python 2 and 3 + * Encoder: use items() instead of iteritems() to be Python 3 compatible + * Encoder: fix frequency getter + +* Drew Fustini (18): + * use https for DEFAULT_URL in distribute_setup.py (#198) + * fix except syntax for Python 3 + * use dict.items() instead of dict.iteritems() for Python 3 + * fix error in set_brightness() + * close enable_fd when stopping PWM output (#197) + * Merge pull request #199 from dplanella/patch-1 + * Fix leak of pwm enable file descriptor (#197) + * Merge pull request #201 from dplanella/encoder-cleanup + * remove test_rotary.py as not valid for pytest + * Fix seg fault of PWM in Python 3.6 (#189) + * Merge pull request #202 from dplanella/patch-2 + * Clarify there is no 0 prefix for pin lables (#180) + * Merge pull request #205 from dplanella/encoder-sysfs + * assign copyright for new file to Adafruit Industries + * Add bash scripts to help install and test + * Merge pull request #212 from dplanella/patch-4 + * Merge pull request #207 from dplanella/patch-3 + * Merge pull request #213 from dplanella/fix-encoder-frequency + 1.0.8 ---- **Fixes:** diff --git a/setup.py b/setup.py index 991b476..e3da413 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.0.8', + version = '1.0.9', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From 61af64e734f3f7c2ca96495cea7ea9fc78f4c877 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 30 Nov 2017 21:01:20 -0600 Subject: [PATCH 045/157] use set_pin_mode() to set uart pinmux (#158) Use set_pin_mode() to set pinmux for UART RX and TX pins. This is similar effect as running the config-pin utility. Signed-off-by: Drew Fustini --- setup.py | 4 ++-- source/common.c | 8 -------- source/common.h | 11 +++++++++++ source/py_uart.c | 24 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index e3da413..e42f907 100644 --- a/setup.py +++ b/setup.py @@ -54,6 +54,6 @@ ext_modules = [Extension('Adafruit_BBIO.GPIO', ['source/py_gpio.c', 'source/event_gpio.c', 'source/c_pinmux.c', 'source/constants.c', 'source/common.c'], **extension_args), Extension('Adafruit_BBIO.PWM', ['source/py_pwm.c', 'source/c_pwm.c', 'source/c_pinmux.c', 'source/constants.c', 'source/common.c'], **extension_args), Extension('Adafruit_BBIO.ADC', ['source/py_adc.c', 'source/c_adc.c', 'source/constants.c', 'source/common.c'], **extension_args), - Extension('Adafruit_BBIO.SPI', ['source/spimodule.c', 'source/constants.c', 'source/common.c'], **extension_args), - Extension('Adafruit_BBIO.UART', ['source/py_uart.c', 'source/c_uart.c', 'source/constants.c', 'source/common.c'], **extension_args)] ) + Extension('Adafruit_BBIO.SPI', ['source/spimodule.c', 'source/c_pinmux.c', 'source/constants.c', 'source/common.c'], **extension_args), + Extension('Adafruit_BBIO.UART', ['source/py_uart.c', 'source/c_pinmux.c', 'source/c_uart.c', 'source/constants.c', 'source/common.c'], **extension_args)] ) diff --git a/source/common.c b/source/common.c index d940042..e8fbbec 100644 --- a/source/common.c +++ b/source/common.c @@ -263,14 +263,6 @@ pins_t table[] = { { NULL, NULL, 0, 0, 0 } }; -typedef struct uart_t { - const char *name; - const char *path; - const char *dt; - const char *rx; - const char *tx; -} uart_t; - uart_t uart_table[] = { { "UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P9_26", "P9_24"}, { "UART2", "/dev/ttyO2", "ADAFRUIT-UART2", "P9_22", "P9_21"}, diff --git a/source/common.h b/source/common.h index 1e2d307..7d60c1f 100644 --- a/source/common.h +++ b/source/common.h @@ -64,6 +64,17 @@ typedef struct pwm_t { const char *key; // Pin name eg P9_21 } pwm_t; + +typedef struct uart_t { + const char *name; + const char *path; + const char *dt; + const char *rx; + const char *tx; +} uart_t; + +extern uart_t uart_table[]; + extern int gpio_mode; extern int gpio_direction[120]; diff --git a/source/py_uart.c b/source/py_uart.c index 78b2535..c70d327 100644 --- a/source/py_uart.c +++ b/source/py_uart.c @@ -25,6 +25,7 @@ SOFTWARE. #include "constants.h" #include "common.h" #include "c_uart.h" +#include "c_pinmux.h" const char *valid_uarts[4] = {"UART1", "UART2", "UART4", "UART5"}; @@ -61,6 +62,29 @@ static PyObject *py_setup_uart(__attribute__ ((unused)) PyObject *self, PyObject return NULL; } +#ifdef BBBVERSION41 + uart_t *p; + for (p = uart_table; p->name != NULL; ++p) { + if (strcmp(p->name, channel) == 0) { + err = set_pin_mode(p->rx, "uart"); + //Check if set_pin_mode() returned no error + if (err != BBIO_OK) { + fprintf(stderr, "py_setup_uart(%s): set_pin_mode() failed for pin=%s", channel, p->rx); + PyErr_SetString(PyExc_ValueError, "Set pin mode failed for uart channel."); + return NULL; + } + + err = set_pin_mode(p->tx, "uart"); + //Check if set_pin_mode() returned no error + if (err != BBIO_OK) { + fprintf(stderr, "py_setup_uart(%s): set_pin_mode() failed for pin=%s", channel, p->tx); + PyErr_SetString(PyExc_ValueError, "Set pin mode failed for uart channel."); + return NULL; + } + } + } +#endif + Py_RETURN_NONE; } From f25179ccd6121d5ce29e4d07d75d98c823916cd6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 1 Dec 2017 02:49:55 -0600 Subject: [PATCH 046/157] Add SPI instructions to README (#158) --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.md b/README.md index 6445bcf..805d890 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,49 @@ ser.close() ``` * [Loopback test with UART1 and UART2](https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/uart#testing-and-using-the-uart) + +### [SPI](https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/spi) +* Use [`config-pin` to set pin mode](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) for [SPI pins](http://beagleboard.org/static/images/cape-headers-spi.png) + * SPI0 + * SPI0_CS0: `config-pin p9.17 spi_cs` + * SPI0_D1: `config-pin p9.18 spi` + * SPI0_D0: `config-pin p9.21 spi` + * SPI0_SCLK: `config-pin p9.22 spi_sclk` + * SPI1 + * SPI1_CS0: `config-pin p9.20 spi_cs` + * SPI1_CS0: `config-pin p9.28 spi_cs` + * SPI1_CS1: `config-pin p9.19 spi_cs` + * SPI1_CS1: `config-pin p9.42 spi_cs` + * SPI1_D0: `config-pin p9.29 spi` + * SPI1_D1: `config-pin p9.30 spi` + * SPI1_SCLK: `config-pin p9.31 spi_sclk` +* Example: +``` +from Adafruit_BBIO.SPI import SPI +#spi = SPI(bus, device) #/dev/spidev. + +# /dev/spidev0.0 +spi = SPI(1,0) +print(spi.xfer2([32, 11, 110, 22, 220])) +spi.close() + +# /dev/spidev0.1 +spi = SPI(1,1) +print(spi.xfer2([32, 11, 110, 22, 220])) +spi.close() + +# /dev/spidev1.0 +spi = SPI(2,0) +print(spi.xfer2([32, 11, 110, 22, 220])) +spi.close() + +# /dev/spidev1.1 +spi = SPI(2,1) +print(spi.xfer2([32, 11, 110, 22, 220])) +spi.close() +``` + + ## Running tests Install py.test to run the tests. You'll also need the python compiler package for pytest: From 2d5e218f4c0a762a6b896d72c6f48f11a0fddeff Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 1 Dec 2017 02:52:41 -0600 Subject: [PATCH 047/157] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 805d890..e4db1e2 100644 --- a/README.md +++ b/README.md @@ -209,8 +209,8 @@ ser.close() * Use [`config-pin` to set pin mode](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) for [SPI pins](http://beagleboard.org/static/images/cape-headers-spi.png) * SPI0 * SPI0_CS0: `config-pin p9.17 spi_cs` - * SPI0_D1: `config-pin p9.18 spi` * SPI0_D0: `config-pin p9.21 spi` + * SPI0_D1: `config-pin p9.18 spi` * SPI0_SCLK: `config-pin p9.22 spi_sclk` * SPI1 * SPI1_CS0: `config-pin p9.20 spi_cs` @@ -246,7 +246,6 @@ print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() ``` - ## Running tests Install py.test to run the tests. You'll also need the python compiler package for pytest: From bddd2f9a7e6fe388ae74aefdc7235f0cb5dc49e5 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 10:55:58 +0100 Subject: [PATCH 048/157] Encoder: README.md: added note about eqep group change --- Adafruit_BBIO/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index 819dd24..58cbfd7 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -94,6 +94,8 @@ To add user `userName` to the `eqep` group (run this command as root): usermod -a -G eqep userName ``` +Note: you will need to log out and log back in for the group membership change to take effect. + ### Capes In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the `cape-universal` overlay. From e640d0582ead1f10ddd9600665e1153777aa6818 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 11:20:22 +0100 Subject: [PATCH 049/157] Add Encoder module info to main README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e4db1e2..2c19f81 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) -* Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone +* Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart) and [eQEP](README.md#eqep) (Quadrature Encoder) access on the BeagleBone * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) * **Currently recommended image: [Debian 9.2 "Stretch" iot (2017-10-29)](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#microSD.2FStandalone:_.28stretch-iot.29_.28All_BeagleBone_Variants_.26_PocketBeagle.29)** @@ -246,6 +246,10 @@ print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() ``` +### eQEP + +To use the enhanced Quadrature Encoder Pulse (eQEP) module, please refer to the [`Encoder` module's documentation](https://github.com/adafruit/adafruit-beaglebone-io-python/tree/master/Adafruit_BBIO#usage). + ## Running tests Install py.test to run the tests. You'll also need the python compiler package for pytest: From 8dfbf64c36f377b7169aff63ffe7580d545d5659 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 1 Dec 2017 06:36:50 -0600 Subject: [PATCH 050/157] Fix spidev path mismatch (#216) Remove unnecessary call to get_spi_bus_path_number() and use the bus and device passed to SPI_open(). Signed-off-by: Drew Fustini --- source/spimodule.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/source/spimodule.c b/source/spimodule.c index 5b1f6ad..3b94109 100644 --- a/source/spimodule.c +++ b/source/spimodule.c @@ -703,7 +703,6 @@ static PyObject * SPI_open(SPI *self, PyObject *args, PyObject *kwds) { int bus, device; - int bus_path; int max_dt_length = 15; char device_tree_name[max_dt_length]; char path[MAXPATH]; @@ -722,14 +721,7 @@ SPI_open(SPI *self, PyObject *args, PyObject *kwds) return NULL; } - bus_path = get_spi_bus_path_number(bus); - if (bus_path == -1) { - PyErr_SetString(PyExc_OverflowError, - "Unable to find loaded spi bus path."); - return NULL; - } - - if (snprintf(path, MAXPATH, "/dev/spidev%d.%d", bus_path, device) >= MAXPATH) { + if (snprintf(path, MAXPATH, "/dev/spidev%d.%d", bus, device) >= MAXPATH) { PyErr_SetString(PyExc_OverflowError, "Bus and/or device number is invalid."); return NULL; From b1557e265d827df0c61d407e178e4e7f6bbb8daf Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 1 Dec 2017 07:21:18 -0600 Subject: [PATCH 051/157] Deprecate Adafruit_BBIO.I2C in favor of Adafruit_GPIO.I2C (#215) Adafruit_BBIO.I2C has been deprecated. Use Adafruit_GPIO.I2C instead: https://github.com/adafruit/Adafruit_Python_GPIO/blob/master/Adafruit_GPIO/I2C.py Signed-off-by: Drew Fustini --- Adafruit_I2C.py | 120 ++---------------------------------------------- 1 file changed, 5 insertions(+), 115 deletions(-) diff --git a/Adafruit_I2C.py b/Adafruit_I2C.py index 742e59e..6a7a3bc 100644 --- a/Adafruit_I2C.py +++ b/Adafruit_I2C.py @@ -1,123 +1,13 @@ #!/usr/bin/python -import smbus - -# =========================================================================== -# Adafruit_I2C Class -# Adafruit_I2C.py is essentially a fork of the Adafruit Raspberry Pi I2C module. -# Any pull requests for this module should be directed to the following, and I -# can pull them. I'd rather not deviate from the original: -# https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code/tree/master/Adafruit_I2C -# =========================================================================== +# WARNING: THIS MODULE IS DEPRECATED! +# use Adafruit_GPIO.I2C instead: +# https://github.com/adafruit/Adafruit_Python_GPIO/blob/master/Adafruit_GPIO/I2C.py class Adafruit_I2C : def __init__(self, address, busnum=-1, debug=False): - self.address = address - self.bus = smbus.SMBus(busnum if busnum >= 0 else 1) - self.debug = debug - - def reverseByteOrder(self, data): - "Reverses the byte order of an int (16-bit) or long (32-bit) value" - # Courtesy Vishal Sapre - byteCount = len(hex(data)[2:].replace('L','')[::2]) - val = 0 - for i in range(byteCount): - val = (val << 8) | (data & 0xff) - data >>= 8 - return val - - def errMsg(self): - print("Error accessing 0x%02X: Check your I2C address" % self.address) - return -1 - - def write8(self, reg, value): - "Writes an 8-bit value to the specified register/address" - try: - self.bus.write_byte_data(self.address, reg, value) - if self.debug: - print("I2C: Wrote 0x%02X to register 0x%02X" % (value, reg)) - except IOError as err: - return self.errMsg() - - def write16(self, reg, value): - "Writes a 16-bit value to the specified register/address pair" - try: - self.bus.write_word_data(self.address, reg, value) - if self.debug: - print("I2C: Wrote 0x%02X to register pair 0x%02X,0x%02X" % - (value, reg, reg+1)) - except IOError as err: - return self.errMsg() - - def writeList(self, reg, list): - "Writes an array of bytes using I2C format" - try: - if self.debug: - print("I2C: Writing list to register 0x%02X:" % reg) - print(list) - self.bus.write_i2c_block_data(self.address, reg, list) - except IOError as err: - return self.errMsg() - - def readList(self, reg, length): - "Read a list of bytes from the I2C device" - try: - results = self.bus.read_i2c_block_data(self.address, reg, length) - if self.debug: - print("I2C: Device 0x%02X returned the following from reg 0x%02X" % - (self.address, reg)) - print(results) - return results - except IOError as err: - return self.errMsg() - - def readU8(self, reg): - "Read an unsigned byte from the I2C device" - try: - result = self.bus.read_byte_data(self.address, reg) - if self.debug: - print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % - (self.address, result & 0xFF, reg)) - return result - except IOError as err: - return self.errMsg() - - def readS8(self, reg): - "Reads a signed byte from the I2C device" - try: - result = self.bus.read_byte_data(self.address, reg) - if result > 127: result -= 256 - if self.debug: - print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % - (self.address, result & 0xFF, reg)) - return result - except IOError as err: - return self.errMsg() - - def readU16(self, reg): - "Reads an unsigned 16-bit value from the I2C device" - try: - result = self.bus.read_word_data(self.address,reg) - if (self.debug): - print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)) - return result - except IOError as err: - return self.errMsg() - - def readS16(self, reg): - "Reads a signed 16-bit value from the I2C device" - try: - result = self.bus.read_word_data(self.address,reg) - if (self.debug): - print("I2C: Device 0x%02X returned 0x%04X from reg 0x%02X" % (self.address, result & 0xFFFF, reg)) - return result - except IOError as err: - return self.errMsg() + print("WARNING: THIS MODULE IS DEPRECATED. Use Adafruit_GPIO.I2C instead.\n"); if __name__ == '__main__': - try: - bus = Adafruit_I2C(address=0) - print("Default I2C bus is accessible") - except: - print("Error accessing default I2C bus") + print("WARNING: THIS MODULE IS DEPRECATED. Use Adafruit_GPIO.I2C instead.\n"); From ca81b283b920cbe1aec771411fae06ce8f9e0d68 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 17:11:48 +0100 Subject: [PATCH 052/157] Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. --- .gitignore | 3 + Adafruit_BBIO/Encoder.py | 120 +++++++++++++++++++-------- docs/Makefile | 20 +++++ docs/conf.py | 169 +++++++++++++++++++++++++++++++++++++++ docs/index.rst | 91 +++++++++++++++++++++ 5 files changed, 370 insertions(+), 33 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst diff --git a/.gitignore b/.gitignore index 5c0e38d..e948a66 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ m4/lt~obsolete.m4 missing source/Makefile.in test-driver +docs/_build +docs/_static +docs/_templates diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 35fd26f..ecfd27a 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -1,5 +1,62 @@ #!/usr/bin/python +"""Quadrature Encoder Pulse interface. + +This module enables access to the enhanced Quadrature Encoder Pulse (eQEP) +channels, which can be used to seamlessly interface with rotary encoder +hardware. + +The channel identifiers are available as module variables :data:`eQEP0`, +:data:`eQEP1`, :data:`eQEP2` and :data:`eQEP2b`. + +Example: + To use the module, you can connect a rotary encoder to your Beaglebone + and then simply instantiate the :class:`RotaryEncoder` class to read its position:: + + from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 + + # Instantiate the class to access channel eQEP2, and initialize + # that channel + myEncoder = RotaryEncoder(eQEP2) + + # Get the current position + cur_position = myEncoder.position + + # Set the current position + next_position = 15 + myEncoder.position = next_position + + # Reset position to 0 + myEncoder.zero() + + # Change mode to relative (default is absolute) + # You can use setAbsolute() to change back to absolute + # Absolute: the position starts at zero and is incremented or + # decremented by the encoder's movement + # Relative: the position is reset when the unit timer overflows. + myEncoder.setRelative() + + # Read the current mode (0: absolute, 1: relative) + # Mode can also be set as a property + mode = myEncoder.mode + + # Get the current frequency of update in Hz + freq = myEncoder.frequency + + # Set the update frequency to 1 kHz + myEncoder.frequency = 1000 + + # Disable the eQEP channel + myEncoder.disable() + + # Check if the channel is enabled + # The 'enabled' property is read-only + # Use the enable() and disable() methods to + # safely enable or disable the module + isEnabled = myEncoder.enabled + +""" + from subprocess import check_output, STDOUT, CalledProcessError import os import logging @@ -15,13 +72,20 @@ 'Your Linux kernel version is {}.'.format(platform.release())) -# eQEP module channel identifiers -# eQEP 2 and 2b are the same channel, exposed on two different sets of pins, -# which are mutually exclusive eQEP0 = 0 +'''eQEP0 channel identifier, pin A-- P9.92, pin B-- P9.27 on Beaglebone +Black.''' eQEP1 = 1 +'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone +Black.''' eQEP2 = 2 +'''eQEP2 channel identifier, pin A-- P8.12, pin B-- P8.11 on Beaglebone Black. +Note that there is only one eQEP2 module. This is one alternative set of pins +where it is exposed, which is mutually-exclusive with eQEP2b''' eQEP2b = 3 +'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone Black. +Note that there is only one eQEP2 module. This is one alternative set of pins +where it is exposed, which is mutually-exclusive with eQEP2''' # Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" @@ -37,7 +101,7 @@ ] -class eQEP(object): +class _eQEP(object): '''Enhanced Quadrature Encoder Pulse (eQEP) module class. Abstraction for either of the three available channels (eQEP0, eQEP1, eQEP2) on the Beaglebone''' @@ -51,7 +115,7 @@ def fromdict(cls, d): return cls(**df) def __init__(self, channel, pin_A, pin_B, sys_path): - '''Initialize the eQEP module + '''Initialize the given eQEP channel Attributes: channel (str): eQEP channel name. E.g. "eQEP0", "eQEP1", etc. @@ -79,21 +143,11 @@ class RotaryEncoder(object): ''' Rotary encoder class abstraction to control a given QEP channel. - Constructor: - eqep_num: QEP object that determines which channel to control - - Properties: - position: current position of the encoder - frequency: frequency at which the encoder reports new positions - enabled: (read only) true if the module is enabled, false otherwise - mode: current mode of the encoder (absolute: 0, relative: 1) - - Methods: - enable: enable the QEP channel - disable: disable the QEP channel - setAbsolute: shortcut for setting the mode to absolute - setRelative: shortcut for setting the mode to relative - zero: shortcut for setting the position to 0 + Args: + eqep_num (int): determines which eQEP pins are set up. + Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, + based on which pins the physical rotary encoder + is connected to. ''' def _run_cmd(self, cmd): @@ -117,15 +171,8 @@ def _config_pin(self, pin): self._run_cmd(["config-pin", pin, "qep"]) def __init__(self, eqep_num): - '''Creates an instance of the class RotaryEncoder. - - Arguments: - eqep_num: determines which eQEP pins are set up. - Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, - based on which pins the physical rotary encoder - is connected to. + '''Creates an instance of the class RotaryEncoder.''' - ''' # nanoseconds factor to convert period to frequency and back self._NS_FACTOR = 1000000000 @@ -134,7 +181,7 @@ def __init__(self, eqep_num): self._logger.addHandler(logging.NullHandler()) # Initialize the eQEP channel structures - self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) + self._eqep = _eQEP.fromdict(_eQEP_DEFS[eqep_num]) self._logger.info( "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, @@ -154,8 +201,8 @@ def __init__(self, eqep_num): def enabled(self): '''Returns the enabled status of the module: - true: module is enabled - false: module is disabled + Returns: + bool: True if the eQEP channel is enabled, False otherwise. ''' isEnabled = bool(int(self._eqep.node.enabled)) @@ -164,7 +211,11 @@ def enabled(self): def _setEnable(self, enabled): '''Turns the eQEP hardware ON or OFF - value (int): 1 represents enabled, 0 is disabled + Args: + enabled (int): enable the module with 1, disable it with 0. + + Raises: + ValueError: if the value for enabled is < 0 or > 1 ''' enabled = int(enabled) @@ -189,8 +240,11 @@ def disable(self): @property def mode(self): - '''Returns the mode the eQEP hardware is in (absolute or relative). + '''Returns the mode the eQEP hardware is in. + Returns: + int: 0 if the eQEP channel is configured in absolute mode, + 1 if configured in relative mode. ''' mode = int(self._eqep.node.mode) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..4430e8a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = Adafruit-BBIO +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..2ac0431 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +# +# Adafruit-BBIO documentation build configuration file, created by +# sphinx-quickstart on Fri Dec 1 12:56:03 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Adafruit-BBIO' +copyright = u'2017, Justin Cooper' +author = u'Justin Cooper' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'' +# The full version, including alpha/beta/rc tags. +release = u'1.0.9' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Adafruit-BBIOdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Adafruit-BBIO.tex', u'Adafruit-BBIO Documentation', + u'Justin Cooper', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'adafruit-bbio', u'Adafruit-BBIO Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Adafruit-BBIO', u'Adafruit-BBIO Documentation', + author, 'Adafruit-BBIO', 'One line description of project.', + 'Miscellaneous'), +] + +autodoc_member_order = 'groupwise' +#autoclass_content = 'both' + diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..9241ca6 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,91 @@ +.. Adafruit-BBIO documentation master file, created by + sphinx-quickstart on Fri Dec 1 12:56:03 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Adafruit Beaglebone IO Python API +================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + +:mod:`Encoder` --- Quadrature Encoder interface +----------------------------------------------- + +.. automodule:: Adafruit_BBIO.Encoder + :members: + +:mod:`PWM` --- Pulse Width Modulation interface +----------------------------------------------- + +Enables access to the Pulse Width Modulation (PWM) module, to easily and +accurately generate a PWM output signal of a given duty cycle and +frequency. + +.. module:: Adafruit_BBIO.PWM + +.. function:: start(channel, duty_cycle[, frequency=2000, polarity=0]) + + Set up and start the given PWM channel. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :type duty_cycle: int + :param frequency: PWM frequency, in Hz. It must be greater than 0. + :type frequency: int + :param polarity: defines whether the value for ``duty_cycle`` affects the + rising edge or the falling edge of the waveform. Allowed values -- 0 + (rising edge, default) or 1 (falling edge). + :type polarity: int + +.. function:: stop(channel) + + Stop the given PWM channel. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + +.. function:: set_duty_cycle(channel, duty_cycle) + + Change the duty cycle of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the duty cycle. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :type duty_cycle: int + +.. function:: set_frequency(channel, frequency) + + Change the frequency of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the frequency. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param frequency: PWM frequency. It must be greater than 0. + :type frequency: int + +.. function:: cleanup() + + Clean up by resetting all GPIO channels that have been used by this + program to INPUT, with no pullup/pulldown and no event detection. + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + + From cfdf7552ade444c84b3611fdee7ead65b74510e6 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:24:03 +0100 Subject: [PATCH 053/157] Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails --- .gitignore | 3 +++ Adafruit_BBIO/Encoder.py | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index e948a66..facfc35 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ test-driver docs/_build docs/_static docs/_templates + +# vim temp files +*~ diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index ecfd27a..39c40b6 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -11,7 +11,8 @@ Example: To use the module, you can connect a rotary encoder to your Beaglebone - and then simply instantiate the :class:`RotaryEncoder` class to read its position:: + and then simply instantiate the :class:`RotaryEncoder` class to read its + position:: from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 @@ -65,7 +66,8 @@ import platform (major, minor, patch) = platform.release().split("-")[0].split(".") -if not (int(major) >= 4 and int(minor) >= 4): +if not (int(major) >= 4 and int(minor) >= 4) \ + and platform.node() == 'beaglebone': raise ImportError( 'The Encoder module requires Linux kernel version >= 4.4.x.\n' 'Please upgrade your kernel to use this module.\n' @@ -76,16 +78,16 @@ '''eQEP0 channel identifier, pin A-- P9.92, pin B-- P9.27 on Beaglebone Black.''' eQEP1 = 1 -'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone +'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone Black.''' eQEP2 = 2 '''eQEP2 channel identifier, pin A-- P8.12, pin B-- P8.11 on Beaglebone Black. Note that there is only one eQEP2 module. This is one alternative set of pins where it is exposed, which is mutually-exclusive with eQEP2b''' eQEP2b = 3 -'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone Black. -Note that there is only one eQEP2 module. This is one alternative set of pins -where it is exposed, which is mutually-exclusive with eQEP2''' +'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone +Black. Note that there is only one eQEP2 module. This is one alternative set of +pins where it is exposed, which is mutually-exclusive with eQEP2''' # Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" @@ -318,14 +320,13 @@ def position(self, position): self._logger.debug("Set position: Channel {}, position: {}".format( self._eqep.channel, position)) - @property def frequency(self): '''Sets the frequency in Hz at which the driver reports new positions. ''' - frequency = self._NS_FACTOR / int(self._eqep.node.period) + frequency = self._NS_FACTOR / int(self._eqep.node.period) self._logger.debug( "Set frequency(): Channel {}, frequency: {} Hz, " @@ -352,3 +353,4 @@ def zero(self): '''Resets the current position to 0''' self.position = 0 + From 19134712f7d4162fa84f2e4e8cb07d6ffa1e6389 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:47:03 +0100 Subject: [PATCH 054/157] Use the default readthedocs theme --- docs/conf.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 2ac0431..556134c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,11 +102,15 @@ # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ - 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', + 'localtoc.html' ] } +html_theme = "default" +html_theme_options = { + #"show_related": "true" +} # -- Options for HTMLHelp output ------------------------------------------ From 7de4ccb3754d742365331876ddf580195bedeca0 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:56:51 +0100 Subject: [PATCH 055/157] Use readthedocs theme if building docs there, remove redundand search link --- docs/conf.py | 10 ++++++---- docs/index.rst | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 556134c..0412db1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -107,10 +107,12 @@ ] } -html_theme = "default" -html_theme_options = { - #"show_related": "true" -} +# Use the readthedocs theme if the documentation is being built there +on_rtd = os.environ.get('READTHEDOCS') == 'True' +if on_rtd: + html_theme = 'default' +else: + html_theme = 'alabaster' # -- Options for HTMLHelp output ------------------------------------------ diff --git a/docs/index.rst b/docs/index.rst index 9241ca6..4b930ad 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -86,6 +86,5 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` -* :ref:`search` From c37cf6a5121d5702ec3c2913905e8b9b38f62664 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 19:52:04 +0100 Subject: [PATCH 056/157] Readthedocs theme tweaks --- docs/conf.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0412db1..a620f16 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -100,19 +100,22 @@ # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'searchbox.html', - 'localtoc.html' - ] -} # Use the readthedocs theme if the documentation is being built there on_rtd = os.environ.get('READTHEDOCS') == 'True' if on_rtd: html_theme = 'default' + html_theme_options = { + 'collapse_navigation': False, + } else: html_theme = 'alabaster' + html_sidebars = { + '**': [ + 'searchbox.html', + 'localtoc.html' + ] + } # -- Options for HTMLHelp output ------------------------------------------ From 7d33f1d85650d19ee118148f6e2b7363de04b56b Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 20:14:42 +0100 Subject: [PATCH 057/157] Removed redundant TOC, added global description --- docs/index.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 4b930ad..2a7fdb4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,9 +6,8 @@ Adafruit Beaglebone IO Python API ================================= -.. toctree:: - :maxdepth: 2 - :caption: Contents: +The Adafruit Beaglebone IO API enables access to the Beaglebone's GPIO, PWM, +ADC, UART and eQEP hardware modules from Python programs. :mod:`Encoder` --- Quadrature Encoder interface ----------------------------------------------- From d1608b44c3dd9033350316e725cad835a77aeaef Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 20:32:16 +0100 Subject: [PATCH 058/157] Added UART documentation --- docs/index.rst | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index 2a7fdb4..f4c8830 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -79,6 +79,44 @@ frequency. Clean up by resetting all GPIO channels that have been used by this program to INPUT, with no pullup/pulldown and no event detection. +:mod:`UART` --- UART communications interface +--------------------------------------------- + +UART functionality of a BeagleBone using Python. Generally used to set up +and grant access to a given UART device, which will then be accessed by +other software or modules (e.g. `pyserial`):: + + sudo pip install pyserial + +Example:: + + import Adafruit_BBIO.UART as UART + import serial + + UART.setup("UART1") + + ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) + ser.close() + ser.open() + if ser.isOpen(): + print "Serial is open!" + ser.write("Hello World!") + ser.close() + +.. function:: setup_uart(channel) + + Set up and start the UART channel. This function will effectively export + the given UART so that it can be accessed by other software that controls + its serial lines. + + :param channel: UART channel to set up. One of "UART1", "UART2", + "UART4" or "UART5" + :type channel: str + +.. function:: cleanup() + + Cleans up the UART. + Indices and tables ================== From 152678a674f6a145e94abd8eebd3341e73b3de63 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 23:23:13 +0100 Subject: [PATCH 059/157] Added documentation badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e4db1e2..5fcaa57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) +[![Documentation Status](https://readthedocs.org/projects/adafruit-beaglebone-io-python/badge/?version=latest)](http://adafruit-beaglebone-io-python.readthedocs.io/en/latest/?badge=latest) + * Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) From 6dc5313d856418d7966cc0852248e56b4f3b545d Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 23:38:31 +0100 Subject: [PATCH 060/157] Added ADC API docs, fixed UART module definition --- docs/index.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index f4c8830..899e365 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -103,6 +103,8 @@ Example:: ser.write("Hello World!") ser.close() +.. module:: Adafruit_BBIO.UART + .. function:: setup_uart(channel) Set up and start the UART channel. This function will effectively export @@ -117,6 +119,38 @@ Example:: Cleans up the UART. +:mod:`ADC` --- A/D Converter input interface +-------------------------------------------- + +This module enables reading analog input values from the analog to digital +converter (ADC) on the Beaglebone processor. + +Example:: + + import Adafruit_BBIO.ADC as ADC + + ADC.setup() + + # The read method returns normalized values from 0 to 1.0 + value = ADC.read("P9_40") + + # The read_raw returns non-normalized values + value = ADC.read_raw("P9_40") + +.. module:: Adafruit_BBIO.ADC + +.. function:: setup_adc() + + Setup and start the ADC hardware. + +.. function:: setup_read() + + Read the normalized 0-1.0 analog value for the channel. + +.. function:: setup_read_raw() + + Read the raw analog value for the channel. + Indices and tables ================== From 93b2a23613360304bbb93109b87ea85844f5d308 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 00:59:33 +0100 Subject: [PATCH 061/157] API docs: added SPI module --- docs/index.rst | 124 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 899e365..7266140 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,25 +28,20 @@ frequency. Set up and start the given PWM channel. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - :type duty_cycle: int - :param frequency: PWM frequency, in Hz. It must be greater than 0. - :type frequency: int - :param polarity: defines whether the value for ``duty_cycle`` affects the + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :param int frequency: PWM frequency, in Hz. It must be greater than 0. + :param int polarity: defines whether the value for ``duty_cycle`` affects the rising edge or the falling edge of the waveform. Allowed values -- 0 (rising edge, default) or 1 (falling edge). - :type polarity: int .. function:: stop(channel) Stop the given PWM channel. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str .. function:: set_duty_cycle(channel, duty_cycle) @@ -55,11 +50,9 @@ frequency. :note: You must have started the PWM channel with :func:`start()` once, before changing the duty cycle. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - :type duty_cycle: int + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. .. function:: set_frequency(channel, frequency) @@ -68,11 +61,9 @@ frequency. :note: You must have started the PWM channel with :func:`start()` once, before changing the frequency. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param frequency: PWM frequency. It must be greater than 0. - :type frequency: int + :param int frequency: PWM frequency. It must be greater than 0. .. function:: cleanup() @@ -151,6 +142,103 @@ Example:: Read the raw analog value for the channel. +:mod:`SPI` --- Serial Peripheral Interface +------------------------------------------ + +This module defines an object type that allows Serial Peripheral Interface +(SPI) bus transactions on hosts running the Linux kernel. The host kernel +must have SPI support and SPI device interface support. + +Because the SPI device interface is opened R/W, users of this module +usually must have root permissions or be members of a group with granted +access rights. + +Example:: + + import Adafruit_BBIO.SPI as SPI + + from Adafruit_BBIO.SPI import SPI + # spi = SPI(bus, device) #/dev/spidev. + + # /dev/spidev0.0 + spi = SPI(1, 0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev0.1 + spi = SPI(1,1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.0 + spi = SPI(2,0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.1 + spi = SPI(2,1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + +.. module:: Adafruit_BBIO.SPI + +.. class:: SPI(bus, client) + + :param bus: bus number + :param client: client number + :returns: a new SPI object, optionally connected to the specified SPI + device interface. + :rtype: :class:`SPI` + + .. method:: open(bus, device) + + Connects the object to the specified SPI device. `open(X, Y)` will open + `/dev/spidev-X.Y` + + :param int bus: bus number + :param str device: device number + + .. method:: close() + + Disconnects the object from the interface. + + .. method:: readbytes(len) + + Read the specified length of bytes from the SPI device. + + :param int len: length of bytes to read, 1024 maximum. + :returns: values read + :rtype: list[int] + + .. method:: writebytes(values) + + Write bytes to the SPI device. + + :param values: list of values to write, with a maximum length of 1024. + :type values: list[int] + + .. method:: xfer(values[,delay=0]) + + xfer([values]) -> [values] + Perform an SPI transaction of values. Slave Select (SS or CS) will be + released and reactivated between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :param delay: delay in microseconds between blocks. + :returns: values transferred + :rtype: list[int] + + .. method:: xfer2(values) + + xfer2([values]) -> [values] + Perform an SPI transaction of values. Slave Select (SS or CS) will be + held active between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :returns: values transferred + :rtype: list[int] Indices and tables ================== From 746c22c0a19a21ddac3153435487f516fe69ffd1 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 01:12:37 +0100 Subject: [PATCH 062/157] Added SPI module attribute docs --- docs/index.rst | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 7266140..1dbb02f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -184,12 +184,40 @@ Example:: .. class:: SPI(bus, client) - :param bus: bus number - :param client: client number + :param bus: bus number. + :param client: client number. :returns: a new SPI object, optionally connected to the specified SPI device interface. :rtype: :class:`SPI` + .. attribute:: bpw + + Bits per word. + + .. attribute:: cshigh + + Chip Select (CS or Slave Select, SS) active high. + + .. attribute:: loop + + Loopback configuration. + + .. attribute:: lsbfirst + + Least Significant Bit (LSB) first. + + .. attribute:: mode + + SPI mode as two bit pattern of Clock Polarity and Phase [CPOL|CPHA]; min-- 0b00 = 0, max-- 0b11 = 3. + + .. attribute:: msh + + Maximum speed in Hz. + + .. attribute:: threewire + + SI/SO signals are shared. + .. method:: open(bus, device) Connects the object to the specified SPI device. `open(X, Y)` will open From c379e3027854818f5afa19a5ad1048e475db1202 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 02:31:21 +0100 Subject: [PATCH 063/157] Added Python badges to README file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5fcaa57..d501a72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) [![Documentation Status](https://readthedocs.org/projects/adafruit-beaglebone-io-python/badge/?version=latest)](http://adafruit-beaglebone-io-python.readthedocs.io/en/latest/?badge=latest) +[![PyPI version](https://badge.fury.io/py/Adafruit_BBIO.svg)](https://badge.fury.io/py/Adafruit_BBIO) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/Adafruit_BBIO.svg)](https://pypi.python.org/pypi/Adafruit_BBIO/) * Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone From c84bc31074910feaac196df83aba228bd3a19e52 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 03:10:26 +0100 Subject: [PATCH 064/157] Added SPI pins table and first shot at GPIO module. Functions still need to be documented --- docs/index.rst | 109 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 1dbb02f..4ae5ced 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -102,9 +102,8 @@ Example:: the given UART so that it can be accessed by other software that controls its serial lines. - :param channel: UART channel to set up. One of "UART1", "UART2", + :param str channel: UART channel to set up. One of "UART1", "UART2", "UART4" or "UART5" - :type channel: str .. function:: cleanup() @@ -153,6 +152,16 @@ Because the SPI device interface is opened R/W, users of this module usually must have root permissions or be members of a group with granted access rights. +Pins used for SPI0 and SPI1 ++++++++++++++++++++++++++++ + +==== ===== ===== ===== ===== +PORT CS0 DO DI SCLK +==== ===== ===== ===== ===== +SPI0 P9_17 P9_21 P9_18 P9_22 +SPI1 P9_28 P9_29 P9_30 P9_31 +==== ===== ===== ===== ===== + Example:: import Adafruit_BBIO.SPI as SPI @@ -166,17 +175,17 @@ Example:: spi.close() # /dev/spidev0.1 - spi = SPI(1,1) + spi = SPI(1, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.0 - spi = SPI(2,0) + spi = SPI(2, 0) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.1 - spi = SPI(2,1) + spi = SPI(2, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() @@ -185,7 +194,7 @@ Example:: .. class:: SPI(bus, client) :param bus: bus number. - :param client: client number. + :param client: client device number. :returns: a new SPI object, optionally connected to the specified SPI device interface. :rtype: :class:`SPI` @@ -268,6 +277,94 @@ Example:: :returns: values transferred :rtype: list[int] +:mod:`GPIO` --- General Purpose I/O interface +--------------------------------------------- + +TODO + +Example:: + + # Use the config-pin command line tool to set a pin's function to GPIO + # Then you can control it with the GPIO module from Python + config-pin P9_14 gpio + + import Adafruit_BBIO.GPIO as GPIO + + # Set up pins as inputs or outputs + GPIO.setup("P8_13", GPIO.IN) + GPIO.setup("P8_14", GPIO.OUT) + GPIO.setup("GPIO0_26", GPIO.OUT) # Alternative: use actual pin names + + # Write a logic high or logic low + GPIO.output("P8_14", GPIO.HIGH) # You can also write '1' instead + GPIO.output("P8_14", GPIO.LOW) # You can also write '0' instead + +.. module:: Adafruit_BBIO.GPIO + +.. function:: setup() + + :param str channel: UART channel to set up. One of "UART1", "UART2", + "UART4" or "UART5" + +.. attribute:: ALT0 + + Pin mode-- alternate function 0. + +.. attribute:: BOTH + + Edge detection-- detect both edges. + +.. attribute:: FALLING + + Edge detection-- detect falling edge. + +.. attribute:: HIGH + + Pin status-- logic low. + +.. attribute:: IN + + Pin mode-- input. + +.. attribute:: LOW + + Pin status-- logic low. + +.. attribute:: OUT + + Pin mode-- output. + +.. attribute:: PUD_OFF + + Pull-up/pull-down resistor type-- no pull-up/pull-down. + +.. attribute:: PUD_DOWN + + Pull-up/pull-down resistor type-- pull-down. + +.. attribute:: PUD_UP + + Pull-up/pull-down resistor type-- pull-up. + +.. attribute:: RISING + + Edge detection-- detect rising edge. + +.. attribute:: VERSION + + GPIO module version. + +.. function:: cleanup() +.. function:: output() +.. function:: input() +.. function:: add_event_detect() +.. function:: remove_event_detect() +.. function:: add_event_detected() +.. function:: add_event_callback() +.. function:: wait_for_edge() +.. function:: gpio_function() +.. function:: setwarnings() + Indices and tables ================== From 2b7de7f3cd3feb2d82f7ac0e711a3cd15b65f186 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 14:04:40 +0100 Subject: [PATCH 065/157] Documented the API docs build process --- docs/README.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..abe18a1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,67 @@ +# Generating API documentation + +This folder contains the required files to automatically generate the Adafruit Beaglebone I/O Python API documentation, partly from the code docstrings and partly from a reStructuredText-formatted `index.rst` file. + +``` +├── conf.py <- Sphinx configuration file +├── index.rst <- Documentation will be generated based on this +└── Makefile <- Auxiliary Makefile to build documentation +``` + +The tools used are [http://www.sphinx-doc.org](Sphinx) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io), which automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches. Generally Readthedocs will be set up to track stable release branches and master. + +## Building the documentation + +The documentation can also be built on a local checkout of the project: + +First ensure you've got sphinx installed: + +``` +sudo pip install sphinx +``` + +Then you can build the HTML docs: + +``` +cd docs +make html +``` + +Once Sphinx has built the documentation, you can open the main index file with your browser: `_build/html/index.html` + +Notes: + +- The build process will create three additional temporary directories: `_build`, `_static` and `_templates` that will not be version-controlled. You can use `make clean` to remove their contents if you wish to do so. +- The html theme from files built locally is different from the online readthedocs theme. See the `docs/config.py` `html_theme` variable. The main reason is not to introduce another dependency to install the readthedocs theme, but as a side effect, it also helps visually distinguishing the locally-built documentation from the online version. + +## Readthedocs maintenance + +At every release that includes documenation (most probably 1.0.10 will be the first one), the release's branch needs to be selected in the web UI and marked as active. + +After this, documentation will automatically be generated and published for that release. It will be available at the same URL as the main documentation, and a link with the version number will be shown, where it can be accessed from. + +Optionally, the 'stable' URL slug can be pointed to that release branch. Otherwise, the 'stable' slug can also be deactivated for less maintenance overhead. + +The 'latest' URL slug will always be pointing at the repo's master branch. + +## Notes + +Ideally, all API documentation would be written in the source files as Python docstrings, and sphinx would simply extract it. This is actually the case with the `Encoder` module, which is pure Python. + +However, most of the code is written as C extensions. While they do provide docstrings once they are built, Sphinx does not natively support extracting them. There is [a workaround](https://stackoverflow.com/a/30110104/9022675) to do this, but it involves first building the extensions, installing them and hardcoding a path. While it might work for locally-built documentation, it's unlikely that readthedocs support this option. + +For the sake of keeping things simple and with less maintenance, the approach of documenting the C-generated API in the `index.rst` file has been taken. + +This has the advantage of having a definition of the API in one place, but it also poses the disadvantage of some duplication, as the C modules do define some docstrings for their objects. Then again, the API itself has hardly changed in the last few years, and the Beaglebone is a mature platform, so it's unlikely that this will pose a significant maintenance overhead. + +- The documentation in Python modules follows the Google readable docstring markup, which is fully supported by Sphinx. +- The documentation in the `index.rst` file is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), with Sphinx markup for defining the objects. + +## Further reference + +- [Google readable docstring markup](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments) +- [Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) +- [More Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)) +- [Sphinx docstring markup](http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain) + + From 32e63c992d8708e24fa0aab53bbe577afe606c81 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 17:11:48 +0100 Subject: [PATCH 066/157] Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. --- .gitignore | 3 + Adafruit_BBIO/Encoder.py | 120 +++++++++++++++++++-------- docs/Makefile | 20 +++++ docs/conf.py | 169 +++++++++++++++++++++++++++++++++++++++ docs/index.rst | 91 +++++++++++++++++++++ 5 files changed, 370 insertions(+), 33 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst diff --git a/.gitignore b/.gitignore index 5c0e38d..e948a66 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ m4/lt~obsolete.m4 missing source/Makefile.in test-driver +docs/_build +docs/_static +docs/_templates diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 35fd26f..ecfd27a 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -1,5 +1,62 @@ #!/usr/bin/python +"""Quadrature Encoder Pulse interface. + +This module enables access to the enhanced Quadrature Encoder Pulse (eQEP) +channels, which can be used to seamlessly interface with rotary encoder +hardware. + +The channel identifiers are available as module variables :data:`eQEP0`, +:data:`eQEP1`, :data:`eQEP2` and :data:`eQEP2b`. + +Example: + To use the module, you can connect a rotary encoder to your Beaglebone + and then simply instantiate the :class:`RotaryEncoder` class to read its position:: + + from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 + + # Instantiate the class to access channel eQEP2, and initialize + # that channel + myEncoder = RotaryEncoder(eQEP2) + + # Get the current position + cur_position = myEncoder.position + + # Set the current position + next_position = 15 + myEncoder.position = next_position + + # Reset position to 0 + myEncoder.zero() + + # Change mode to relative (default is absolute) + # You can use setAbsolute() to change back to absolute + # Absolute: the position starts at zero and is incremented or + # decremented by the encoder's movement + # Relative: the position is reset when the unit timer overflows. + myEncoder.setRelative() + + # Read the current mode (0: absolute, 1: relative) + # Mode can also be set as a property + mode = myEncoder.mode + + # Get the current frequency of update in Hz + freq = myEncoder.frequency + + # Set the update frequency to 1 kHz + myEncoder.frequency = 1000 + + # Disable the eQEP channel + myEncoder.disable() + + # Check if the channel is enabled + # The 'enabled' property is read-only + # Use the enable() and disable() methods to + # safely enable or disable the module + isEnabled = myEncoder.enabled + +""" + from subprocess import check_output, STDOUT, CalledProcessError import os import logging @@ -15,13 +72,20 @@ 'Your Linux kernel version is {}.'.format(platform.release())) -# eQEP module channel identifiers -# eQEP 2 and 2b are the same channel, exposed on two different sets of pins, -# which are mutually exclusive eQEP0 = 0 +'''eQEP0 channel identifier, pin A-- P9.92, pin B-- P9.27 on Beaglebone +Black.''' eQEP1 = 1 +'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone +Black.''' eQEP2 = 2 +'''eQEP2 channel identifier, pin A-- P8.12, pin B-- P8.11 on Beaglebone Black. +Note that there is only one eQEP2 module. This is one alternative set of pins +where it is exposed, which is mutually-exclusive with eQEP2b''' eQEP2b = 3 +'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone Black. +Note that there is only one eQEP2 module. This is one alternative set of pins +where it is exposed, which is mutually-exclusive with eQEP2''' # Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" @@ -37,7 +101,7 @@ ] -class eQEP(object): +class _eQEP(object): '''Enhanced Quadrature Encoder Pulse (eQEP) module class. Abstraction for either of the three available channels (eQEP0, eQEP1, eQEP2) on the Beaglebone''' @@ -51,7 +115,7 @@ def fromdict(cls, d): return cls(**df) def __init__(self, channel, pin_A, pin_B, sys_path): - '''Initialize the eQEP module + '''Initialize the given eQEP channel Attributes: channel (str): eQEP channel name. E.g. "eQEP0", "eQEP1", etc. @@ -79,21 +143,11 @@ class RotaryEncoder(object): ''' Rotary encoder class abstraction to control a given QEP channel. - Constructor: - eqep_num: QEP object that determines which channel to control - - Properties: - position: current position of the encoder - frequency: frequency at which the encoder reports new positions - enabled: (read only) true if the module is enabled, false otherwise - mode: current mode of the encoder (absolute: 0, relative: 1) - - Methods: - enable: enable the QEP channel - disable: disable the QEP channel - setAbsolute: shortcut for setting the mode to absolute - setRelative: shortcut for setting the mode to relative - zero: shortcut for setting the position to 0 + Args: + eqep_num (int): determines which eQEP pins are set up. + Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, + based on which pins the physical rotary encoder + is connected to. ''' def _run_cmd(self, cmd): @@ -117,15 +171,8 @@ def _config_pin(self, pin): self._run_cmd(["config-pin", pin, "qep"]) def __init__(self, eqep_num): - '''Creates an instance of the class RotaryEncoder. - - Arguments: - eqep_num: determines which eQEP pins are set up. - Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, - based on which pins the physical rotary encoder - is connected to. + '''Creates an instance of the class RotaryEncoder.''' - ''' # nanoseconds factor to convert period to frequency and back self._NS_FACTOR = 1000000000 @@ -134,7 +181,7 @@ def __init__(self, eqep_num): self._logger.addHandler(logging.NullHandler()) # Initialize the eQEP channel structures - self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) + self._eqep = _eQEP.fromdict(_eQEP_DEFS[eqep_num]) self._logger.info( "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, @@ -154,8 +201,8 @@ def __init__(self, eqep_num): def enabled(self): '''Returns the enabled status of the module: - true: module is enabled - false: module is disabled + Returns: + bool: True if the eQEP channel is enabled, False otherwise. ''' isEnabled = bool(int(self._eqep.node.enabled)) @@ -164,7 +211,11 @@ def enabled(self): def _setEnable(self, enabled): '''Turns the eQEP hardware ON or OFF - value (int): 1 represents enabled, 0 is disabled + Args: + enabled (int): enable the module with 1, disable it with 0. + + Raises: + ValueError: if the value for enabled is < 0 or > 1 ''' enabled = int(enabled) @@ -189,8 +240,11 @@ def disable(self): @property def mode(self): - '''Returns the mode the eQEP hardware is in (absolute or relative). + '''Returns the mode the eQEP hardware is in. + Returns: + int: 0 if the eQEP channel is configured in absolute mode, + 1 if configured in relative mode. ''' mode = int(self._eqep.node.mode) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..4430e8a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = Adafruit-BBIO +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..2ac0431 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,169 @@ +# -*- coding: utf-8 -*- +# +# Adafruit-BBIO documentation build configuration file, created by +# sphinx-quickstart on Fri Dec 1 12:56:03 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Adafruit-BBIO' +copyright = u'2017, Justin Cooper' +author = u'Justin Cooper' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'' +# The full version, including alpha/beta/rc tags. +release = u'1.0.9' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Adafruit-BBIOdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Adafruit-BBIO.tex', u'Adafruit-BBIO Documentation', + u'Justin Cooper', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'adafruit-bbio', u'Adafruit-BBIO Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Adafruit-BBIO', u'Adafruit-BBIO Documentation', + author, 'Adafruit-BBIO', 'One line description of project.', + 'Miscellaneous'), +] + +autodoc_member_order = 'groupwise' +#autoclass_content = 'both' + diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..9241ca6 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,91 @@ +.. Adafruit-BBIO documentation master file, created by + sphinx-quickstart on Fri Dec 1 12:56:03 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Adafruit Beaglebone IO Python API +================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + +:mod:`Encoder` --- Quadrature Encoder interface +----------------------------------------------- + +.. automodule:: Adafruit_BBIO.Encoder + :members: + +:mod:`PWM` --- Pulse Width Modulation interface +----------------------------------------------- + +Enables access to the Pulse Width Modulation (PWM) module, to easily and +accurately generate a PWM output signal of a given duty cycle and +frequency. + +.. module:: Adafruit_BBIO.PWM + +.. function:: start(channel, duty_cycle[, frequency=2000, polarity=0]) + + Set up and start the given PWM channel. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :type duty_cycle: int + :param frequency: PWM frequency, in Hz. It must be greater than 0. + :type frequency: int + :param polarity: defines whether the value for ``duty_cycle`` affects the + rising edge or the falling edge of the waveform. Allowed values -- 0 + (rising edge, default) or 1 (falling edge). + :type polarity: int + +.. function:: stop(channel) + + Stop the given PWM channel. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + +.. function:: set_duty_cycle(channel, duty_cycle) + + Change the duty cycle of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the duty cycle. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :type duty_cycle: int + +.. function:: set_frequency(channel, frequency) + + Change the frequency of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the frequency. + + :param channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :type channel: str + :param frequency: PWM frequency. It must be greater than 0. + :type frequency: int + +.. function:: cleanup() + + Clean up by resetting all GPIO channels that have been used by this + program to INPUT, with no pullup/pulldown and no event detection. + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + + From 47aa372a5bdaf81fdbca5f530709328d804b194f Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:24:03 +0100 Subject: [PATCH 067/157] Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails --- .gitignore | 3 +++ Adafruit_BBIO/Encoder.py | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index e948a66..facfc35 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,6 @@ test-driver docs/_build docs/_static docs/_templates + +# vim temp files +*~ diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index ecfd27a..39c40b6 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -11,7 +11,8 @@ Example: To use the module, you can connect a rotary encoder to your Beaglebone - and then simply instantiate the :class:`RotaryEncoder` class to read its position:: + and then simply instantiate the :class:`RotaryEncoder` class to read its + position:: from Adafruit_BBIO.Encoder import RotaryEncoder, eQEP2 @@ -65,7 +66,8 @@ import platform (major, minor, patch) = platform.release().split("-")[0].split(".") -if not (int(major) >= 4 and int(minor) >= 4): +if not (int(major) >= 4 and int(minor) >= 4) \ + and platform.node() == 'beaglebone': raise ImportError( 'The Encoder module requires Linux kernel version >= 4.4.x.\n' 'Please upgrade your kernel to use this module.\n' @@ -76,16 +78,16 @@ '''eQEP0 channel identifier, pin A-- P9.92, pin B-- P9.27 on Beaglebone Black.''' eQEP1 = 1 -'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone +'''eQEP1 channel identifier, pin A-- P9.35, pin B-- P9.33 on Beaglebone Black.''' eQEP2 = 2 '''eQEP2 channel identifier, pin A-- P8.12, pin B-- P8.11 on Beaglebone Black. Note that there is only one eQEP2 module. This is one alternative set of pins where it is exposed, which is mutually-exclusive with eQEP2b''' eQEP2b = 3 -'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone Black. -Note that there is only one eQEP2 module. This is one alternative set of pins -where it is exposed, which is mutually-exclusive with eQEP2''' +'''eQEP2(b) channel identifier, pin A-- P8.41, pin B-- P8.42 on Beaglebone +Black. Note that there is only one eQEP2 module. This is one alternative set of +pins where it is exposed, which is mutually-exclusive with eQEP2''' # Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" @@ -318,14 +320,13 @@ def position(self, position): self._logger.debug("Set position: Channel {}, position: {}".format( self._eqep.channel, position)) - @property def frequency(self): '''Sets the frequency in Hz at which the driver reports new positions. ''' - frequency = self._NS_FACTOR / int(self._eqep.node.period) + frequency = self._NS_FACTOR / int(self._eqep.node.period) self._logger.debug( "Set frequency(): Channel {}, frequency: {} Hz, " @@ -352,3 +353,4 @@ def zero(self): '''Resets the current position to 0''' self.position = 0 + From fa5a786ab3563b0fb0474da8a5e364115860fd14 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:47:03 +0100 Subject: [PATCH 068/157] Use the default readthedocs theme --- docs/conf.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 2ac0431..556134c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -102,11 +102,15 @@ # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ - 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', + 'localtoc.html' ] } +html_theme = "default" +html_theme_options = { + #"show_related": "true" +} # -- Options for HTMLHelp output ------------------------------------------ From 24337296dd0e25fbd28bcc86617e8588845fd87b Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 18:56:51 +0100 Subject: [PATCH 069/157] Use readthedocs theme if building docs there, remove redundand search link --- docs/conf.py | 10 ++++++---- docs/index.rst | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 556134c..0412db1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -107,10 +107,12 @@ ] } -html_theme = "default" -html_theme_options = { - #"show_related": "true" -} +# Use the readthedocs theme if the documentation is being built there +on_rtd = os.environ.get('READTHEDOCS') == 'True' +if on_rtd: + html_theme = 'default' +else: + html_theme = 'alabaster' # -- Options for HTMLHelp output ------------------------------------------ diff --git a/docs/index.rst b/docs/index.rst index 9241ca6..4b930ad 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -86,6 +86,5 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` -* :ref:`search` From be0a908142b59a03245922d0f222ebc07c6a6ae6 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 19:52:04 +0100 Subject: [PATCH 070/157] Readthedocs theme tweaks --- docs/conf.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0412db1..a620f16 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -100,19 +100,22 @@ # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -html_sidebars = { - '**': [ - 'searchbox.html', - 'localtoc.html' - ] -} # Use the readthedocs theme if the documentation is being built there on_rtd = os.environ.get('READTHEDOCS') == 'True' if on_rtd: html_theme = 'default' + html_theme_options = { + 'collapse_navigation': False, + } else: html_theme = 'alabaster' + html_sidebars = { + '**': [ + 'searchbox.html', + 'localtoc.html' + ] + } # -- Options for HTMLHelp output ------------------------------------------ From f9212b26760477baf55738863918b8bf77c9e2e3 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 20:14:42 +0100 Subject: [PATCH 071/157] Removed redundant TOC, added global description --- docs/index.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 4b930ad..2a7fdb4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,9 +6,8 @@ Adafruit Beaglebone IO Python API ================================= -.. toctree:: - :maxdepth: 2 - :caption: Contents: +The Adafruit Beaglebone IO API enables access to the Beaglebone's GPIO, PWM, +ADC, UART and eQEP hardware modules from Python programs. :mod:`Encoder` --- Quadrature Encoder interface ----------------------------------------------- From 0dc0ca73ab67bee4fb7c29d9ad16a34a22451cea Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 20:32:16 +0100 Subject: [PATCH 072/157] Added UART documentation --- docs/index.rst | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index 2a7fdb4..f4c8830 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -79,6 +79,44 @@ frequency. Clean up by resetting all GPIO channels that have been used by this program to INPUT, with no pullup/pulldown and no event detection. +:mod:`UART` --- UART communications interface +--------------------------------------------- + +UART functionality of a BeagleBone using Python. Generally used to set up +and grant access to a given UART device, which will then be accessed by +other software or modules (e.g. `pyserial`):: + + sudo pip install pyserial + +Example:: + + import Adafruit_BBIO.UART as UART + import serial + + UART.setup("UART1") + + ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) + ser.close() + ser.open() + if ser.isOpen(): + print "Serial is open!" + ser.write("Hello World!") + ser.close() + +.. function:: setup_uart(channel) + + Set up and start the UART channel. This function will effectively export + the given UART so that it can be accessed by other software that controls + its serial lines. + + :param channel: UART channel to set up. One of "UART1", "UART2", + "UART4" or "UART5" + :type channel: str + +.. function:: cleanup() + + Cleans up the UART. + Indices and tables ================== From f0487a7a3368fe9d8e54ff7fdb20dde10536a0e2 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 23:23:13 +0100 Subject: [PATCH 073/157] Added documentation badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e4db1e2..5fcaa57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) +[![Documentation Status](https://readthedocs.org/projects/adafruit-beaglebone-io-python/badge/?version=latest)](http://adafruit-beaglebone-io-python.readthedocs.io/en/latest/?badge=latest) + * Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) From 330b0f270a49d1c459f0756a8aaa9896eee27110 Mon Sep 17 00:00:00 2001 From: David Planella Date: Fri, 1 Dec 2017 23:38:31 +0100 Subject: [PATCH 074/157] Added ADC API docs, fixed UART module definition --- docs/index.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/index.rst b/docs/index.rst index f4c8830..899e365 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -103,6 +103,8 @@ Example:: ser.write("Hello World!") ser.close() +.. module:: Adafruit_BBIO.UART + .. function:: setup_uart(channel) Set up and start the UART channel. This function will effectively export @@ -117,6 +119,38 @@ Example:: Cleans up the UART. +:mod:`ADC` --- A/D Converter input interface +-------------------------------------------- + +This module enables reading analog input values from the analog to digital +converter (ADC) on the Beaglebone processor. + +Example:: + + import Adafruit_BBIO.ADC as ADC + + ADC.setup() + + # The read method returns normalized values from 0 to 1.0 + value = ADC.read("P9_40") + + # The read_raw returns non-normalized values + value = ADC.read_raw("P9_40") + +.. module:: Adafruit_BBIO.ADC + +.. function:: setup_adc() + + Setup and start the ADC hardware. + +.. function:: setup_read() + + Read the normalized 0-1.0 analog value for the channel. + +.. function:: setup_read_raw() + + Read the raw analog value for the channel. + Indices and tables ================== From 191b21408e9f208e7d254a0f8ddf613a34329e8d Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 00:59:33 +0100 Subject: [PATCH 075/157] API docs: added SPI module --- docs/index.rst | 124 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 899e365..7266140 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,25 +28,20 @@ frequency. Set up and start the given PWM channel. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - :type duty_cycle: int - :param frequency: PWM frequency, in Hz. It must be greater than 0. - :type frequency: int - :param polarity: defines whether the value for ``duty_cycle`` affects the + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :param int frequency: PWM frequency, in Hz. It must be greater than 0. + :param int polarity: defines whether the value for ``duty_cycle`` affects the rising edge or the falling edge of the waveform. Allowed values -- 0 (rising edge, default) or 1 (falling edge). - :type polarity: int .. function:: stop(channel) Stop the given PWM channel. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str .. function:: set_duty_cycle(channel, duty_cycle) @@ -55,11 +50,9 @@ frequency. :note: You must have started the PWM channel with :func:`start()` once, before changing the duty cycle. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - :type duty_cycle: int + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. .. function:: set_frequency(channel, frequency) @@ -68,11 +61,9 @@ frequency. :note: You must have started the PWM channel with :func:`start()` once, before changing the frequency. - :param channel: PWM channel. It can be specified in the form + :param str channel: PWM channel. It can be specified in the form of of 'P8_10', or 'EHRPWM2A'. - :type channel: str - :param frequency: PWM frequency. It must be greater than 0. - :type frequency: int + :param int frequency: PWM frequency. It must be greater than 0. .. function:: cleanup() @@ -151,6 +142,103 @@ Example:: Read the raw analog value for the channel. +:mod:`SPI` --- Serial Peripheral Interface +------------------------------------------ + +This module defines an object type that allows Serial Peripheral Interface +(SPI) bus transactions on hosts running the Linux kernel. The host kernel +must have SPI support and SPI device interface support. + +Because the SPI device interface is opened R/W, users of this module +usually must have root permissions or be members of a group with granted +access rights. + +Example:: + + import Adafruit_BBIO.SPI as SPI + + from Adafruit_BBIO.SPI import SPI + # spi = SPI(bus, device) #/dev/spidev. + + # /dev/spidev0.0 + spi = SPI(1, 0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev0.1 + spi = SPI(1,1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.0 + spi = SPI(2,0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.1 + spi = SPI(2,1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + +.. module:: Adafruit_BBIO.SPI + +.. class:: SPI(bus, client) + + :param bus: bus number + :param client: client number + :returns: a new SPI object, optionally connected to the specified SPI + device interface. + :rtype: :class:`SPI` + + .. method:: open(bus, device) + + Connects the object to the specified SPI device. `open(X, Y)` will open + `/dev/spidev-X.Y` + + :param int bus: bus number + :param str device: device number + + .. method:: close() + + Disconnects the object from the interface. + + .. method:: readbytes(len) + + Read the specified length of bytes from the SPI device. + + :param int len: length of bytes to read, 1024 maximum. + :returns: values read + :rtype: list[int] + + .. method:: writebytes(values) + + Write bytes to the SPI device. + + :param values: list of values to write, with a maximum length of 1024. + :type values: list[int] + + .. method:: xfer(values[,delay=0]) + + xfer([values]) -> [values] + Perform an SPI transaction of values. Slave Select (SS or CS) will be + released and reactivated between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :param delay: delay in microseconds between blocks. + :returns: values transferred + :rtype: list[int] + + .. method:: xfer2(values) + + xfer2([values]) -> [values] + Perform an SPI transaction of values. Slave Select (SS or CS) will be + held active between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :returns: values transferred + :rtype: list[int] Indices and tables ================== From 2769792028df6a7c425de8e2c459f428f2665536 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 01:12:37 +0100 Subject: [PATCH 076/157] Added SPI module attribute docs --- docs/index.rst | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 7266140..1dbb02f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -184,12 +184,40 @@ Example:: .. class:: SPI(bus, client) - :param bus: bus number - :param client: client number + :param bus: bus number. + :param client: client number. :returns: a new SPI object, optionally connected to the specified SPI device interface. :rtype: :class:`SPI` + .. attribute:: bpw + + Bits per word. + + .. attribute:: cshigh + + Chip Select (CS or Slave Select, SS) active high. + + .. attribute:: loop + + Loopback configuration. + + .. attribute:: lsbfirst + + Least Significant Bit (LSB) first. + + .. attribute:: mode + + SPI mode as two bit pattern of Clock Polarity and Phase [CPOL|CPHA]; min-- 0b00 = 0, max-- 0b11 = 3. + + .. attribute:: msh + + Maximum speed in Hz. + + .. attribute:: threewire + + SI/SO signals are shared. + .. method:: open(bus, device) Connects the object to the specified SPI device. `open(X, Y)` will open From e955585000eefdc338ae997062f52cb2c4893aa0 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 02:31:21 +0100 Subject: [PATCH 077/157] Added Python badges to README file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5fcaa57..d501a72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) [![Documentation Status](https://readthedocs.org/projects/adafruit-beaglebone-io-python/badge/?version=latest)](http://adafruit-beaglebone-io-python.readthedocs.io/en/latest/?badge=latest) +[![PyPI version](https://badge.fury.io/py/Adafruit_BBIO.svg)](https://badge.fury.io/py/Adafruit_BBIO) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/Adafruit_BBIO.svg)](https://pypi.python.org/pypi/Adafruit_BBIO/) * Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone From 4ab134b57257ee3e1eae2b3babcc6e5c8987d5e9 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 03:10:26 +0100 Subject: [PATCH 078/157] Added SPI pins table and first shot at GPIO module. Functions still need to be documented --- docs/index.rst | 109 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 1dbb02f..4ae5ced 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -102,9 +102,8 @@ Example:: the given UART so that it can be accessed by other software that controls its serial lines. - :param channel: UART channel to set up. One of "UART1", "UART2", + :param str channel: UART channel to set up. One of "UART1", "UART2", "UART4" or "UART5" - :type channel: str .. function:: cleanup() @@ -153,6 +152,16 @@ Because the SPI device interface is opened R/W, users of this module usually must have root permissions or be members of a group with granted access rights. +Pins used for SPI0 and SPI1 ++++++++++++++++++++++++++++ + +==== ===== ===== ===== ===== +PORT CS0 DO DI SCLK +==== ===== ===== ===== ===== +SPI0 P9_17 P9_21 P9_18 P9_22 +SPI1 P9_28 P9_29 P9_30 P9_31 +==== ===== ===== ===== ===== + Example:: import Adafruit_BBIO.SPI as SPI @@ -166,17 +175,17 @@ Example:: spi.close() # /dev/spidev0.1 - spi = SPI(1,1) + spi = SPI(1, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.0 - spi = SPI(2,0) + spi = SPI(2, 0) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.1 - spi = SPI(2,1) + spi = SPI(2, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() @@ -185,7 +194,7 @@ Example:: .. class:: SPI(bus, client) :param bus: bus number. - :param client: client number. + :param client: client device number. :returns: a new SPI object, optionally connected to the specified SPI device interface. :rtype: :class:`SPI` @@ -268,6 +277,94 @@ Example:: :returns: values transferred :rtype: list[int] +:mod:`GPIO` --- General Purpose I/O interface +--------------------------------------------- + +TODO + +Example:: + + # Use the config-pin command line tool to set a pin's function to GPIO + # Then you can control it with the GPIO module from Python + config-pin P9_14 gpio + + import Adafruit_BBIO.GPIO as GPIO + + # Set up pins as inputs or outputs + GPIO.setup("P8_13", GPIO.IN) + GPIO.setup("P8_14", GPIO.OUT) + GPIO.setup("GPIO0_26", GPIO.OUT) # Alternative: use actual pin names + + # Write a logic high or logic low + GPIO.output("P8_14", GPIO.HIGH) # You can also write '1' instead + GPIO.output("P8_14", GPIO.LOW) # You can also write '0' instead + +.. module:: Adafruit_BBIO.GPIO + +.. function:: setup() + + :param str channel: UART channel to set up. One of "UART1", "UART2", + "UART4" or "UART5" + +.. attribute:: ALT0 + + Pin mode-- alternate function 0. + +.. attribute:: BOTH + + Edge detection-- detect both edges. + +.. attribute:: FALLING + + Edge detection-- detect falling edge. + +.. attribute:: HIGH + + Pin status-- logic low. + +.. attribute:: IN + + Pin mode-- input. + +.. attribute:: LOW + + Pin status-- logic low. + +.. attribute:: OUT + + Pin mode-- output. + +.. attribute:: PUD_OFF + + Pull-up/pull-down resistor type-- no pull-up/pull-down. + +.. attribute:: PUD_DOWN + + Pull-up/pull-down resistor type-- pull-down. + +.. attribute:: PUD_UP + + Pull-up/pull-down resistor type-- pull-up. + +.. attribute:: RISING + + Edge detection-- detect rising edge. + +.. attribute:: VERSION + + GPIO module version. + +.. function:: cleanup() +.. function:: output() +.. function:: input() +.. function:: add_event_detect() +.. function:: remove_event_detect() +.. function:: add_event_detected() +.. function:: add_event_callback() +.. function:: wait_for_edge() +.. function:: gpio_function() +.. function:: setwarnings() + Indices and tables ================== From 6e0cf949dbd3c58ef6dcf1788d063b6ea9445d42 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 14:04:40 +0100 Subject: [PATCH 079/157] Documented the API docs build process --- docs/README.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..abe18a1 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,67 @@ +# Generating API documentation + +This folder contains the required files to automatically generate the Adafruit Beaglebone I/O Python API documentation, partly from the code docstrings and partly from a reStructuredText-formatted `index.rst` file. + +``` +├── conf.py <- Sphinx configuration file +├── index.rst <- Documentation will be generated based on this +└── Makefile <- Auxiliary Makefile to build documentation +``` + +The tools used are [http://www.sphinx-doc.org](Sphinx) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io), which automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches. Generally Readthedocs will be set up to track stable release branches and master. + +## Building the documentation + +The documentation can also be built on a local checkout of the project: + +First ensure you've got sphinx installed: + +``` +sudo pip install sphinx +``` + +Then you can build the HTML docs: + +``` +cd docs +make html +``` + +Once Sphinx has built the documentation, you can open the main index file with your browser: `_build/html/index.html` + +Notes: + +- The build process will create three additional temporary directories: `_build`, `_static` and `_templates` that will not be version-controlled. You can use `make clean` to remove their contents if you wish to do so. +- The html theme from files built locally is different from the online readthedocs theme. See the `docs/config.py` `html_theme` variable. The main reason is not to introduce another dependency to install the readthedocs theme, but as a side effect, it also helps visually distinguishing the locally-built documentation from the online version. + +## Readthedocs maintenance + +At every release that includes documenation (most probably 1.0.10 will be the first one), the release's branch needs to be selected in the web UI and marked as active. + +After this, documentation will automatically be generated and published for that release. It will be available at the same URL as the main documentation, and a link with the version number will be shown, where it can be accessed from. + +Optionally, the 'stable' URL slug can be pointed to that release branch. Otherwise, the 'stable' slug can also be deactivated for less maintenance overhead. + +The 'latest' URL slug will always be pointing at the repo's master branch. + +## Notes + +Ideally, all API documentation would be written in the source files as Python docstrings, and sphinx would simply extract it. This is actually the case with the `Encoder` module, which is pure Python. + +However, most of the code is written as C extensions. While they do provide docstrings once they are built, Sphinx does not natively support extracting them. There is [a workaround](https://stackoverflow.com/a/30110104/9022675) to do this, but it involves first building the extensions, installing them and hardcoding a path. While it might work for locally-built documentation, it's unlikely that readthedocs support this option. + +For the sake of keeping things simple and with less maintenance, the approach of documenting the C-generated API in the `index.rst` file has been taken. + +This has the advantage of having a definition of the API in one place, but it also poses the disadvantage of some duplication, as the C modules do define some docstrings for their objects. Then again, the API itself has hardly changed in the last few years, and the Beaglebone is a mature platform, so it's unlikely that this will pose a significant maintenance overhead. + +- The documentation in Python modules follows the Google readable docstring markup, which is fully supported by Sphinx. +- The documentation in the `index.rst` file is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), with Sphinx markup for defining the objects. + +## Further reference + +- [Google readable docstring markup](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments) +- [Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) +- [More Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)) +- [Sphinx docstring markup](http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain) + + From 30794971cf0d4464c655d2f9cbf936eb52bc272d Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 14:15:12 +0100 Subject: [PATCH 080/157] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d501a72..66f8414 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Adafruit BeagleBone I/O Python Library (Adafruit_BBIO) +# Adafruit Beaglebone I/O Python API [![Documentation Status](https://readthedocs.org/projects/adafruit-beaglebone-io-python/badge/?version=latest)](http://adafruit-beaglebone-io-python.readthedocs.io/en/latest/?badge=latest) [![PyPI version](https://badge.fury.io/py/Adafruit_BBIO.svg)](https://badge.fury.io/py/Adafruit_BBIO) [![PyPI pyversions](https://img.shields.io/pypi/pyversions/Adafruit_BBIO.svg)](https://pypi.python.org/pypi/Adafruit_BBIO/) -* Adafruit_BBIO is a set of Python tools to allow [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc) and [UART](README.md#uart) access on the BeagleBone +Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart), SPI and eQEP hardware access from Python applications running on the Beaglebone. * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) * **Currently recommended image: [Debian 9.2 "Stretch" iot (2017-10-29)](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#microSD.2FStandalone:_.28stretch-iot.29_.28All_BeagleBone_Variants_.26_PocketBeagle.29)** From a86300f18480cc3c71f1644efb0f00594a504f17 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 15:56:13 +0100 Subject: [PATCH 081/157] Added some more API doc content --- docs/README.md | 9 +++++---- docs/index.rst | 29 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index abe18a1..4f88a47 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,7 +3,7 @@ This folder contains the required files to automatically generate the Adafruit Beaglebone I/O Python API documentation, partly from the code docstrings and partly from a reStructuredText-formatted `index.rst` file. ``` -├── conf.py <- Sphinx configuration file +├── conf.py <- Sphinx configuration file ├── index.rst <- Documentation will be generated based on this └── Makefile <- Auxiliary Makefile to build documentation ``` @@ -54,14 +54,15 @@ For the sake of keeping things simple and with less maintenance, the approach of This has the advantage of having a definition of the API in one place, but it also poses the disadvantage of some duplication, as the C modules do define some docstrings for their objects. Then again, the API itself has hardly changed in the last few years, and the Beaglebone is a mature platform, so it's unlikely that this will pose a significant maintenance overhead. -- The documentation in Python modules follows the Google readable docstring markup, which is fully supported by Sphinx. -- The documentation in the `index.rst` file is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), with Sphinx markup for defining the objects. +- The documentation in the `index.rst` file is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), extended with Sphinx markup for defining the objects. +- The documentation in Python modules follows the Google readable docstring markup, which also builds upon reStructuredText and is fully supported by Sphinx. ## Further reference - [Google readable docstring markup](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments) - [Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) -- [More Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html)) +- [More Google docstring examples](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) - [Sphinx docstring markup](http://www.sphinx-doc.org/en/stable/domains.html#the-python-domain) +- [reStructuredText primer](http://www.sphinx-doc.org/en/stable/rest.html#rst-primer) diff --git a/docs/index.rst b/docs/index.rst index 4ae5ced..4011231 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,6 +3,10 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. toctree:: + :hidden: + :maxdepth: 2 + Adafruit Beaglebone IO Python API ================================= @@ -22,6 +26,14 @@ Enables access to the Pulse Width Modulation (PWM) module, to easily and accurately generate a PWM output signal of a given duty cycle and frequency. +.. note:: + + You need to be part of the ``pwm`` group of the OS running on the + Beaglebone to be able to run PWM code as a non-root user. The default + user created upon the Debian image installation should already be + part of the group. Otherwise, you can use + ``sudo usermod -a -G pwm userName`` to add ``userName`` to the group. + .. module:: Adafruit_BBIO.PWM .. function:: start(channel, duty_cycle[, frequency=2000, polarity=0]) @@ -256,7 +268,6 @@ Example:: .. method:: xfer(values[,delay=0]) - xfer([values]) -> [values] Perform an SPI transaction of values. Slave Select (SS or CS) will be released and reactivated between blocks. @@ -268,7 +279,6 @@ Example:: .. method:: xfer2(values) - xfer2([values]) -> [values] Perform an SPI transaction of values. Slave Select (SS or CS) will be held active between blocks. @@ -282,6 +292,21 @@ Example:: TODO +.. note:: + + You need to be part of the ``gpio`` group of the OS running on the + Beaglebone to be able to run GPIO code as a non-root user. The default + user created upon the Debian image installation should already be + part of the group. Otherwise, you can use + ``sudo usermod -a -G gpio userName`` to add ``userName`` to the group. + +.. note:: + + When coding with this module, you will often be using pin names for + better readability. For easy reference, you can use the + `Beaglebone pin names table `_ + + Example:: # Use the config-pin command line tool to set a pin's function to GPIO From 6e9ea9245da1db985314f3f55bdcd0042bbee668 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 16:27:48 +0100 Subject: [PATCH 082/157] Minor documentation and configuration improvements --- Adafruit_BBIO/Encoder.py | 2 +- docs/conf.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 39c40b6..d2915c9 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -246,7 +246,7 @@ def mode(self): Returns: int: 0 if the eQEP channel is configured in absolute mode, - 1 if configured in relative mode. + 1 if configured in relative mode. ''' mode = int(self._eqep.node.mode) diff --git a/docs/conf.py b/docs/conf.py index a620f16..d99d788 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,8 +46,8 @@ # General information about the project. project = u'Adafruit-BBIO' -copyright = u'2017, Justin Cooper' -author = u'Justin Cooper' +copyright = u'2017, Adafruit Industries and contributors' +author = u'Justin Cooper and contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -82,7 +82,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +# html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the From f12715b2772420245ed4368334cd407df4cc7732 Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 18:19:00 +0100 Subject: [PATCH 083/157] Finished documenting GPIO --- .gitignore | 1 + Adafruit_BBIO/Encoder.py | 9 +++ docs/conf.py | 4 +- docs/index.rst | 136 ++++++++++++++++++++++++++++++++------- 4 files changed, 124 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index facfc35..06eca82 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ docs/_templates # vim temp files *~ +*.swp diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index d2915c9..21c88c1 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -9,6 +9,15 @@ The channel identifiers are available as module variables :data:`eQEP0`, :data:`eQEP1`, :data:`eQEP2` and :data:`eQEP2b`. +======= ======= ======= =================================================== +Channel Pin A Pin B Notes +======= ======= ======= =================================================== +eQEP0 P9.27 P9.92 +eQEP1 P8.33 P8.35 Only available with video disabled +eQEP2 P8.11 P8.12 Only available with eQEP2b unused (same channel) +eQEP2b P8.41 P8.42 Only available with video disabled and eQEP2 unused +======= ======= ======= =================================================== + Example: To use the module, you can connect a rotary encoder to your Beaglebone and then simply instantiate the :class:`RotaryEncoder` class to read its diff --git a/docs/conf.py b/docs/conf.py index d99d788..c002fc2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -54,9 +54,9 @@ # built documents. # # The short X.Y version. -version = u'' +version = u'1.0' # The full version, including alpha/beta/rc tags. -release = u'1.0.9' +release = u'' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/index.rst b/docs/index.rst index 4011231..3d39377 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -22,7 +22,7 @@ ADC, UART and eQEP hardware modules from Python programs. :mod:`PWM` --- Pulse Width Modulation interface ----------------------------------------------- -Enables access to the Pulse Width Modulation (PWM) module, to easily and +Enables access to the Pulse Width Modulation (PWM) module, to easily and accurately generate a PWM output signal of a given duty cycle and frequency. @@ -160,7 +160,7 @@ This module defines an object type that allows Serial Peripheral Interface (SPI) bus transactions on hosts running the Linux kernel. The host kernel must have SPI support and SPI device interface support. -Because the SPI device interface is opened R/W, users of this module +Because the SPI device interface is opened R/W, users of this module usually must have root permissions or be members of a group with granted access rights. @@ -184,22 +184,22 @@ Example:: # /dev/spidev0.0 spi = SPI(1, 0) print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() + spi.close() # /dev/spidev0.1 spi = SPI(1, 1) print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() + spi.close() # /dev/spidev1.0 spi = SPI(2, 0) print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() + spi.close() # /dev/spidev1.1 spi = SPI(2, 1) print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() + spi.close() .. module:: Adafruit_BBIO.SPI @@ -290,7 +290,8 @@ Example:: :mod:`GPIO` --- General Purpose I/O interface --------------------------------------------- -TODO +This module provides access and control of pins set up as General Purpose +I/O (GPIO). .. note:: @@ -302,8 +303,10 @@ TODO .. note:: - When coding with this module, you will often be using pin names for - better readability. For easy reference, you can use the + When coding with this module, you will be using pin names for + better readability. As such, you can specify them in the header 8 or 9 + form (e.g. "P8_16") or in pin name form (e.g. "GPIO1_14"). + For easy reference, you can use the `Beaglebone pin names table `_ @@ -326,10 +329,106 @@ Example:: .. module:: Adafruit_BBIO.GPIO -.. function:: setup() +.. function:: setup(channel, direction[, pull_up_down=:data:`PUD_OFF`, initial=None, delay=0]) - :param str channel: UART channel to set up. One of "UART1", "UART2", - "UART4" or "UART5" + Set up the given GPIO channel, its direction and (optional) pull/up down control + + :param str channel: GPIO channel to set up (e.g. "P8_16"). + :param int direction: GPIO channel direction (:data:`IN` or :data:`OUT`). + :param int pull_up_down: pull-up/pull-down resistor configuration + (:data:`PUD_OFF`, :data:`PUD_UP` or :data:`PUD_DOWN`). + :param int initial: initial value for an output channel (:data:`LOW`/:data:`HIGH`). + :param int delay: time in milliseconds to wait after exporting the GPIO pin. + +.. function:: cleanup() + + Clean up by resetting all GPIO channels that have been used by + the application to :data:`IN` with no pullup/pulldown and no event + detection. + +.. function:: output(channel, value) + + Set the given output channel to the given digital value. + + :param str channel: GPIO channel to output the value to (e.g. "P8_16"). + :param value: value to set the output to-- 0/1 or False/True + or :data:`LOW`/:data:`HIGH`. + :type value: int or bool + +.. function:: input(channel) + + Get the given input channel's digital value. + + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + :returns: Channel value–– 0 or 1. + :rtype: int + +.. function:: add_event_detect(channel, edge[, callback=None, bouncetime=0]) + + Enable edge detection events for the given GPIO channel. + + :param str channel: GPIO channel to detect events from (e.g. "P8_16"). + :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` + or :data:`BOTH` + :param func callback: a function to call once the event has been detected. + :param int bouncetime: switch bounce timeout in ms for the callback. + +.. function:: remove_event_detect(channel) + + Remove edge detection for the given GPIO channel. + + :param str channel: GPIO channel to remove event detection + from (e.g. "P8_16"). + +.. function:: event_detected(channel) + + Checks if an edge event has occured on a given GPIO. + + :note: You need to enable edge detection using :func:`add_event_detect()` first. + + :param str channel: GPIO channel to check for event detection + for (e.g. "P8_16"). + :returns: True if an edge has occured on a given GPIO, False otherwise + :rtype: bool + +.. function:: add_event_callback(channel, callback[, bouncetime=0]) + + Add a callback for an event already defined using :func:`add_event_detect()` + + :param str channel: GPIO channel to add a callback to (e.g. "P8_16"). + :param func callback: a function to call once the event has been detected. + :param int bouncetime: switch bounce timeout in ms for the callback. + +.. function:: wait_for_edge(channel, edge[, timeout=-1]) + + Wait for an edge on the given channel. + + :param str channel: GPIO channel to wait on (e.g. "P8_16"). + :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` + or :data:`BOTH` + :param int timeout: time to wait for an edge, in milliseconds. + -1 will wait forever. + +.. function:: gpio_function(channel) + + Return the current GPIO function + (:data:`IN`, :data:`IN`, :data:`ALT0`) of the given pin. + + :warning: Currently only returning the direction of the + pin (input or output) is supported. + + :param str channel: GPIO pin to query the status of. + :returns: 0 if :data:`IN`, 1 if :data:`OUT` + :rtype: int + +.. function:: setwarnings(gpio_warnings) + + Enable or disable GPIO warning messages. + + :warning: Currently enabling or disabling warnings + has no effect. + + :param int gpio_warnings: 0–– disable warnings; 1–– enable warnings .. attribute:: ALT0 @@ -377,18 +476,7 @@ Example:: .. attribute:: VERSION - GPIO module version. - -.. function:: cleanup() -.. function:: output() -.. function:: input() -.. function:: add_event_detect() -.. function:: remove_event_detect() -.. function:: add_event_detected() -.. function:: add_event_callback() -.. function:: wait_for_edge() -.. function:: gpio_function() -.. function:: setwarnings() + GPIO module version. Currently unused. Indices and tables ================== From 55aa0a9da4cefd624680e1066135f3dd207d7f8f Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 18:25:48 +0100 Subject: [PATCH 084/157] rST fixes --- docs/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 3d39377..252ce6e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -329,7 +329,7 @@ Example:: .. module:: Adafruit_BBIO.GPIO -.. function:: setup(channel, direction[, pull_up_down=:data:`PUD_OFF`, initial=None, delay=0]) +.. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) Set up the given GPIO channel, its direction and (optional) pull/up down control @@ -346,6 +346,9 @@ Example:: the application to :data:`IN` with no pullup/pulldown and no event detection. + :note: It's recommended that you call this function upon exiting your + application. + .. function:: output(channel, value) Set the given output channel to the given digital value. From 9d6aa46a61f77594d76cb8759f71e1dff3b4260e Mon Sep 17 00:00:00 2001 From: David Planella Date: Sat, 2 Dec 2017 18:57:58 +0100 Subject: [PATCH 085/157] Update README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 4f88a47..e2b2188 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ This folder contains the required files to automatically generate the Adafruit B └── Makefile <- Auxiliary Makefile to build documentation ``` -The tools used are [http://www.sphinx-doc.org](Sphinx) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io), which automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches. Generally Readthedocs will be set up to track stable release branches and master. +The tools used are [Sphinx](http://www.sphinx-doc.org) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io), which automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches. Generally Readthedocs will be set up to track stable release branches and master. ## Building the documentation From f2f5c0af7e62b79280e45935c7639b01d24afe42 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 3 Dec 2017 03:44:43 -0600 Subject: [PATCH 086/157] relocate doc dir to avoid confusion (#218) Now that there is 'docs' dir, move existing 'doc' dir containing misc documentation into 'test/notes' dir. Signed-off-by: Drew Fustini --- {doc => test/notes}/rotary-encoder-eqep-test.md | 0 {doc => test/notes}/run_config-pin_during_startup.md | 0 {doc => test/notes}/spi_loopback_test.md | 0 {doc => test/notes}/test_read_write_all_gpio_pins.md | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {doc => test/notes}/rotary-encoder-eqep-test.md (100%) rename {doc => test/notes}/run_config-pin_during_startup.md (100%) rename {doc => test/notes}/spi_loopback_test.md (100%) rename {doc => test/notes}/test_read_write_all_gpio_pins.md (100%) diff --git a/doc/rotary-encoder-eqep-test.md b/test/notes/rotary-encoder-eqep-test.md similarity index 100% rename from doc/rotary-encoder-eqep-test.md rename to test/notes/rotary-encoder-eqep-test.md diff --git a/doc/run_config-pin_during_startup.md b/test/notes/run_config-pin_during_startup.md similarity index 100% rename from doc/run_config-pin_during_startup.md rename to test/notes/run_config-pin_during_startup.md diff --git a/doc/spi_loopback_test.md b/test/notes/spi_loopback_test.md similarity index 100% rename from doc/spi_loopback_test.md rename to test/notes/spi_loopback_test.md diff --git a/doc/test_read_write_all_gpio_pins.md b/test/notes/test_read_write_all_gpio_pins.md similarity index 100% rename from doc/test_read_write_all_gpio_pins.md rename to test/notes/test_read_write_all_gpio_pins.md From b1e0db2a29d67a010daa1b9af0413c1dfc76c3c3 Mon Sep 17 00:00:00 2001 From: David Planella Date: Mon, 4 Dec 2017 12:52:59 +0100 Subject: [PATCH 087/157] Minor API doc improvements --- docs/index.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 3d39377..252ce6e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -329,7 +329,7 @@ Example:: .. module:: Adafruit_BBIO.GPIO -.. function:: setup(channel, direction[, pull_up_down=:data:`PUD_OFF`, initial=None, delay=0]) +.. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) Set up the given GPIO channel, its direction and (optional) pull/up down control @@ -346,6 +346,9 @@ Example:: the application to :data:`IN` with no pullup/pulldown and no event detection. + :note: It's recommended that you call this function upon exiting your + application. + .. function:: output(channel, value) Set the given output channel to the given digital value. From edc1799df2ce58bd9e8187d59fdd9c56418c0b6e Mon Sep 17 00:00:00 2001 From: David Planella Date: Mon, 4 Dec 2017 13:50:41 +0100 Subject: [PATCH 088/157] Generate the API documentation from a master index and a separate file for each module --- docs/ADC.rst | 36 ++++ docs/Encoder.rst | 5 + docs/GPIO.rst | 194 +++++++++++++++++++ docs/PWM.rst | 62 ++++++ docs/SPI.rst | 134 +++++++++++++ docs/UART.rst | 39 ++++ docs/index.rst | 483 ++--------------------------------------------- 7 files changed, 481 insertions(+), 472 deletions(-) create mode 100644 docs/ADC.rst create mode 100644 docs/Encoder.rst create mode 100644 docs/GPIO.rst create mode 100644 docs/PWM.rst create mode 100644 docs/SPI.rst create mode 100644 docs/UART.rst diff --git a/docs/ADC.rst b/docs/ADC.rst new file mode 100644 index 0000000..ae90254 --- /dev/null +++ b/docs/ADC.rst @@ -0,0 +1,36 @@ +:mod:`ADC` --- A/D Converter input interface +-------------------------------------------- + +This module enables reading analog input values from the analog to digital +converter (ADC) on the Beaglebone processor. + +Example:: + + import Adafruit_BBIO.ADC as ADC + + ADC.setup() + + # The read method returns normalized values from 0 to 1.0 + value = ADC.read("P9_40") + + # The read_raw returns non-normalized values + value = ADC.read_raw("P9_40") + +.. module:: Adafruit_BBIO.ADC + +.. function:: setup_adc() + + Setup and start the ADC hardware. + +.. function:: setup_read(channel) + + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + + Read the normalized 0-1.0 analog value for the channel. + +.. function:: setup_read_raw(channel) + + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + + Read the raw analog value for the channel. + diff --git a/docs/Encoder.rst b/docs/Encoder.rst new file mode 100644 index 0000000..7716e3b --- /dev/null +++ b/docs/Encoder.rst @@ -0,0 +1,5 @@ +:mod:`Encoder` --- Quadrature Encoder interface +----------------------------------------------- + +.. automodule:: Adafruit_BBIO.Encoder + :members: diff --git a/docs/GPIO.rst b/docs/GPIO.rst new file mode 100644 index 0000000..b95b2b3 --- /dev/null +++ b/docs/GPIO.rst @@ -0,0 +1,194 @@ +:mod:`GPIO` --- General Purpose I/O interface +--------------------------------------------- + +This module provides access and control of pins set up as General Purpose +I/O (GPIO). + +.. note:: + + You need to be part of the ``gpio`` group of the OS running on the + Beaglebone to be able to run GPIO code as a non-root user. The default + user created upon the Debian image installation should already be + part of the group. Otherwise, you can use + ``sudo usermod -a -G gpio userName`` to add ``userName`` to the group. + +.. note:: + + When coding with this module, you will be using pin names for + better readability. As such, you can specify them in the header 8 or 9 + form (e.g. "P8_16") or in pin name form (e.g. "GPIO1_14"). + For easy reference, you can use the + `Beaglebone pin names table `_ + + +Example:: + + # Use the config-pin command line tool to set a pin's function to GPIO + # Then you can control it with the GPIO module from Python + config-pin P9_14 gpio + + import Adafruit_BBIO.GPIO as GPIO + + # Set up pins as inputs or outputs + GPIO.setup("P8_13", GPIO.IN) + GPIO.setup("P8_14", GPIO.OUT) + GPIO.setup("GPIO0_26", GPIO.OUT) # Alternative: use actual pin names + + # Write a logic high or logic low + GPIO.output("P8_14", GPIO.HIGH) # You can also write '1' instead + GPIO.output("P8_14", GPIO.LOW) # You can also write '0' instead + +.. module:: Adafruit_BBIO.GPIO + +.. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) + + Set up the given GPIO channel, its direction and (optional) pull/up down control + + :param str channel: GPIO channel to set up (e.g. "P8_16"). + :param int direction: GPIO channel direction (:data:`IN` or :data:`OUT`). + :param int pull_up_down: pull-up/pull-down resistor configuration + (:data:`PUD_OFF`, :data:`PUD_UP` or :data:`PUD_DOWN`). + :param int initial: initial value for an output channel (:data:`LOW`/:data:`HIGH`). + :param int delay: time in milliseconds to wait after exporting the GPIO pin. + +.. function:: cleanup() + + Clean up by resetting all GPIO channels that have been used by + the application to :data:`IN` with no pullup/pulldown and no event + detection. + + :note: It's recommended that you call this function upon exiting your + application. + +.. function:: output(channel, value) + + Set the given output channel to the given digital value. + + :param str channel: GPIO channel to output the value to (e.g. "P8_16"). + :param value: value to set the output to-- 0/1 or False/True + or :data:`LOW`/:data:`HIGH`. + :type value: int or bool + +.. function:: input(channel) + + Get the given input channel's digital value. + + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + :returns: Channel value–– 0 or 1. + :rtype: int + +.. function:: add_event_detect(channel, edge[, callback=None, bouncetime=0]) + + Enable edge detection events for the given GPIO channel. + + :param str channel: GPIO channel to detect events from (e.g. "P8_16"). + :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` + or :data:`BOTH` + :param func callback: a function to call once the event has been detected. + :param int bouncetime: switch bounce timeout in ms for the callback. + +.. function:: remove_event_detect(channel) + + Remove edge detection for the given GPIO channel. + + :param str channel: GPIO channel to remove event detection + from (e.g. "P8_16"). + +.. function:: event_detected(channel) + + Checks if an edge event has occured on a given GPIO. + + :note: You need to enable edge detection using :func:`add_event_detect()` first. + + :param str channel: GPIO channel to check for event detection + for (e.g. "P8_16"). + :returns: True if an edge has occured on a given GPIO, False otherwise + :rtype: bool + +.. function:: add_event_callback(channel, callback[, bouncetime=0]) + + Add a callback for an event already defined using :func:`add_event_detect()` + + :param str channel: GPIO channel to add a callback to (e.g. "P8_16"). + :param func callback: a function to call once the event has been detected. + :param int bouncetime: switch bounce timeout in ms for the callback. + +.. function:: wait_for_edge(channel, edge[, timeout=-1]) + + Wait for an edge on the given channel. + + :param str channel: GPIO channel to wait on (e.g. "P8_16"). + :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` + or :data:`BOTH` + :param int timeout: time to wait for an edge, in milliseconds. + -1 will wait forever. + +.. function:: gpio_function(channel) + + Return the current GPIO function + (:data:`IN`, :data:`IN`, :data:`ALT0`) of the given pin. + + :warning: Currently only returning the direction of the + pin (input or output) is supported. + + :param str channel: GPIO pin to query the status of. + :returns: 0 if :data:`IN`, 1 if :data:`OUT` + :rtype: int + +.. function:: setwarnings(gpio_warnings) + + Enable or disable GPIO warning messages. + + :warning: Currently enabling or disabling warnings + has no effect. + + :param int gpio_warnings: 0–– disable warnings; 1–– enable warnings + +.. attribute:: ALT0 + + Pin mode-- alternate function 0. + +.. attribute:: BOTH + + Edge detection-- detect both edges. + +.. attribute:: FALLING + + Edge detection-- detect falling edge. + +.. attribute:: HIGH + + Pin status-- logic low. + +.. attribute:: IN + + Pin mode-- input. + +.. attribute:: LOW + + Pin status-- logic low. + +.. attribute:: OUT + + Pin mode-- output. + +.. attribute:: PUD_OFF + + Pull-up/pull-down resistor type-- no pull-up/pull-down. + +.. attribute:: PUD_DOWN + + Pull-up/pull-down resistor type-- pull-down. + +.. attribute:: PUD_UP + + Pull-up/pull-down resistor type-- pull-up. + +.. attribute:: RISING + + Edge detection-- detect rising edge. + +.. attribute:: VERSION + + GPIO module version. Currently unused. + diff --git a/docs/PWM.rst b/docs/PWM.rst new file mode 100644 index 0000000..95d428a --- /dev/null +++ b/docs/PWM.rst @@ -0,0 +1,62 @@ +:mod:`PWM` --- Pulse Width Modulation interface +----------------------------------------------- + +Enables access to the Pulse Width Modulation (PWM) module, to easily and +accurately generate a PWM output signal of a given duty cycle and +frequency. + +.. note:: + + You need to be part of the ``pwm`` group of the OS running on the + Beaglebone to be able to run PWM code as a non-root user. The default + user created upon the Debian image installation should already be + part of the group. Otherwise, you can use + ``sudo usermod -a -G pwm userName`` to add ``userName`` to the group. + +.. module:: Adafruit_BBIO.PWM + +.. function:: start(channel, duty_cycle[, frequency=2000, polarity=0]) + + Set up and start the given PWM channel. + + :param str channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + :param int frequency: PWM frequency, in Hz. It must be greater than 0. + :param int polarity: defines whether the value for ``duty_cycle`` affects the + rising edge or the falling edge of the waveform. Allowed values -- 0 + (rising edge, default) or 1 (falling edge). + +.. function:: stop(channel) + + Stop the given PWM channel. + + :param str channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + +.. function:: set_duty_cycle(channel, duty_cycle) + + Change the duty cycle of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the duty cycle. + + :param str channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. + +.. function:: set_frequency(channel, frequency) + + Change the frequency of the given PWM channel. + + :note: You must have started the PWM channel with :func:`start()` + once, before changing the frequency. + + :param str channel: PWM channel. It can be specified in the form + of of 'P8_10', or 'EHRPWM2A'. + :param int frequency: PWM frequency. It must be greater than 0. + +.. function:: cleanup() + + Clean up by resetting all GPIO channels that have been used by this + program to INPUT, with no pullup/pulldown and no event detection. diff --git a/docs/SPI.rst b/docs/SPI.rst new file mode 100644 index 0000000..d33aa5a --- /dev/null +++ b/docs/SPI.rst @@ -0,0 +1,134 @@ +:mod:`SPI` --- Serial Peripheral Interface +------------------------------------------ + +This module defines an object type that allows Serial Peripheral Interface +(SPI) bus transactions on hosts running the Linux kernel. The host kernel +must have SPI support and SPI device interface support. + +Because the SPI device interface is opened R/W, users of this module +usually must have root permissions or be members of a group with granted +access rights. + +Pins used for SPI0 and SPI1 ++++++++++++++++++++++++++++ + +==== ===== ===== ===== ===== +PORT CS0 DO DI SCLK +==== ===== ===== ===== ===== +SPI0 P9_17 P9_21 P9_18 P9_22 +SPI1 P9_28 P9_29 P9_30 P9_31 +==== ===== ===== ===== ===== + +Example:: + + import Adafruit_BBIO.SPI as SPI + + from Adafruit_BBIO.SPI import SPI + # spi = SPI(bus, device) #/dev/spidev. + + # /dev/spidev0.0 + spi = SPI(1, 0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev0.1 + spi = SPI(1, 1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.0 + spi = SPI(2, 0) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + + # /dev/spidev1.1 + spi = SPI(2, 1) + print(spi.xfer2([32, 11, 110, 22, 220])) + spi.close() + +.. module:: Adafruit_BBIO.SPI + +.. class:: SPI(bus, client) + + :param bus: bus number. + :param client: client device number. + :returns: a new SPI object, optionally connected to the specified SPI + device interface. + :rtype: :class:`SPI` + + .. attribute:: bpw + + Bits per word. + + .. attribute:: cshigh + + Chip Select (CS or Slave Select, SS) active high. + + .. attribute:: loop + + Loopback configuration. + + .. attribute:: lsbfirst + + Least Significant Bit (LSB) first. + + .. attribute:: mode + + SPI mode as two bit pattern of Clock Polarity and Phase [CPOL|CPHA]; min-- 0b00 = 0, max-- 0b11 = 3. + + .. attribute:: msh + + Maximum speed in Hz. + + .. attribute:: threewire + + SI/SO signals are shared. + + .. method:: open(bus, device) + + Connects the object to the specified SPI device. `open(X, Y)` will open + `/dev/spidev-X.Y` + + :param int bus: bus number + :param str device: device number + + .. method:: close() + + Disconnects the object from the interface. + + .. method:: readbytes(len) + + Read the specified length of bytes from the SPI device. + + :param int len: length of bytes to read, 1024 maximum. + :returns: values read + :rtype: list[int] + + .. method:: writebytes(values) + + Write bytes to the SPI device. + + :param values: list of values to write, with a maximum length of 1024. + :type values: list[int] + + .. method:: xfer(values[,delay=0]) + + Perform an SPI transaction of values. Slave Select (SS or CS) will be + released and reactivated between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :param delay: delay in microseconds between blocks. + :returns: values transferred + :rtype: list[int] + + .. method:: xfer2(values) + + Perform an SPI transaction of values. Slave Select (SS or CS) will be + held active between blocks. + + :param values: list of values to transfer, with a maximum length of 1024. + :type values: list[int] + :returns: values transferred + :rtype: list[int] + diff --git a/docs/UART.rst b/docs/UART.rst new file mode 100644 index 0000000..3566803 --- /dev/null +++ b/docs/UART.rst @@ -0,0 +1,39 @@ +:mod:`UART` --- UART communications interface +--------------------------------------------- + +UART functionality of a BeagleBone using Python. Generally used to set up +and grant access to a given UART device, which will then be accessed by +other software or modules (e.g. `pyserial`):: + + sudo pip install pyserial + +Example:: + + import Adafruit_BBIO.UART as UART + import serial + + UART.setup("UART1") + + ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) + ser.close() + ser.open() + if ser.isOpen(): + print "Serial is open!" + ser.write("Hello World!") + ser.close() + +.. module:: Adafruit_BBIO.UART + +.. function:: setup_uart(channel) + + Set up and start the UART channel. This function will effectively export + the given UART so that it can be accessed by other software that controls + its serial lines. + + :param str channel: UART channel to set up. One of "UART1", "UART2", + "UART4" or "UART5" + +.. function:: cleanup() + + Cleans up the UART. + diff --git a/docs/index.rst b/docs/index.rst index 252ce6e..a663628 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,483 +3,22 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -.. toctree:: - :hidden: - :maxdepth: 2 - Adafruit Beaglebone IO Python API ================================= The Adafruit Beaglebone IO API enables access to the Beaglebone's GPIO, PWM, -ADC, UART and eQEP hardware modules from Python programs. - -:mod:`Encoder` --- Quadrature Encoder interface ------------------------------------------------ - -.. automodule:: Adafruit_BBIO.Encoder - :members: - -:mod:`PWM` --- Pulse Width Modulation interface ------------------------------------------------ - -Enables access to the Pulse Width Modulation (PWM) module, to easily and -accurately generate a PWM output signal of a given duty cycle and -frequency. - -.. note:: - - You need to be part of the ``pwm`` group of the OS running on the - Beaglebone to be able to run PWM code as a non-root user. The default - user created upon the Debian image installation should already be - part of the group. Otherwise, you can use - ``sudo usermod -a -G pwm userName`` to add ``userName`` to the group. - -.. module:: Adafruit_BBIO.PWM - -.. function:: start(channel, duty_cycle[, frequency=2000, polarity=0]) - - Set up and start the given PWM channel. - - :param str channel: PWM channel. It can be specified in the form - of of 'P8_10', or 'EHRPWM2A'. - :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - :param int frequency: PWM frequency, in Hz. It must be greater than 0. - :param int polarity: defines whether the value for ``duty_cycle`` affects the - rising edge or the falling edge of the waveform. Allowed values -- 0 - (rising edge, default) or 1 (falling edge). - -.. function:: stop(channel) - - Stop the given PWM channel. - - :param str channel: PWM channel. It can be specified in the form - of of 'P8_10', or 'EHRPWM2A'. - -.. function:: set_duty_cycle(channel, duty_cycle) - - Change the duty cycle of the given PWM channel. - - :note: You must have started the PWM channel with :func:`start()` - once, before changing the duty cycle. - - :param str channel: PWM channel. It can be specified in the form - of of 'P8_10', or 'EHRPWM2A'. - :param int duty_cycle: PWM duty cycle. It must have a value from 0 to 100. - -.. function:: set_frequency(channel, frequency) - - Change the frequency of the given PWM channel. - - :note: You must have started the PWM channel with :func:`start()` - once, before changing the frequency. - - :param str channel: PWM channel. It can be specified in the form - of of 'P8_10', or 'EHRPWM2A'. - :param int frequency: PWM frequency. It must be greater than 0. - -.. function:: cleanup() - - Clean up by resetting all GPIO channels that have been used by this - program to INPUT, with no pullup/pulldown and no event detection. - -:mod:`UART` --- UART communications interface ---------------------------------------------- - -UART functionality of a BeagleBone using Python. Generally used to set up -and grant access to a given UART device, which will then be accessed by -other software or modules (e.g. `pyserial`):: - - sudo pip install pyserial - -Example:: - - import Adafruit_BBIO.UART as UART - import serial - - UART.setup("UART1") - - ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) - ser.close() - ser.open() - if ser.isOpen(): - print "Serial is open!" - ser.write("Hello World!") - ser.close() - -.. module:: Adafruit_BBIO.UART - -.. function:: setup_uart(channel) - - Set up and start the UART channel. This function will effectively export - the given UART so that it can be accessed by other software that controls - its serial lines. - - :param str channel: UART channel to set up. One of "UART1", "UART2", - "UART4" or "UART5" - -.. function:: cleanup() - - Cleans up the UART. - -:mod:`ADC` --- A/D Converter input interface --------------------------------------------- - -This module enables reading analog input values from the analog to digital -converter (ADC) on the Beaglebone processor. - -Example:: - - import Adafruit_BBIO.ADC as ADC - - ADC.setup() - - # The read method returns normalized values from 0 to 1.0 - value = ADC.read("P9_40") - - # The read_raw returns non-normalized values - value = ADC.read_raw("P9_40") - -.. module:: Adafruit_BBIO.ADC - -.. function:: setup_adc() - - Setup and start the ADC hardware. - -.. function:: setup_read() - - Read the normalized 0-1.0 analog value for the channel. - -.. function:: setup_read_raw() - - Read the raw analog value for the channel. - -:mod:`SPI` --- Serial Peripheral Interface ------------------------------------------- - -This module defines an object type that allows Serial Peripheral Interface -(SPI) bus transactions on hosts running the Linux kernel. The host kernel -must have SPI support and SPI device interface support. - -Because the SPI device interface is opened R/W, users of this module -usually must have root permissions or be members of a group with granted -access rights. - -Pins used for SPI0 and SPI1 -+++++++++++++++++++++++++++ - -==== ===== ===== ===== ===== -PORT CS0 DO DI SCLK -==== ===== ===== ===== ===== -SPI0 P9_17 P9_21 P9_18 P9_22 -SPI1 P9_28 P9_29 P9_30 P9_31 -==== ===== ===== ===== ===== - -Example:: - - import Adafruit_BBIO.SPI as SPI - - from Adafruit_BBIO.SPI import SPI - # spi = SPI(bus, device) #/dev/spidev. - - # /dev/spidev0.0 - spi = SPI(1, 0) - print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() - - # /dev/spidev0.1 - spi = SPI(1, 1) - print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() - - # /dev/spidev1.0 - spi = SPI(2, 0) - print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() - - # /dev/spidev1.1 - spi = SPI(2, 1) - print(spi.xfer2([32, 11, 110, 22, 220])) - spi.close() - -.. module:: Adafruit_BBIO.SPI - -.. class:: SPI(bus, client) - - :param bus: bus number. - :param client: client device number. - :returns: a new SPI object, optionally connected to the specified SPI - device interface. - :rtype: :class:`SPI` - - .. attribute:: bpw - - Bits per word. - - .. attribute:: cshigh - - Chip Select (CS or Slave Select, SS) active high. - - .. attribute:: loop - - Loopback configuration. - - .. attribute:: lsbfirst - - Least Significant Bit (LSB) first. - - .. attribute:: mode - - SPI mode as two bit pattern of Clock Polarity and Phase [CPOL|CPHA]; min-- 0b00 = 0, max-- 0b11 = 3. - - .. attribute:: msh - - Maximum speed in Hz. - - .. attribute:: threewire - - SI/SO signals are shared. - - .. method:: open(bus, device) - - Connects the object to the specified SPI device. `open(X, Y)` will open - `/dev/spidev-X.Y` - - :param int bus: bus number - :param str device: device number - - .. method:: close() - - Disconnects the object from the interface. +ADC, UART, SPI and eQEP hardware modules from Python programs. - .. method:: readbytes(len) - - Read the specified length of bytes from the SPI device. - - :param int len: length of bytes to read, 1024 maximum. - :returns: values read - :rtype: list[int] - - .. method:: writebytes(values) - - Write bytes to the SPI device. - - :param values: list of values to write, with a maximum length of 1024. - :type values: list[int] - - .. method:: xfer(values[,delay=0]) - - Perform an SPI transaction of values. Slave Select (SS or CS) will be - released and reactivated between blocks. - - :param values: list of values to transfer, with a maximum length of 1024. - :type values: list[int] - :param delay: delay in microseconds between blocks. - :returns: values transferred - :rtype: list[int] - - .. method:: xfer2(values) - - Perform an SPI transaction of values. Slave Select (SS or CS) will be - held active between blocks. - - :param values: list of values to transfer, with a maximum length of 1024. - :type values: list[int] - :returns: values transferred - :rtype: list[int] - -:mod:`GPIO` --- General Purpose I/O interface ---------------------------------------------- - -This module provides access and control of pins set up as General Purpose -I/O (GPIO). - -.. note:: - - You need to be part of the ``gpio`` group of the OS running on the - Beaglebone to be able to run GPIO code as a non-root user. The default - user created upon the Debian image installation should already be - part of the group. Otherwise, you can use - ``sudo usermod -a -G gpio userName`` to add ``userName`` to the group. - -.. note:: - - When coding with this module, you will be using pin names for - better readability. As such, you can specify them in the header 8 or 9 - form (e.g. "P8_16") or in pin name form (e.g. "GPIO1_14"). - For easy reference, you can use the - `Beaglebone pin names table `_ - - -Example:: - - # Use the config-pin command line tool to set a pin's function to GPIO - # Then you can control it with the GPIO module from Python - config-pin P9_14 gpio - - import Adafruit_BBIO.GPIO as GPIO - - # Set up pins as inputs or outputs - GPIO.setup("P8_13", GPIO.IN) - GPIO.setup("P8_14", GPIO.OUT) - GPIO.setup("GPIO0_26", GPIO.OUT) # Alternative: use actual pin names - - # Write a logic high or logic low - GPIO.output("P8_14", GPIO.HIGH) # You can also write '1' instead - GPIO.output("P8_14", GPIO.LOW) # You can also write '0' instead - -.. module:: Adafruit_BBIO.GPIO - -.. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) - - Set up the given GPIO channel, its direction and (optional) pull/up down control - - :param str channel: GPIO channel to set up (e.g. "P8_16"). - :param int direction: GPIO channel direction (:data:`IN` or :data:`OUT`). - :param int pull_up_down: pull-up/pull-down resistor configuration - (:data:`PUD_OFF`, :data:`PUD_UP` or :data:`PUD_DOWN`). - :param int initial: initial value for an output channel (:data:`LOW`/:data:`HIGH`). - :param int delay: time in milliseconds to wait after exporting the GPIO pin. - -.. function:: cleanup() - - Clean up by resetting all GPIO channels that have been used by - the application to :data:`IN` with no pullup/pulldown and no event - detection. - - :note: It's recommended that you call this function upon exiting your - application. - -.. function:: output(channel, value) - - Set the given output channel to the given digital value. - - :param str channel: GPIO channel to output the value to (e.g. "P8_16"). - :param value: value to set the output to-- 0/1 or False/True - or :data:`LOW`/:data:`HIGH`. - :type value: int or bool - -.. function:: input(channel) - - Get the given input channel's digital value. - - :param str channel: GPIO channel to read the value from (e.g. "P8_16"). - :returns: Channel value–– 0 or 1. - :rtype: int - -.. function:: add_event_detect(channel, edge[, callback=None, bouncetime=0]) - - Enable edge detection events for the given GPIO channel. - - :param str channel: GPIO channel to detect events from (e.g. "P8_16"). - :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` - or :data:`BOTH` - :param func callback: a function to call once the event has been detected. - :param int bouncetime: switch bounce timeout in ms for the callback. - -.. function:: remove_event_detect(channel) - - Remove edge detection for the given GPIO channel. - - :param str channel: GPIO channel to remove event detection - from (e.g. "P8_16"). - -.. function:: event_detected(channel) - - Checks if an edge event has occured on a given GPIO. - - :note: You need to enable edge detection using :func:`add_event_detect()` first. - - :param str channel: GPIO channel to check for event detection - for (e.g. "P8_16"). - :returns: True if an edge has occured on a given GPIO, False otherwise - :rtype: bool - -.. function:: add_event_callback(channel, callback[, bouncetime=0]) - - Add a callback for an event already defined using :func:`add_event_detect()` - - :param str channel: GPIO channel to add a callback to (e.g. "P8_16"). - :param func callback: a function to call once the event has been detected. - :param int bouncetime: switch bounce timeout in ms for the callback. - -.. function:: wait_for_edge(channel, edge[, timeout=-1]) - - Wait for an edge on the given channel. - - :param str channel: GPIO channel to wait on (e.g. "P8_16"). - :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` - or :data:`BOTH` - :param int timeout: time to wait for an edge, in milliseconds. - -1 will wait forever. - -.. function:: gpio_function(channel) - - Return the current GPIO function - (:data:`IN`, :data:`IN`, :data:`ALT0`) of the given pin. - - :warning: Currently only returning the direction of the - pin (input or output) is supported. - - :param str channel: GPIO pin to query the status of. - :returns: 0 if :data:`IN`, 1 if :data:`OUT` - :rtype: int - -.. function:: setwarnings(gpio_warnings) - - Enable or disable GPIO warning messages. - - :warning: Currently enabling or disabling warnings - has no effect. - - :param int gpio_warnings: 0–– disable warnings; 1–– enable warnings - -.. attribute:: ALT0 - - Pin mode-- alternate function 0. - -.. attribute:: BOTH - - Edge detection-- detect both edges. - -.. attribute:: FALLING - - Edge detection-- detect falling edge. - -.. attribute:: HIGH - - Pin status-- logic low. - -.. attribute:: IN - - Pin mode-- input. - -.. attribute:: LOW - - Pin status-- logic low. - -.. attribute:: OUT - - Pin mode-- output. - -.. attribute:: PUD_OFF - - Pull-up/pull-down resistor type-- no pull-up/pull-down. - -.. attribute:: PUD_DOWN - - Pull-up/pull-down resistor type-- pull-down. - -.. attribute:: PUD_UP - - Pull-up/pull-down resistor type-- pull-up. - -.. attribute:: RISING - - Edge detection-- detect rising edge. - -.. attribute:: VERSION - - GPIO module version. Currently unused. +.. toctree:: + :maxdepth: 4 + :caption: Contents + + ADC + Encoder + GPIO + PWM + SPI + UART Indices and tables ================== From ee6bd69a9f6197d8e6b17e46fc9ed67979ec3e6e Mon Sep 17 00:00:00 2001 From: David Planella Date: Mon, 4 Dec 2017 13:57:24 +0100 Subject: [PATCH 089/157] Improvements to the API docs output config --- docs/conf.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index c002fc2..6dfd6ad 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -101,7 +101,8 @@ # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -# Use the readthedocs theme if the documentation is being built there +# Use the readthedocs theme if the documentation is being built there, or +# use a Sphinx theme if the documentation is being built locally on_rtd = os.environ.get('READTHEDOCS') == 'True' if on_rtd: html_theme = 'default' @@ -116,6 +117,17 @@ 'localtoc.html' ] } + # If you want to use the same theme as readthedocs, uncomment the lines + # below and install the readthedocs theme (pip install sphinx_rtd_theme) + # before doing a new build: + #html_theme = 'sphinx_rtd_theme' + #html_theme_options = { + # 'collapse_navigation': False, + #} + +# Do not show the "View source" link that shows the .rst files +html_copy_source = False +html_show_sourcelink = False # -- Options for HTMLHelp output ------------------------------------------ From 2978a08fcb268409bc7f6767b54faeebd0362a3d Mon Sep 17 00:00:00 2001 From: David Planella Date: Mon, 4 Dec 2017 14:25:02 +0100 Subject: [PATCH 090/157] Update docs generation description to reflect new separate modules --- docs/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index e2b2188..828f2c3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,14 +1,14 @@ # Generating API documentation -This folder contains the required files to automatically generate the Adafruit Beaglebone I/O Python API documentation, partly from the code docstrings and partly from a reStructuredText-formatted `index.rst` file. +This folder contains the required files to automatically generate the Adafruit Beaglebone I/O Python API documentation, partly from the code docstrings and partly from files in reStructuredText format. ``` ├── conf.py <- Sphinx configuration file -├── index.rst <- Documentation will be generated based on this +├── index.rst <- Documentation will be generated based on the master index └── Makefile <- Auxiliary Makefile to build documentation ``` -The tools used are [Sphinx](http://www.sphinx-doc.org) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io), which automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches. Generally Readthedocs will be set up to track stable release branches and master. +The tools used are [Sphinx](http://www.sphinx-doc.org) to extract the documentation and publish it in HTML format for online viewing, in combination with [Readthedocs](http://readthedocs.io). Readthedocs automatically executes Sphinx via webhooks triggered by Github commits, and publishes the resulting docs for all tracked branches or tags. Generally Readthedocs will be set up to track stable release tags and the master branch. ## Building the documentation @@ -36,7 +36,7 @@ Notes: ## Readthedocs maintenance -At every release that includes documenation (most probably 1.0.10 will be the first one), the release's branch needs to be selected in the web UI and marked as active. +At every release that includes documenation (most probably 1.0.10 will be the first one), the release's branch or tag needs to be selected in the web UI and marked as active. After this, documentation will automatically be generated and published for that release. It will be available at the same URL as the main documentation, and a link with the version number will be shown, where it can be accessed from. @@ -50,11 +50,11 @@ Ideally, all API documentation would be written in the source files as Python do However, most of the code is written as C extensions. While they do provide docstrings once they are built, Sphinx does not natively support extracting them. There is [a workaround](https://stackoverflow.com/a/30110104/9022675) to do this, but it involves first building the extensions, installing them and hardcoding a path. While it might work for locally-built documentation, it's unlikely that readthedocs support this option. -For the sake of keeping things simple and with less maintenance, the approach of documenting the C-generated API in the `index.rst` file has been taken. +For the sake of keeping things simple and with less maintenance, the approach of documenting the C-generated API in separate `.rst` files (one for each Python module) has been taken. -This has the advantage of having a definition of the API in one place, but it also poses the disadvantage of some duplication, as the C modules do define some docstrings for their objects. Then again, the API itself has hardly changed in the last few years, and the Beaglebone is a mature platform, so it's unlikely that this will pose a significant maintenance overhead. +This has the advantage of having a definition of the API in one place, but it also poses the disadvantage of some duplication, as the C modules do define some docstrings for their objects. Then again, the API itself has hardly changed in the last few years, and the Beaglebone is a mature platform, so it's unlikely that this will add a significant maintenance overhead. -- The documentation in the `index.rst` file is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), extended with Sphinx markup for defining the objects. +- The documentation in the `.rst` files is written in [reStructuredText](http://docutils.sourceforge.net/rst.html), extended with Sphinx markup for defining the objects. - The documentation in Python modules follows the Google readable docstring markup, which also builds upon reStructuredText and is fully supported by Sphinx. ## Further reference From 14f1f79385e68342c30cf77898a0f0fd4a7a7c07 Mon Sep 17 00:00:00 2001 From: David Planella Date: Tue, 5 Dec 2017 08:44:52 +0100 Subject: [PATCH 091/157] Updated ADC API docs --- docs/ADC.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/ADC.rst b/docs/ADC.rst index ae90254..4aa14be 100644 --- a/docs/ADC.rst +++ b/docs/ADC.rst @@ -13,7 +13,7 @@ Example:: # The read method returns normalized values from 0 to 1.0 value = ADC.read("P9_40") - # The read_raw returns non-normalized values + # The read_raw returns non-normalized values from 0 to 4095 value = ADC.read_raw("P9_40") .. module:: Adafruit_BBIO.ADC @@ -24,13 +24,22 @@ Example:: .. function:: setup_read(channel) + Read the normalized analog value for the channel. + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + :returns: normalized value reading from 0.0 to 1.0 + :rtype: float - Read the normalized 0-1.0 analog value for the channel. .. function:: setup_read_raw(channel) + Read the raw analog value for the channel. + + :note: Kernels older than 4.1.x returned a raw value range based on + the reference voltage of 1.8 V–– from 0 to 1800. + :param str channel: GPIO channel to read the value from (e.g. "P8_16"). + :returns: raw value reading from 0 to 4095 (12 bits). + :rtype: float - Read the raw analog value for the channel. From 6f3589a7c5d6872dfae84b8bd1152200b2e01651 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 25 Jan 2018 22:49:09 -0600 Subject: [PATCH 092/157] create release 1.0.10 Features: * automatically set pin modes for UART (PR #158) * Encoder: README.md: added note about eqep group change (PR #214) * deprecate out of date Adafruit_I2C.py (PR #215) * Add Encoder module info to main README.md (PR #217) * Add automatic API documentation generation (PR #219) * Separate API docs into modules (PR #221) shortlog: * David Planella (46): * Encoder: README.md: added note about eqep group change * Add Encoder module info to main README.md * Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. * Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails * Use the default readthedocs theme * Use readthedocs theme if building docs there, remove redundand search link * Readthedocs theme tweaks * Removed redundant TOC, added global description * Added UART documentation * Added documentation badge * Added ADC API docs, fixed UART module definition * API docs: added SPI module * Added SPI module attribute docs * Added Python badges to README file * Added SPI pins table and first shot at GPIO module. Functions still need to be documented * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs * Documented the API docs build process * Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. * Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails * Use the default readthedocs theme * Use readthedocs theme if building docs there, remove redundand search link * Readthedocs theme tweaks * Removed redundant TOC, added global description * Added UART documentation * Added documentation badge * Added ADC API docs, fixed UART module definition * API docs: added SPI module * Added SPI module attribute docs * Added Python badges to README file * Added SPI pins table and first shot at GPIO module. Functions still need to be documented * Documented the API docs build process * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs * Update README.md * Added some more API doc content * Sync from upstream master * Minor documentation and configuration improvements * Finished documenting GPIO * rST fixes * Update README.md * Minor API doc improvements * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs * Generate the API documentation from a master index and a separate file for each module * Sync from upstream master * Improvements to the API docs output config * Update docs generation description to reflect new separate modules * Updated ADC API docs * Drew Fustini (10): * use set_pin_mode() to set uart pinmux (#158) * Add SPI instructions to README (#158) * Update README.md * Fix spidev path mismatch (#216) * Merge pull request #217 from dplanella/patch-2 * Merge pull request #214 from dplanella/patch-1 * Deprecate Adafruit_BBIO.I2C in favor of Adafruit_GPIO.I2C (#215) * Merge pull request #219 from dplanella/readthedocs * relocate doc dir to avoid confusion (#218) * Merge pull request #221 from dplanella/readthedocs Signed-off-by: Drew Fustini --- CHANGELOG.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cd59eb..565b357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,75 @@ +1.0.10 +---- +**features** +* automatically set pin modes for UART (PR #158) +* Encoder: README.md: added note about eqep group change (PR #214) +* deprecate out of date Adafruit_I2C.py (PR #215) +* Add Encoder module info to main README.md (PR #217) +* Add automatic API documentation generation (PR #219) +* Separate API docs into modules (PR #221) + +**shortlog** +* David Planella (46): + * Encoder: README.md: added note about eqep group change + * Add Encoder module info to main README.md + * Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. + * Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails + * Use the default readthedocs theme + * Use readthedocs theme if building docs there, remove redundand search link + * Readthedocs theme tweaks + * Removed redundant TOC, added global description + * Added UART documentation + * Added documentation badge + * Added ADC API docs, fixed UART module definition + * API docs: added SPI module + * Added SPI module attribute docs + * Added Python badges to README file + * Added SPI pins table and first shot at GPIO module. Functions still need to be documented + * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs + * Documented the API docs build process + * Added docstrings using Google syntax and Sphinx support to generate the API documentation for the Encoder and PWM modules for now. + * Made kernel version check to happen only if running on a beaglebone. The readthedocs builders that import the Encoder module have an old 3.3 kernel and the autodoc build fails + * Use the default readthedocs theme + * Use readthedocs theme if building docs there, remove redundand search link + * Readthedocs theme tweaks + * Removed redundant TOC, added global description + * Added UART documentation + * Added documentation badge + * Added ADC API docs, fixed UART module definition + * API docs: added SPI module + * Added SPI module attribute docs + * Added Python badges to README file + * Added SPI pins table and first shot at GPIO module. Functions still need to be documented + * Documented the API docs build process + * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs + * Update README.md + * Added some more API doc content + * Sync from upstream master + * Minor documentation and configuration improvements + * Finished documenting GPIO + * rST fixes + * Update README.md + * Minor API doc improvements + * Merge branch 'readthedocs' of https://github.com/dplanella/adafruit-beaglebone-io-python into readthedocs + * Generate the API documentation from a master index and a separate file for each module + * Sync from upstream master + * Improvements to the API docs output config + * Update docs generation description to reflect new separate modules + * Updated ADC API docs + +* Drew Fustini (10): + * use set_pin_mode() to set uart pinmux (#158) + * Add SPI instructions to README (#158) + * Update README.md + * Fix spidev path mismatch (#216) + * Merge pull request #217 from dplanella/patch-2 + * Merge pull request #214 from dplanella/patch-1 + * Deprecate Adafruit_BBIO.I2C in favor of Adafruit_GPIO.I2C (#215) + * Merge pull request #219 from dplanella/readthedocs + * relocate doc dir to avoid confusion (#218) + * Merge pull request #221 from dplanella/readthedocs + + 1.0.9 ---- **Features:** diff --git a/setup.py b/setup.py index e42f907..ec60ac7 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.0.9', + version = '1.0.10', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From 9fd1073982770ba5c9ce4b7ce3a633a695b4faf4 Mon Sep 17 00:00:00 2001 From: zserg Date: Sun, 18 Feb 2018 00:02:50 +0000 Subject: [PATCH 093/157] * Fixed SEGFAULT when calling remove_event_detect() inside python callback function. --- source/event_gpio.c | 6 +++-- source/py_gpio.c | 59 ++++++++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/source/event_gpio.c b/source/event_gpio.c index 22f3658..d5e7396 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -522,9 +522,11 @@ void run_callbacks(unsigned int gpio) struct callback *cb = callbacks; while (cb != NULL) { - if (cb->gpio == gpio) + if (cb->gpio == gpio) cb->func(cb->gpio); - cb = cb->next; + // Current callback pointer might have changed _only_ if linked list structure has been altered from within the callback function, which should happen _only_ in remove_event_detect() call + if (cb != NULL) + cb = cb->next; } } diff --git a/source/py_gpio.c b/source/py_gpio.c index 8682b80..a954652 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -218,6 +218,7 @@ static void run_py_callbacks(unsigned int gpio) PyObject *result; PyGILState_STATE gstate; struct py_callback *cb = py_callbacks; + unsigned char cookie[2] = {0}; struct timeval tv_timenow; unsigned long long timenow; @@ -225,28 +226,40 @@ static void run_py_callbacks(unsigned int gpio) { if (cb->gpio == gpio) { - gettimeofday(&tv_timenow, NULL); - timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; - if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) { - - // save lastcall before calling func to prevent reentrant bounce + //Store memory contents of the first byte of current callback structure as a "magic cookie" + memcpy(&cookie[0], cb, 1); + gettimeofday(&tv_timenow, NULL); + timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; + if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) { + + // save lastcall before calling func to prevent reentrant bounce + cb->lastcall = timenow; + + // run callback + gstate = PyGILState_Ensure(); + result = PyObject_CallFunction(cb->py_cb, "s", cb->channel); + //Check the first byte of callback structure after executing callback function body + memcpy(&cookie[1], cb, 1); + + if (result == NULL && PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + Py_XDECREF(result); + PyGILState_Release(gstate); + } + + // Current callback pointer might have changed _only_ if linked list structure has been altered from within the callback function, which should happen _only_ in remove_event_detect() call + // If that happened, cb* pointer will be now addressing different memory location with different data. + if (cookie[0] != cookie[1]) break; + + if (cb != NULL) cb->lastcall = timenow; - - // run callback - gstate = PyGILState_Ensure(); - result = PyObject_CallFunction(cb->py_cb, "s", cb->channel); - - if (result == NULL && PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - Py_XDECREF(result); - PyGILState_Release(gstate); - } - cb->lastcall = timenow; } - cb = cb->next; + // If callback just executed was the only one in chain and it was removed inside cb->py_cb() body, cb->next will be pointing to NULL now + if (cb != NULL) + cb = cb->next; } } @@ -411,7 +424,9 @@ static PyObject *py_remove_event_detect(__attribute__ ((unused)) PyObject *self, temp = cb; cb = cb->next; free(temp); - } else { + } + else + { prev = cb; cb = cb->next; } @@ -582,7 +597,7 @@ PyMODINIT_FUNC initGPIO(void) define_constants(module); - initlog(LOG_NOTICE, NULL, BBIO_LOG_OPTION); + initlog(LOG_INFO, NULL, BBIO_LOG_OPTION); if (!PyEval_ThreadsInitialized()) PyEval_InitThreads(); From e9c70f7d23392be3843b28d600d49a01d14ac2b5 Mon Sep 17 00:00:00 2001 From: zserg Date: Sun, 18 Feb 2018 00:02:50 +0000 Subject: [PATCH 094/157] * Fixed SEGFAULT when calling remove_event_detect() inside python callback function. --- source/event_gpio.c | 6 +++-- source/py_gpio.c | 57 ++++++++++++++++++++++++++++----------------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/source/event_gpio.c b/source/event_gpio.c index 3dc8714..ee1e2bb 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -562,9 +562,11 @@ void run_callbacks(unsigned int gpio) struct callback *cb = callbacks; while (cb != NULL) { - if (cb->gpio == gpio) + if (cb->gpio == gpio) cb->func(cb->gpio); - cb = cb->next; + // Current callback pointer might have changed _only_ if linked list structure has been altered from within the callback function, which should happen _only_ in remove_event_detect() call + if (cb != NULL) + cb = cb->next; } } diff --git a/source/py_gpio.c b/source/py_gpio.c index 385a060..a954652 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -218,6 +218,7 @@ static void run_py_callbacks(unsigned int gpio) PyObject *result; PyGILState_STATE gstate; struct py_callback *cb = py_callbacks; + unsigned char cookie[2] = {0}; struct timeval tv_timenow; unsigned long long timenow; @@ -225,28 +226,40 @@ static void run_py_callbacks(unsigned int gpio) { if (cb->gpio == gpio) { - gettimeofday(&tv_timenow, NULL); - timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; - if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) { - - // save lastcall before calling func to prevent reentrant bounce + //Store memory contents of the first byte of current callback structure as a "magic cookie" + memcpy(&cookie[0], cb, 1); + gettimeofday(&tv_timenow, NULL); + timenow = tv_timenow.tv_sec*1E6 + tv_timenow.tv_usec; + if (cb->bouncetime == 0 || timenow - cb->lastcall > cb->bouncetime*1000 || cb->lastcall == 0 || cb->lastcall > timenow) { + + // save lastcall before calling func to prevent reentrant bounce + cb->lastcall = timenow; + + // run callback + gstate = PyGILState_Ensure(); + result = PyObject_CallFunction(cb->py_cb, "s", cb->channel); + //Check the first byte of callback structure after executing callback function body + memcpy(&cookie[1], cb, 1); + + if (result == NULL && PyErr_Occurred()) + { + PyErr_Print(); + PyErr_Clear(); + } + Py_XDECREF(result); + PyGILState_Release(gstate); + } + + // Current callback pointer might have changed _only_ if linked list structure has been altered from within the callback function, which should happen _only_ in remove_event_detect() call + // If that happened, cb* pointer will be now addressing different memory location with different data. + if (cookie[0] != cookie[1]) break; + + if (cb != NULL) cb->lastcall = timenow; - - // run callback - gstate = PyGILState_Ensure(); - result = PyObject_CallFunction(cb->py_cb, "s", cb->channel); - - if (result == NULL && PyErr_Occurred()) - { - PyErr_Print(); - PyErr_Clear(); - } - Py_XDECREF(result); - PyGILState_Release(gstate); - } - cb->lastcall = timenow; } - cb = cb->next; + // If callback just executed was the only one in chain and it was removed inside cb->py_cb() body, cb->next will be pointing to NULL now + if (cb != NULL) + cb = cb->next; } } @@ -411,7 +424,9 @@ static PyObject *py_remove_event_detect(__attribute__ ((unused)) PyObject *self, temp = cb; cb = cb->next; free(temp); - } else { + } + else + { prev = cb; cb = cb->next; } From e061d1358e189115d3a7fd907470e6b4783c8733 Mon Sep 17 00:00:00 2001 From: Aaron Marburg Date: Thu, 12 Apr 2018 22:46:49 +0000 Subject: [PATCH 095/157] Added usleep after successfully enabling PWM via udev. --- source/c_pwm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/c_pwm.c b/source/c_pwm.c index e6bc7b0..f983592 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -457,6 +457,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri } } else { strncpy(pwm_path, pwm_path_udev, sizeof(pwm_path_udev)); + usleep(100*1000); } } } From b054cc083e69b3d825915bd97f24619f6565d00b Mon Sep 17 00:00:00 2001 From: zserg Date: Wed, 30 May 2018 16:47:47 +0100 Subject: [PATCH 096/157] * Fixed SEGFAULT in event_gpio,c run_callbacks() * Added more elaborate epoll() error logging --- source/event_gpio.c | 38 +++++++++++++++++++++++++++++++------- source/py_gpio.c | 6 +++--- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/source/event_gpio.c b/source/event_gpio.c index ee1e2bb..d83cff5 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -560,11 +560,22 @@ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)) void run_callbacks(unsigned int gpio) { struct callback *cb = callbacks; + //Memory cookie + unsigned char cookie[2] = {0}; while (cb != NULL) { + //Store memory contents of the first byte of current callback structure as a "magic cookie" + memcpy(&cookie[0], cb, 1); if (cb->gpio == gpio) cb->func(cb->gpio); + + //Check the first byte of callback structure after executing callback function body + memcpy(&cookie[1], cb, 1); + // Current callback pointer might have changed _only_ if linked list structure has been altered from within the callback function, which should happen _only_ in remove_event_detect() call + // If that happened, cb* pointer will be now addressing different memory location with different data. + if (cookie[0] != cookie[1]) break; + if (cb != NULL) cb = cb->next; } @@ -702,8 +713,8 @@ int gpio_event_remove(unsigned int gpio) int add_edge_detect(unsigned int gpio, unsigned int edge) // return values: // 0 - Success -// 1 - Edge detection already added -// 2 - Other error +// -1 - Even detection already enabled for that GPIO +// Other error codes are system-wide { int fd = fd_lookup(gpio); pthread_t threads; @@ -712,7 +723,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) // check to see if this gpio has been added already if (gpio_event_add(gpio) != 0) - return 1; + return -1; // export /sys/class/gpio interface gpio_export(gpio); @@ -722,24 +733,37 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) if (!fd) { if ((fd = open_value_file(gpio)) == -1) - return 2; + { + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: open_value_file error %i-%s", errno, strerror(errno)); + return errno; + } } // create epfd if not already open if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) - return 2; + { + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: epoll_create error %i-%s", errno, strerror(errno)); + return errno; + } + // add to epoll fd ev.events = EPOLLIN | EPOLLET | EPOLLPRI; ev.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) - return 2; + { + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: epoll_ctl error %i-%s", errno, strerror(errno)); + return errno; + } // start poll thread if it is not already running if (!thread_running) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) - return 2; + { + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: pthread_create error %i-%s", errno, strerror(errno)); + return errno; + } } return 0; diff --git a/source/py_gpio.c b/source/py_gpio.c index a954652..1f37dda 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -377,12 +377,12 @@ static PyObject *py_add_event_detect(__attribute__ ((unused)) PyObject *self, Py if ((result = add_edge_detect(gpio, edge)) != 0) // starts a thread { - if (result == 1) + if (result == -1) { - PyErr_SetString(PyExc_RuntimeError, "Edge detection already enabled for this GPIO channel"); + PyErr_SetString(PyExc_KeyError, "Edge detection already enabled for this GPIO channel"); return NULL; } else { - PyErr_SetString(PyExc_RuntimeError, "Failed to add edge detection"); + PyErr_SetFromErrno(PyExc_RuntimeError); return NULL; } } From 3265d156e4858250ba08d6861277513d337ec733 Mon Sep 17 00:00:00 2001 From: zserg Date: Thu, 31 May 2018 18:10:26 +0100 Subject: [PATCH 097/157] * Minor style fixes * Added comments * Added debug logging * Line 724 - now flag is properly reset upon removal of event detection from GPIO pin --- source/event_gpio.c | 83 +++++++++++++++++++++++++++++---------------- source/event_gpio.h | 1 + 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/source/event_gpio.c b/source/event_gpio.c index d83cff5..c63fdbd 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -80,7 +80,7 @@ BBIO_err gpio_export(unsigned int gpio) // already exported by us? if (exported_gpios[gpio] != GPIO_NOT_EXPORTED) { - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export: %u already exported", gpio); + syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export(): %u already exported before", gpio); ret = BBIO_OK; goto exit; } @@ -91,7 +91,7 @@ BBIO_err gpio_export(unsigned int gpio) if (access(gpio_path, R_OK|W_OK|X_OK) != -1) { exported_gpios[gpio] = GPIO_ALREADY_EXPORTED; - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export: %u already exported", gpio); + syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export(): %u already exported externally", gpio); ret = BBIO_OK; goto exit; } @@ -99,7 +99,7 @@ BBIO_err gpio_export(unsigned int gpio) const char gpio_export[] = "/sys/class/gpio/export"; if ((fd = open(gpio_export, O_WRONLY)) < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_export: %u couldn't open \"%s\": %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_export(): %u couldn't open \"%s\": %i-%s", gpio, gpio_export, errno, strerror(errno)); ret = BBIO_SYSFS; goto exit; @@ -116,19 +116,19 @@ BBIO_err gpio_export(unsigned int gpio) // add to list exported_gpios[gpio] = GPIO_EXPORTED; - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export: %u OK", gpio); + syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_export(): %u OK", gpio); ret = BBIO_OK; exit: if(fd && (ret = close(fd))) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_export: %u couldn't close \"%s\": %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_export(): %u couldn't close \"%s\": %i-%s", gpio, gpio_export, errno, strerror(errno)); ret = BBIO_SYSFS; } usleep(200000); // Hack to wait for newly exported pins to get correct ownership return ret; } - +// Closes fd corresponding to specified GPIO pin and removes it from fdx list void close_value_fd(unsigned int gpio) { struct fdx *f = fd_list; @@ -140,10 +140,12 @@ void close_value_fd(unsigned int gpio) if (f->gpio == gpio) { close(f->fd); + syslog(LOG_DEBUG, "Adafruit_BBIO: close_value_fd(): closed file descriptor %d", f->fd); if (prev == NULL) fd_list = f->next; else prev->next = f->next; + syslog(LOG_DEBUG, "Adafruit_BBIO: close_value_fd(): removing file descriptor %d for pin %u from opened descriptors list",f->fd, f->gpio); temp = f; f = f->next; free(temp); @@ -153,7 +155,7 @@ void close_value_fd(unsigned int gpio) } } } - +// Returns file descriptor corresponding to specified GPIO pin int fd_lookup(unsigned int gpio) { struct fdx *f = fd_list; @@ -165,7 +167,7 @@ int fd_lookup(unsigned int gpio) } return 0; } - +// Adds GPIO file descriptor to fdx list int add_fd_list(unsigned int gpio, int fd) { struct fdx *new_fd; @@ -184,6 +186,7 @@ int add_fd_list(unsigned int gpio, int fd) new_fd->next = fd_list; } fd_list = new_fd; + syslog(LOG_DEBUG, "Adafruit_BBIO: add_fd_list(): registered file descriptor %d for pin %u.",fd, gpio); return 0; } @@ -242,6 +245,7 @@ int open_value_file(unsigned int gpio) gpio, filename, errno, strerror(errno)); return -1; } + syslog(LOG_DEBUG, "Adafruit_BBIO: open_value_file(): opened file descriptor %d for pin %u.",fd, gpio); add_fd_list(gpio, fd); return fd; } @@ -251,15 +255,16 @@ BBIO_err gpio_unexport(unsigned int gpio) int fd, len; char str_gpio[10]; + //If gpio is not exported by us - no need to do anything if (exported_gpios[gpio] != GPIO_EXPORTED) return 0; - + //close gpio pin file descriptor close_value_fd(gpio); #define GPIO_UNEXPORT "/sys/class/gpio/unexport" if ((fd = open(GPIO_UNEXPORT, O_WRONLY)) < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_unexport: %u couldn't open '"GPIO_UNEXPORT"': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_unexport(): %u couldn't open '"GPIO_UNEXPORT"': %i-%s", gpio, errno, strerror(errno)); return BBIO_SYSFS; } @@ -268,7 +273,7 @@ BBIO_err gpio_unexport(unsigned int gpio) int ret = write(fd, str_gpio, len); close(fd); if (ret < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_unexport: %u couldn't write '"GPIO_UNEXPORT"': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_unexport(): %u couldn't write '"GPIO_UNEXPORT"': %i-%s", gpio, errno, strerror(errno)); return BBIO_SYSFS; } @@ -276,7 +281,7 @@ BBIO_err gpio_unexport(unsigned int gpio) // remove from list exported_gpios[gpio] = GPIO_NOT_EXPORTED; - syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_unexport: %u OK", gpio); + syslog(LOG_DEBUG, "Adafruit_BBIO: gpio_unexport(): %u OK", gpio); return BBIO_OK; } @@ -308,7 +313,7 @@ BBIO_err gpio_set_direction(unsigned int gpio, unsigned int in_flag) snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); if ((fd = open(filename, O_WRONLY)) < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_direction: %u couldn't open '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_direction(): %u couldn't open '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -322,7 +327,7 @@ BBIO_err gpio_set_direction(unsigned int gpio, unsigned int in_flag) int ret = write(fd, direction, strlen(direction)); close(fd); if (ret < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_direction: %u couldn't write '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_direction(): %u couldn't write '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -339,7 +344,7 @@ BBIO_err gpio_get_direction(unsigned int gpio, unsigned int *value) snprintf(filename, sizeof(filename), "/sys/class/gpio/gpio%d/direction", gpio); if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_get_direction: %u couldn't open '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_get_direction(): %u couldn't open '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -348,7 +353,7 @@ BBIO_err gpio_get_direction(unsigned int gpio, unsigned int *value) int ret = read(fd, &direction, sizeof(direction) - 1); close(fd); if (ret < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_get_direction: %u couldn't read '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_get_direction(): %u couldn't read '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -438,7 +443,7 @@ BBIO_err gpio_set_value(unsigned int gpio, unsigned int value) fd = open(filename, O_WRONLY); if (fd < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value: %u couldn't open '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value(): %u couldn't open '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -452,7 +457,7 @@ BBIO_err gpio_set_value(unsigned int gpio, unsigned int value) int ret = write(fd, vstr, strlen(vstr)); close(fd); if (ret < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value: %u couldn't write '%s': %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value(): %u couldn't write '%s': %i-%s", gpio, filename, errno, strerror(errno)); return BBIO_SYSFS; } @@ -469,7 +474,7 @@ BBIO_err gpio_get_value(unsigned int gpio, unsigned int *value) if (!fd) { if ((fd = open_value_file(gpio)) == -1) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value: %u couldn't open value file: %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value(): %u couldn't open value file: %i-%s", gpio, errno, strerror(errno)); return BBIO_SYSFS; } @@ -478,7 +483,7 @@ BBIO_err gpio_get_value(unsigned int gpio, unsigned int *value) lseek(fd, 0, SEEK_SET); int ret = read(fd, &ch, sizeof(ch)); if (ret < 0) { - syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value: %u couldn't read value file: %i-%s", + syslog(LOG_ERR, "Adafruit_BBIO: gpio_set_value(): %u couldn't read value file: %i-%s", gpio, errno, strerror(errno)); return BBIO_SYSFS; } @@ -511,7 +516,7 @@ int gpio_set_edge(unsigned int gpio, unsigned int edge) return 0; } - +//Returns gpio number corresponding to fd file descriptor unsigned int gpio_lookup(int fd) { struct fdx *f = fd_list; @@ -554,6 +559,7 @@ int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)) cb = cb->next; cb->next = new_cb; } + syslog(LOG_DEBUG, "Adafruit_BBIO: add_edge_callback(): added callback to %p for pin %u", new_cb->func, gpio); return 0; } @@ -566,6 +572,7 @@ void run_callbacks(unsigned int gpio) { //Store memory contents of the first byte of current callback structure as a "magic cookie" memcpy(&cookie[0], cb, 1); + syslog(LOG_DEBUG, "Adafruit_BBIO: run_callbacks(): running callback %p for pin %u", cb->func, gpio); if (cb->gpio == gpio) cb->func(cb->gpio); @@ -591,6 +598,7 @@ void remove_callbacks(unsigned int gpio) { if (cb->gpio == gpio) { + syslog(LOG_DEBUG, "Adafruit_BBIO: remove_callbacks(): removing callback to %p for pin %u", cb->func, cb->gpio); if (prev == NULL) callbacks = cb->next; else @@ -604,7 +612,7 @@ void remove_callbacks(unsigned int gpio) } } } - +// Resets flag for the corresponding gpio void set_initial_false(unsigned int gpio) { struct fdx *f = fd_list; @@ -616,7 +624,7 @@ void set_initial_false(unsigned int gpio) f = f->next; } } - +// Checks if flag is set for the corresponding gpio int gpio_initial(unsigned int gpio) { struct fdx *f = fd_list; @@ -640,28 +648,38 @@ void *poll_thread(__attribute__ ((unused)) void *threadarg) thread_running = 1; while (thread_running) { + // epoll_wait() returns -1 on error/timeout if ((n = epoll_wait(epfd, &events, 1, -1)) == -1) { thread_running = 0; + syslog(LOG_ERR, "Adafruit_BBIO: poll_thread(): exiting due to error/timeout returned by epoll_wait()"); pthread_exit(NULL); } + // otherwise it returns number of file descriptors ready if (n > 0) { + // Set read/write offset to the beginning of the file lseek(events.data.fd, 0, SEEK_SET); + // Try to check if there's new data available on fd by reading from it, i.e. no error ocurred if (read(events.data.fd, &buf, 1) != 1) { thread_running = 0; + syslog(LOG_ERR, "Adafruit_BBIO: poll_thread(): exiting due to no data available to read"); pthread_exit(NULL); } + // Find out gpio number corresponding to fd on which event has happened gpio = gpio_lookup(events.data.fd); if (gpio_initial(gpio)) { // ignore first epoll trigger + syslog(LOG_DEBUG, "Adafruit_BBIO: poll_thread(): discarding first epoll() event for pin %u",gpio); set_initial_false(gpio); } else { event_occurred[gpio] = 1; + syslog(LOG_DEBUG, "Adafruit_BBIO: poll_thread(): running callbacks for pin %u",gpio); run_callbacks(gpio); } } } thread_running = 0; + syslog(LOG_DEBUG, "Adafruit_BBIO: poll_thread(): normal exit"); pthread_exit(NULL); } @@ -703,6 +721,7 @@ int gpio_event_remove(unsigned int gpio) if (f->gpio == gpio) { f->is_evented = 0; + f->initial = 1; return 0; } f = f->next; @@ -721,7 +740,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) struct epoll_event ev; long t = 0; - // check to see if this gpio has been added already + // check to see if this gpio has been added already to the list of gpios with event detection enabled if (gpio_event_add(gpio) != 0) return -1; @@ -734,7 +753,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) { if ((fd = open_value_file(gpio)) == -1) { - syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: open_value_file error %i-%s", errno, strerror(errno)); + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect(): open_value_file() error %i-%s", errno, strerror(errno)); return errno; } } @@ -742,7 +761,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) // create epfd if not already open if ((epfd == -1) && ((epfd = epoll_create(1)) == -1)) { - syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: epoll_create error %i-%s", errno, strerror(errno)); + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect(): epoll_create() error %i-%s", errno, strerror(errno)); return errno; } @@ -752,7 +771,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) ev.data.fd = fd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) { - syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: epoll_ctl error %i-%s", errno, strerror(errno)); + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect(): epoll_ctl() error %i-%s", errno, strerror(errno)); return errno; } @@ -761,7 +780,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge) { if (pthread_create(&threads, NULL, poll_thread, (void *)t) != 0) { - syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect: pthread_create error %i-%s", errno, strerror(errno)); + syslog(LOG_ERR, "Adafruit_BBIO: add_edge_detect(): pthread_create() error %i-%s", errno, strerror(errno)); return errno; } } @@ -777,17 +796,21 @@ void remove_edge_detect(unsigned int gpio) // delete callbacks for gpio remove_callbacks(gpio); - // delete epoll of fd + // delete fd from epoll epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev); // set edge to none gpio_set_edge(gpio, NO_EDGE); - // unexport gpio + //clear event gpio_event_remove(gpio); + // clear detected flag event_occurred[gpio] = 0; + + syslog(LOG_DEBUG, "Adafruit_BBIO: remove_edge_detect(): event detection disabled for pin %u",gpio); + } int event_detected(unsigned int gpio) diff --git a/source/event_gpio.h b/source/event_gpio.h index 78092ab..e06f344 100644 --- a/source/event_gpio.h +++ b/source/event_gpio.h @@ -72,6 +72,7 @@ int add_edge_detect(unsigned int gpio, unsigned int edge); void remove_edge_detect(unsigned int gpio); int add_edge_callback(unsigned int gpio, void (*func)(unsigned int gpio)); int event_detected(unsigned int gpio); +int gpio_initial(unsigned int gpio); int gpio_event_add(unsigned int gpio); int gpio_event_remove(unsigned int gpio); int gpio_is_evented(unsigned int gpio); From 4cc4b761886c57b1b022d447eee20052c89ef1f4 Mon Sep 17 00:00:00 2001 From: Demo User Date: Fri, 20 Jul 2018 10:50:01 +0000 Subject: [PATCH 098/157] update README with recommended Debian image Signed-off-by: Drew Fustini --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 75adddd..8d6bcfc 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart), [SPI](README.md#spi) and [eQEP](README.md#eqep) (Quadrature Encoder) hardware access from Python applications running on the Beaglebone. * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) - * **Currently recommended image: [Debian 9.2 "Stretch" iot (2017-10-29)](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#microSD.2FStandalone:_.28stretch-iot.29_.28All_BeagleBone_Variants_.26_PocketBeagle.29)** + * **Currently recommended image: [Debian 9.4 "Stretch" IoT (2018-06-17)](http://debian.beagleboard.org/images/bone-debian-9.4-iot-armhf-2018-06-17-4gb.img.xz)** * Install [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29) to enable [non-root control of GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) [_(commit)_](https://github.com/adafruit/adafruit-beaglebone-io-python/commit/b65cbf8e41b444bad7c4ef6cfd4f88a30210fd78) * Adafruit_BBIO supports Linux kernels 3.8 through 4.14 From 339314535b3eea782c3fdf34e8cbba9918e4e397 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Tue, 31 Jul 2018 20:44:11 -0500 Subject: [PATCH 099/157] docs/SPI.rst: Fix bus numbering in examples Commit 8dfbf64c36f3 ("Fix spidev path mismatch (#216)") changes how the SPI constructor maps to the spidev entry. Update the documentation to reflect this change. Signed-off-by: Franklin S Cooper Jr --- docs/SPI.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/SPI.rst b/docs/SPI.rst index d33aa5a..fcf4bf6 100644 --- a/docs/SPI.rst +++ b/docs/SPI.rst @@ -27,22 +27,22 @@ Example:: # spi = SPI(bus, device) #/dev/spidev. # /dev/spidev0.0 - spi = SPI(1, 0) + spi = SPI(0, 0) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev0.1 - spi = SPI(1, 1) + spi = SPI(0, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.0 - spi = SPI(2, 0) + spi = SPI(1, 0) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() # /dev/spidev1.1 - spi = SPI(2, 1) + spi = SPI(1, 1) print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() From 61ca14b9265e3cc0e406c89e4000541125fbe640 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Tue, 31 Jul 2018 21:03:29 -0500 Subject: [PATCH 100/157] docs/GPIO.rst: Add information on blinking led Copy information regarding blinking leds to the GPIO documentation Signed-off-by: Franklin S Cooper Jr --- docs/GPIO.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/GPIO.rst b/docs/GPIO.rst index b95b2b3..1bb443b 100644 --- a/docs/GPIO.rst +++ b/docs/GPIO.rst @@ -21,6 +21,14 @@ I/O (GPIO). `Beaglebone pin names table `_ +.. note:: + + On-board LEDs (USR0-USR3) are handled by LED class driver rather than the GPIO pin driver. + + They have a different path in the /sys/ filesystem. + + Setup the pin for output and write GPIO.HIGH or GPIO.LOW + Example:: # Use the config-pin command line tool to set a pin's function to GPIO @@ -38,6 +46,23 @@ Example:: GPIO.output("P8_14", GPIO.HIGH) # You can also write '1' instead GPIO.output("P8_14", GPIO.LOW) # You can also write '0' instead + + # Blinking onboard led example + import Adafruit_BBIO.GPIO as GPIO + import time + + for i in range(4): + GPIO.setup("USR%d" % i, GPIO.OUT) + + while True: + for i in range(4): + GPIO.output("USR%d" % i, GPIO.HIGH) + time.sleep(1) + for i in range(4): + GPIO.output("USR%d" % i, GPIO.LOW) + time.sleep(1) + + .. module:: Adafruit_BBIO.GPIO .. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) From 44c371a77a91d5a0677c783340c6de44934747e4 Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Tue, 31 Jul 2018 21:13:06 -0500 Subject: [PATCH 101/157] docs/GPIO.rst Make documentation a bit newbie friendly Make it clear in the parameter snippet that the various attributes belong to the GPIO class. Signed-off-by: Franklin S Cooper Jr --- docs/GPIO.rst | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/GPIO.rst b/docs/GPIO.rst index 1bb443b..70be0a1 100644 --- a/docs/GPIO.rst +++ b/docs/GPIO.rst @@ -65,15 +65,17 @@ Example:: .. module:: Adafruit_BBIO.GPIO -.. function:: setup(channel, direction[, pull_up_down=PUD_OFF, initial=None, delay=0]) +.. function:: setup(channel, direction[, pull_up_down=GPIO.PUD_OFF, initial=None, delay=0]) Set up the given GPIO channel, its direction and (optional) pull/up down control :param str channel: GPIO channel to set up (e.g. "P8_16"). - :param int direction: GPIO channel direction (:data:`IN` or :data:`OUT`). + :param int direction: GPIO channel direction + (:data:`GPIO.IN` or :data:`GPIO.OUT`). :param int pull_up_down: pull-up/pull-down resistor configuration - (:data:`PUD_OFF`, :data:`PUD_UP` or :data:`PUD_DOWN`). - :param int initial: initial value for an output channel (:data:`LOW`/:data:`HIGH`). + (:data:`GPIO.PUD_OFF`, :data:`GPIO.PUD_UP` or :data:`GPIO.PUD_DOWN`). + :param int initial: initial value for an output channel + (:data:`GPIO.LOW`/:data:`GPIO.HIGH`). :param int delay: time in milliseconds to wait after exporting the GPIO pin. .. function:: cleanup() @@ -91,7 +93,7 @@ Example:: :param str channel: GPIO channel to output the value to (e.g. "P8_16"). :param value: value to set the output to-- 0/1 or False/True - or :data:`LOW`/:data:`HIGH`. + or :data:`GPIO.LOW`/:data:`GPIO.HIGH`. :type value: int or bool .. function:: input(channel) @@ -107,8 +109,8 @@ Example:: Enable edge detection events for the given GPIO channel. :param str channel: GPIO channel to detect events from (e.g. "P8_16"). - :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` - or :data:`BOTH` + :param int edge: edge to detect–– :data:`GPIO.RISING`, :data:`GPIO.FALLING` + or :data:`GPIO.BOTH` :param func callback: a function to call once the event has been detected. :param int bouncetime: switch bounce timeout in ms for the callback. @@ -143,8 +145,8 @@ Example:: Wait for an edge on the given channel. :param str channel: GPIO channel to wait on (e.g. "P8_16"). - :param int edge: edge to detect–– :data:`RISING`, :data:`FALLING` - or :data:`BOTH` + :param int edge: edge to detect–– :data:`GPIO.RISING`, :data:`GPIO.FALLING` + or :data:`GPIO.BOTH` :param int timeout: time to wait for an edge, in milliseconds. -1 will wait forever. From e9d56e06c7ddc31bd6b2ae4f95b2092b976a353a Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 16 Aug 2018 01:06:50 -0500 Subject: [PATCH 102/157] Update ADC.rst testing readthedocs webhook --- docs/ADC.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ADC.rst b/docs/ADC.rst index 4aa14be..598ff25 100644 --- a/docs/ADC.rst +++ b/docs/ADC.rst @@ -35,8 +35,8 @@ Example:: Read the raw analog value for the channel. - :note: Kernels older than 4.1.x returned a raw value range based on - the reference voltage of 1.8 V–– from 0 to 1800. + :note: Kernels older than 4.1.x returned a raw value range 0 - 1800 + based on the reference voltage of 1.8 V. :param str channel: GPIO channel to read the value from (e.g. "P8_16"). :returns: raw value reading from 0 to 4095 (12 bits). From 4a82f4c430be953dbb3993783ae5fae66533a5d6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 16 Aug 2018 01:17:32 -0500 Subject: [PATCH 103/157] Update Encoder.rst --- docs/Encoder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Encoder.rst b/docs/Encoder.rst index 7716e3b..364eee3 100644 --- a/docs/Encoder.rst +++ b/docs/Encoder.rst @@ -1,4 +1,4 @@ -:mod:`Encoder` --- Quadrature Encoder interface +:mod:`Encoder` --- Quadrature Encoder interface (eQEP) ----------------------------------------------- .. automodule:: Adafruit_BBIO.Encoder From 829f97a91777a5a626b8624f6b90e433c8342e63 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 16 Aug 2018 01:20:47 -0500 Subject: [PATCH 104/157] Update ADC.rst --- docs/ADC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ADC.rst b/docs/ADC.rst index 598ff25..dc9c64c 100644 --- a/docs/ADC.rst +++ b/docs/ADC.rst @@ -2,7 +2,7 @@ -------------------------------------------- This module enables reading analog input values from the analog to digital -converter (ADC) on the Beaglebone processor. +converter (ADC) on the TI AM3358 SoC on the BeagleBone. Example:: From c749402003d9514ac23ed4885dc9806a68924fc3 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 30 Aug 2018 04:42:35 +0000 Subject: [PATCH 105/157] Add UART entries for the PocketBeagle (issue #242) PocketBeagle pins with UART pin mode: P1_30 uart0_txd P1_32 uart0_rxd P2_11 uart1_rxd P2_09 uart1_txd P1_08 uart2_rxd P1_10 uart2_txd P2_29 uart3_txd Available UART names on PocketBeagle: PB-UART0: /dev/ttyO0, Rx: P1_30, Tx: P1_32 PB-UART1: /dev/ttyO1, Rx: P2_11, Tx: P2_09 PB-UART2: /dev/ttyO2, Rx: P1_08, Tx: P1_10 PB-UART3: /dev/ttyO3, Rx: P2_29, Tx: none Signed-off-by: Drew Fustini --- README.md | 11 +++++++++++ source/common.c | 12 ++++++++++++ test/test_uart.py | 35 +++++++++++++++++++++++++++++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8d6bcfc..637dc4b 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,17 @@ if ser.isOpen(): ser.write("Hello World!") ser.close() ``` +* Available UART names on BeagleBone + * `UART1`: /dev/ttyO1, Rx: P9_26, Tx: P9_24 + * `UART2`: /dev/ttyO2, Rx: P9_22, Tx: P9_21 + * `UART3`: /dev/ttyO3, Rx: P9_42, Tx: none + * `UART4`: /dev/ttyO4, Rx: P9_11, Tx: P9_13 + * `UART5`: /dev/ttyO5, Rx: P8_38, Tx: P8_37 + * note: `UART5` requires `disable_uboot_overlay_video=1` in `/boot/uEnv.txt` +* Available UART names on PocketBeagle + * `PB-UART0`: /dev/ttyO0, Rx: P1_30, Tx: P1_32 + * `PB-UART1`: /dev/ttyO1, Rx: P2_11, Tx: P2_09 + * `PB-UART2`: /dev/ttyO2, Rx: P1_08, Tx: P1_10 * [Loopback test with UART1 and UART2](https://learn.adafruit.com/setting-up-io-python-library-on-beaglebone-black/uart#testing-and-using-the-uart) diff --git a/source/common.c b/source/common.c index e8fbbec..2b5fe67 100644 --- a/source/common.c +++ b/source/common.c @@ -263,12 +263,24 @@ pins_t table[] = { { NULL, NULL, 0, 0, 0 } }; +// Issue #243: UART setup not working for pocket beagle pins +// Add UART entries for the PocketBeagle: +// P1_30 uart0_txd +// P1_32 uart0_rxd +// P2_11 uart1_rxd +// P2_09 uart1_txd +// P1_08 uart2_rxd +// P1_10 uart2_txd + uart_t uart_table[] = { { "UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P9_26", "P9_24"}, { "UART2", "/dev/ttyO2", "ADAFRUIT-UART2", "P9_22", "P9_21"}, { "UART3", "/dev/ttyO3", "ADAFRUIT-UART3", "P9_42", ""}, { "UART4", "/dev/ttyO4", "ADAFRUIT-UART4", "P9_11", "P9_13"}, { "UART5", "/dev/ttyO5", "ADAFRUIT-UART5", "P8_38", "P8_37"}, + { "PB-UART0", "/dev/ttyO0", "ADAFRUIT-UART0", "P1_30", "P1_32"}, + { "PB-UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P2_11", "P2_09"}, + { "PB-UART2", "/dev/ttyO2", "ADAFRUIT-UART2", "P1_08", "P1_10"}, { NULL, NULL, 0, 0, 0 } }; diff --git a/test/test_uart.py b/test/test_uart.py index 4fd4ac3..38f3ba7 100644 --- a/test/test_uart.py +++ b/test/test_uart.py @@ -1,4 +1,5 @@ import pytest +import serial import platform import Adafruit_BBIO.UART as UART @@ -11,7 +12,7 @@ def teardown_module(module): # ADC.cleanup() -class TestAdc: +class TestUart: def test_setup_uart_wrong_name(self): if kernel >= '4.1.0': pass @@ -25,9 +26,39 @@ def test_setup_adc(self): else: UART.setup("UART1") - def test_setup_adc_multiple(self): + def test_setup_uart_multiple(self): if kernel >= '4.1.0': pass else: UART.setup("UART1") UART.setup("UART1") + + # test UART entries for the PocketBeagle (issue #243) + def test_pocketbeagle(self): + if kernel < '4.1.0': + pass + value = open('/proc/device-tree/model').read() + if(value.startswith("TI AM335x PocketBeagle")): + uarts = { + 'PB-UART0': '/dev/ttyO0', + 'PB-UART1': '/dev/ttyO1', + 'PB-UART2': '/dev/ttyO2', + } + else: + uarts = { + 'UART1': '/dev/ttyO1', + 'UART2': '/dev/ttyO2', + 'UART4': '/dev/ttyO4' + # note: UART5 requires + # "disable_uboot_overlay_video=1" in /boot/uEnv.txt + #'UART5': '/dev/ttyO5' + } + + for name, device in sorted(uarts.items()): + UART.setup(name) + uart = serial.Serial(port = device, baudrate=9600) + uart.close() + uart.open() + if uart.isOpen(): + uart.write("hello world".encode("utf-8")) + uart.close() From bf97de641a7c73ce4be7af55a3ef98eb245e8757 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 31 Aug 2018 09:22:12 +0000 Subject: [PATCH 106/157] update install and test shell scripts Signed-off-by: Drew Fustini --- install_all_python_versions.sh | 10 ++++------ pytest_all_versions.sh | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/install_all_python_versions.sh b/install_all_python_versions.sh index 932c462..cc19011 100755 --- a/install_all_python_versions.sh +++ b/install_all_python_versions.sh @@ -1,9 +1,7 @@ #!/bin/bash # useful for testing changes against all versions of python make clean -echo "Install Python 2.7" -python2.7 ./setup.py install -echo "Install Python 3.5" -python3.5 ./setup.py install -echo "Install Python 3.6" -python3.6 ./setup.py install +echo "Install Python 2" +python2 ./setup.py install +echo "Install Python 3" +python3 ./setup.py install diff --git a/pytest_all_versions.sh b/pytest_all_versions.sh index dca6919..76d46e6 100755 --- a/pytest_all_versions.sh +++ b/pytest_all_versions.sh @@ -2,10 +2,8 @@ # useful for testing changes against all versions of python cd test -echo "Testing Python 2.7" -python2.7 -mpytest -echo "Testing Python 3.5" -python3.5 -mpytest -echo "Testing Python 3.6" -python3.6 -mpytest +echo "Testing Python 2" +python2 -mpytest +echo "Testing Python 3" +python3 -mpytest cd .. From 8353c7c39b7f239916a9ca735e9994f4c0311146 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 31 Aug 2018 05:19:22 -0500 Subject: [PATCH 107/157] update UART section in README Signed-off-by: Drew Fustini --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 637dc4b..d3ddf1a 100644 --- a/README.md +++ b/README.md @@ -202,14 +202,13 @@ ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) ser.close() ser.open() if ser.isOpen(): - print "Serial is open!" + print "Serial is open!" ser.write("Hello World!") ser.close() ``` * Available UART names on BeagleBone * `UART1`: /dev/ttyO1, Rx: P9_26, Tx: P9_24 * `UART2`: /dev/ttyO2, Rx: P9_22, Tx: P9_21 - * `UART3`: /dev/ttyO3, Rx: P9_42, Tx: none * `UART4`: /dev/ttyO4, Rx: P9_11, Tx: P9_13 * `UART5`: /dev/ttyO5, Rx: P8_38, Tx: P8_37 * note: `UART5` requires `disable_uboot_overlay_video=1` in `/boot/uEnv.txt` From e626f07d8d79e3eca8a2578da7eab6e8096b0e29 Mon Sep 17 00:00:00 2001 From: Erik Welsh Date: Sun, 30 Sep 2018 16:20:04 +0000 Subject: [PATCH 108/157] Fixed GPIO export problem; Leaves GPIO in bad state on latest BeagleBone image on PocketBeagle --- source/event_gpio.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/source/event_gpio.c b/source/event_gpio.c index c63fdbd..9f5acd6 100644 --- a/source/event_gpio.c +++ b/source/event_gpio.c @@ -85,6 +85,27 @@ BBIO_err gpio_export(unsigned int gpio) goto exit; } + // Is GPIO an LED? + if ( ((gpio >= USR_LED_GPIO_MIN) && (gpio <= USR_LED_GPIO_MAX)) + || + ( beaglebone_blue() + && + ( + (gpio == USR_LED_RED) + || (gpio == USR_LED_GREEN) + || (gpio == BAT25) + || (gpio == BAT50) + || (gpio == BAT75) + || (gpio == BAT100) + || (gpio == WIFI) + ) + ) + ) + { + syslog(LOG_WARNING, "Adafruit_BBIO: gpio_export: %u not applicable to built-in LEDs", gpio); + return BBIO_OK; // export is not applicable to the USR LED pins + } + // already exported by someone else? char gpio_path[64]; snprintf(gpio_path, sizeof(gpio_path), "/sys/class/gpio/gpio%d", gpio); From 7affea78fd995b522a49c19df060b1daea404b5f Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 7 Oct 2018 22:07:42 +0000 Subject: [PATCH 109/157] do not load overlays for the beaglebone blue #283 beaglebone blue has complete dtb file and does not need overlays refer to issue 283: https://github.com/adafruit/adafruit-beaglebone-io-python/issues/283 --- source/common.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/source/common.c b/source/common.c index 2b5fe67..1a186b7 100644 --- a/source/common.c +++ b/source/common.c @@ -653,7 +653,15 @@ BBIO_err load_device_tree(const char *name) return BBIO_OK; } + /* beaglebone blue has complete dtb file and does not need overlays */ + if(beaglebone_blue()) { + fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + return BBIO_OK; + } + + /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { + fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); return BBIO_OK; } @@ -707,7 +715,15 @@ int device_tree_loaded(const char *name) return 1; } + /* beaglebone blue has complete dtb file and does not need overlays */ + if(beaglebone_blue()) { + fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + return BBIO_OK; + } + + /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { + fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); return BBIO_OK; } @@ -749,6 +765,18 @@ BBIO_err unload_device_tree(const char *name) char line[256]; char *slot_line; + /* beaglebone blue has complete dtb file and does not need overlays */ + if(beaglebone_blue()) { + fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + return BBIO_OK; + } + + /* pocketbeagle has complete dtb file and does not need overlays */ + if(pocketbeagle()) { + fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); + return BBIO_OK; + } + snprintf(slots, sizeof(slots), "%s/slots", ctrl_dir); file = fopen(slots, "r+"); if (!file) { From eff11b83feecf083104eae87281979a7eaad4107 Mon Sep 17 00:00:00 2001 From: Sam Bristow Date: Tue, 9 Oct 2018 23:31:35 +1300 Subject: [PATCH 110/157] Use print() function in all code and docs Low-hanging fruit of Python3 compatibility work. I've left fix_py_compile.py as it is only ever going to be run under Python 2. --- Adafruit_BBIO/sysfs.py | 2 +- README.md | 4 ++-- source/examples/python/i2ctmp101.py | 2 +- test/notes/spi_loopback_test.md | 2 +- test/start_all_pwm.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Adafruit_BBIO/sysfs.py b/Adafruit_BBIO/sysfs.py index 43fd078..f2273a1 100644 --- a/Adafruit_BBIO/sysfs.py +++ b/Adafruit_BBIO/sysfs.py @@ -41,7 +41,7 @@ # Print all block devices in /sys, with their sizes for block_dev in sys.block: - print block_dev, str(int(block_dev.size) / 1048576) + ' M' + print(block_dev, str(int(block_dev.size) / 1048576) + ' M') >>> import sysfs >>> # Read/write Beaglebone Black's eQEP module attributes diff --git a/README.md b/README.md index d3ddf1a..656881b 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ Detecting events: #your amazing code here #detect wherever: if GPIO.event_detected("P9_12"): - print "event detected!" + print("event detected!") ### PWM **The PWM Duty Cycle range was reversed in 0.0.15 from 100(off)-0(on) to 0(off)-100(on). Please update your code accordingly.** @@ -202,7 +202,7 @@ ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) ser.close() ser.open() if ser.isOpen(): - print "Serial is open!" + print("Serial is open!") ser.write("Hello World!") ser.close() ``` diff --git a/source/examples/python/i2ctmp101.py b/source/examples/python/i2ctmp101.py index 923c0f9..ab916c0 100755 --- a/source/examples/python/i2ctmp101.py +++ b/source/examples/python/i2ctmp101.py @@ -8,5 +8,5 @@ while True: temp = bus.read_byte_data(address, 0) - print (temp, end="\r") + print(temp, end="\r") time.sleep(0.25) diff --git a/test/notes/spi_loopback_test.md b/test/notes/spi_loopback_test.md index 0f93d0c..7041852 100644 --- a/test/notes/spi_loopback_test.md +++ b/test/notes/spi_loopback_test.md @@ -46,7 +46,7 @@ from Adafruit_BBIO.SPI import SPI #spi = SPI(1,1) #/dev/spidev2.1 spi = SPI(0,0) -print spi.xfer2([32, 11, 110, 22, 220]) +print(spi.xfer2([32, 11, 110, 22, 220])) spi.close() ``` diff --git a/test/start_all_pwm.py b/test/start_all_pwm.py index 58d02f5..f19ef97 100644 --- a/test/start_all_pwm.py +++ b/test/start_all_pwm.py @@ -20,7 +20,7 @@ # /sys/devices/platform/ocp/48304000.epwmss/48304100.ecap/pwm/pwmchip5/pwm-5:0/duty_cycle for pin in pins: - print pin + print(pin) PWM.start(pin, 50, 2000, 1) PWM.stop(pin) PWM.cleanup() From 783bfacee8fa013adf60c3f98b334d5f57fe52b3 Mon Sep 17 00:00:00 2001 From: Sam Bristow Date: Tue, 9 Oct 2018 23:39:43 +1300 Subject: [PATCH 111/157] Use new python-serial API Version 3.0 of python-serial introduced an updated API, we may as well use it. This change also uses context-managers for dealing with UARTs as they are less error-prone and the code is much cleaner/shorter. --- README.md | 9 +++------ docs/UART.rst | 10 +++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 656881b..cc179c2 100644 --- a/README.md +++ b/README.md @@ -198,13 +198,10 @@ import serial UART.setup("UART1") -ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) -ser.close() -ser.open() -if ser.isOpen(): +with serial.Serial(port = "/dev/ttyO1", baudrate=9600) as ser: print("Serial is open!") - ser.write("Hello World!") -ser.close() + ser.write(b"Hello World!") + ``` * Available UART names on BeagleBone * `UART1`: /dev/ttyO1, Rx: P9_26, Tx: P9_24 diff --git a/docs/UART.rst b/docs/UART.rst index 3566803..c3d238d 100644 --- a/docs/UART.rst +++ b/docs/UART.rst @@ -14,13 +14,9 @@ Example:: UART.setup("UART1") - ser = serial.Serial(port = "/dev/ttyO1", baudrate=9600) - ser.close() - ser.open() - if ser.isOpen(): - print "Serial is open!" - ser.write("Hello World!") - ser.close() + with serial.Serial(port = "/dev/ttyO1", baudrate=9600) as ser: + print("Serial is open!") + ser.write(b"Hello World!") .. module:: Adafruit_BBIO.UART From 448854c2094e66c783ae7d27fa230e057d6e1ab6 Mon Sep 17 00:00:00 2001 From: Sam Bristow Date: Tue, 9 Oct 2018 23:57:20 +1300 Subject: [PATCH 112/157] Return error-code for failing interface Rather than returning the error code for UART1 regardless of which interface had problems, we should return the error code for the interface that actually had an error. Pretty sure this was a simple copy-paste mistake. --- source/c_uart.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/c_uart.c b/source/c_uart.c index 211c54e..471c2a9 100644 --- a/source/c_uart.c +++ b/source/c_uart.c @@ -46,13 +46,13 @@ BBIO_err uart_cleanup(void) if (e1 != BBIO_OK) return e1; if (e2 != BBIO_OK) - return e1; + return e2; if (e3 != BBIO_OK) - return e1; + return e3; if (e4 != BBIO_OK) - return e1; + return e4; if (e5 != BBIO_OK) - return e1; + return e5; return BBIO_OK; } From c09ab8ee43fe211a38523a96e7039aee0df33084 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 12 Oct 2018 19:07:33 +0000 Subject: [PATCH 113/157] fix pwm on pocketbeagle and beaglebone blue #286 pocketbeagle and beaglebone blue have complete dtb file and do not need overlays --- source/c_pwm.c | 5 +++++ source/common.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index f983592..95b6d17 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -338,6 +338,10 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri // Make sure that one of the universal capes is loaded if( !uboot_overlay_enabled() // only check kernel overlays if u-boot overlays are not being used + && + !beaglebone_blue() // beaglebone blue has complete dtb file and does not need overlays + && + !pocketbeagle() // pocketbeagle has complete dtb file and does not need overlays && !( device_tree_loaded("cape-univ-audio") // from cdsteinkuehler/beaglebone-universal-io || device_tree_loaded("cape-univ-emmc") // "" @@ -583,6 +587,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri BBIO_err pwm_start(const char *key, float duty, float freq, int polarity) { syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i", key, duty, freq, polarity); + fprintf(stderr, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i\n", key, duty, freq, polarity); BBIO_err err; char buffer[20]; diff --git a/source/common.c b/source/common.c index 1a186b7..8625cc4 100644 --- a/source/common.c +++ b/source/common.c @@ -717,13 +717,13 @@ int device_tree_loaded(const char *name) /* beaglebone blue has complete dtb file and does not need overlays */ if(beaglebone_blue()) { - fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + fprintf(stderr, "common.c: device_tree_loaded(): beaglebone_blue(): TRUE\n"); return BBIO_OK; } /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { - fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); + fprintf(stderr, "common.c: device_tree_loaded(): pocketbeagle(): TRUE\n"); return BBIO_OK; } @@ -767,13 +767,13 @@ BBIO_err unload_device_tree(const char *name) /* beaglebone blue has complete dtb file and does not need overlays */ if(beaglebone_blue()) { - fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + fprintf(stderr, "common.c: unload_device_tree(): beaglebone_blue(): TRUE\n"); return BBIO_OK; } /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { - fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); + fprintf(stderr, "common.c: unload_device_tree(): pocketbeagle(): TRUE\n"); return BBIO_OK; } From 1f7c20e8991f887267f34559907229b702a36e17 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 17 Oct 2018 14:59:09 -0500 Subject: [PATCH 114/157] remove debug logging --- source/c_pwm.c | 2 +- source/common.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 95b6d17..e1f917e 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -587,7 +587,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri BBIO_err pwm_start(const char *key, float duty, float freq, int polarity) { syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i", key, duty, freq, polarity); - fprintf(stderr, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i\n", key, duty, freq, polarity); + //fprintf(stderr, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i\n", key, duty, freq, polarity); BBIO_err err; char buffer[20]; diff --git a/source/common.c b/source/common.c index 8625cc4..42dd5f5 100644 --- a/source/common.c +++ b/source/common.c @@ -655,13 +655,13 @@ BBIO_err load_device_tree(const char *name) /* beaglebone blue has complete dtb file and does not need overlays */ if(beaglebone_blue()) { - fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); + //fprintf(stderr, "common.c: load_device_tree(): beaglebone_blue(): TRUE\n"); return BBIO_OK; } /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { - fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); + //fprintf(stderr, "common.c: load_device_tree(): pocketbeagle(): TRUE\n"); return BBIO_OK; } @@ -717,13 +717,13 @@ int device_tree_loaded(const char *name) /* beaglebone blue has complete dtb file and does not need overlays */ if(beaglebone_blue()) { - fprintf(stderr, "common.c: device_tree_loaded(): beaglebone_blue(): TRUE\n"); + //fprintf(stderr, "common.c: device_tree_loaded(): beaglebone_blue(): TRUE\n"); return BBIO_OK; } /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { - fprintf(stderr, "common.c: device_tree_loaded(): pocketbeagle(): TRUE\n"); + //fprintf(stderr, "common.c: device_tree_loaded(): pocketbeagle(): TRUE\n"); return BBIO_OK; } @@ -767,13 +767,13 @@ BBIO_err unload_device_tree(const char *name) /* beaglebone blue has complete dtb file and does not need overlays */ if(beaglebone_blue()) { - fprintf(stderr, "common.c: unload_device_tree(): beaglebone_blue(): TRUE\n"); + //fprintf(stderr, "common.c: unload_device_tree(): beaglebone_blue(): TRUE\n"); return BBIO_OK; } /* pocketbeagle has complete dtb file and does not need overlays */ if(pocketbeagle()) { - fprintf(stderr, "common.c: unload_device_tree(): pocketbeagle(): TRUE\n"); + //fprintf(stderr, "common.c: unload_device_tree(): pocketbeagle(): TRUE\n"); return BBIO_OK; } From 71d1bb293ade1e0cf4820bc5888c84d059d6d27c Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 18 Oct 2018 06:58:25 +0000 Subject: [PATCH 115/157] update version to 1.1.0 --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 565b357..caf0bbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +1.1.0 +--- +Aaron Marburg (1): + * Added usleep after successfully enabling PWM via udev. + +Drew Fustini (16): + * Merge pull request #233 from zsserg/fixed_segfault_in_event_detection + * Merge pull request #257 from zsserg/develop + * Merge pull request #251 from amarburg/master + * Merge pull request #271 from fcooper/documentation-updates + * Update ADC.rst + * Update Encoder.rst + * Update ADC.rst + * Add UART entries for the PocketBeagle (issue #242) + * update install and test shell scripts + * update UART section in README + * Merge pull request #282 from erikwelsh/master + * do not load overlays for the beaglebone blue #283 + * Merge pull request #284 from sam-bristow/py3-docs + * Merge pull request #285 from sam-bristow/bugfix/uart-error-reporting + * fix pwm on pocketbeagle and beaglebone blue #286 + * remove debug logging + +Erik Welsh (1): + * Fixed GPIO export problem; Leaves GPIO in bad state on latest BeagleBone image on PocketBeagle + +Franklin S Cooper Jr (3): + * docs/SPI.rst: Fix bus numbering in examples + * docs/GPIO.rst: Add information on blinking led + * docs/GPIO.rst Make documentation a bit newbie friendly + +Sam Bristow (3): + * Use print() function in all code and docs + * Use new python-serial API + * Return error-code for failing interface + +zserg (5): + * Fixed SEGFAULT when calling remove_event_detect() inside python callback function. + * Fixed SEGFAULT when calling remove_event_detect() inside python callback function. + * Fixed SEGFAULT in event_gpio,c run_callbacks() * Added more elaborate epoll() error logging + * Minor style fixes + 1.0.10 ---- **features** diff --git a/setup.py b/setup.py index ec60ac7..bbe0209 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.0.10', + version = '1.1.0', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From f70453ed413796c2b5d612a5e2056927d168f699 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 20 Nov 2018 08:26:47 +0000 Subject: [PATCH 116/157] upload to PyPI againt to resolve #293 --- CHANGELOG.md | 5 +++++ setup.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caf0bbb..a3895c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +1.1.1 +--- +Attempt upload to PyPI again to avoid +error reported in issue #293 + 1.1.0 --- Aaron Marburg (1): diff --git a/setup.py b/setup.py index bbe0209..fd63bd8 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.1.0', + version = '1.1.1', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From 96aa8ed2aa427923c04987c102ebe53f9e6b69c9 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 23 Nov 2018 04:54:32 +0000 Subject: [PATCH 117/157] do not set pinmux on the beaglebone blue beaglebone blue has complete dtb file and does not need pinmux set for gpio ports --- source/c_pinmux.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/c_pinmux.c b/source/c_pinmux.c index 6932ec6..d22272b 100644 --- a/source/c_pinmux.c +++ b/source/c_pinmux.c @@ -32,13 +32,23 @@ BBIO_err set_pin_mode(const char *key, const char *mode) snprintf(pinmux_dir, sizeof(pinmux_dir), "ocp:%s_pinmux", pin); snprintf(path, sizeof(path), "%s/%s/state", ocp_dir, pinmux_dir); + /* beaglebone blue has complete dtb file and does not need overlays */ + if(beaglebone_blue()) { + fprintf(stderr, "DEBUG: Adafruit_BBIO: set_pin_mode() :: Pinmux file: %s, mode: %s", path, mode); + fprintf(stderr, "DEBUG: Adafruit_BBIO: set_pin_mode(): beaglebone_blue() is TRUE; return BBIO_OK\n"); + return BBIO_OK; + } + + f = fopen(path, "w"); if (NULL == f) { return BBIO_ACCESS; } syslog(LOG_DEBUG, "Adafruit_BBIO: set_pin_mode() :: Pinmux file %s access OK", path); + fprintf(stderr, "Adafruit_BBIO: set_pin_mode() :: Pinmux file %s access OK", path); fprintf(f, "%s", mode); fclose(f); syslog(LOG_DEBUG, "Adafruit_BBIO: set_pin_mode() :: Set pinmux mode to %s for %s", mode, pin); + fprintf(stderr, "Adafruit_BBIO: set_pin_mode() :: Set pinmux mode to %s for %s", mode, pin); return BBIO_OK; } From e96e1efb53b3dc225567f4aec3173edc0829b8db Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 23 Nov 2018 05:35:27 +0000 Subject: [PATCH 118/157] remove deug output --- source/c_pinmux.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/c_pinmux.c b/source/c_pinmux.c index d22272b..f08934a 100644 --- a/source/c_pinmux.c +++ b/source/c_pinmux.c @@ -45,10 +45,8 @@ BBIO_err set_pin_mode(const char *key, const char *mode) return BBIO_ACCESS; } syslog(LOG_DEBUG, "Adafruit_BBIO: set_pin_mode() :: Pinmux file %s access OK", path); - fprintf(stderr, "Adafruit_BBIO: set_pin_mode() :: Pinmux file %s access OK", path); fprintf(f, "%s", mode); fclose(f); syslog(LOG_DEBUG, "Adafruit_BBIO: set_pin_mode() :: Set pinmux mode to %s for %s", mode, pin); - fprintf(stderr, "Adafruit_BBIO: set_pin_mode() :: Set pinmux mode to %s for %s", mode, pin); return BBIO_OK; } From 2cfded3459b1ab4e5054c5ebbdbfcee905702905 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 10 Dec 2018 07:32:21 -0600 Subject: [PATCH 119/157] Fix dead link to bone.js #296 --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index 42dd5f5..e003d22 100644 --- a/source/common.c +++ b/source/common.c @@ -69,7 +69,7 @@ typedef struct pins_t { int ain; } pins_t; -//Table generated based on https://raw.github.com/jadonk/bonescript/master/node_modules/bonescript/bone.js +//Table generated based on https://github.com/jadonk/bonescript/blob/master/src/bone.js pins_t table[] = { { "USR0", "USR0", 53, -1, -1}, { "USR1", "USR1", 54, -1, -1}, From b2a6be54a102377b8e1a5018948362b07e71adc3 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 19 Dec 2018 19:30:41 +0000 Subject: [PATCH 120/157] force Encoder period to be an integer #299 --- Adafruit_BBIO/Encoder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index 21c88c1..84ca5f6 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -351,7 +351,8 @@ def frequency(self, frequency): new positions. ''' - period = self._NS_FACTOR / frequency # Period in nanoseconds + # github issue #299: force period to be an integer + period = int(self._NS_FACTOR / frequency) # Period in nanoseconds self._eqep.node.period = str(period) self._logger.debug( "Set frequency(): Channel {}, frequency: {} Hz, " From 0923b85884fd1a021a3ea92b3e30ab5a654e121b Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 18 Mar 2019 23:12:00 +0100 Subject: [PATCH 121/157] Ignore new compiler warnings in gcc 8.2.0 I was testing the new Debian "buster" image by @RobertCNelson and we noticed that the Adafruit_BBIO build was failing on compiler warnings. This seems to be due to the introduction of new compiler warnings in the more recent version of gcc that is on the buster image: https://rcn-ee.net/rootfs/bb.org/testing/2019-03-03/buster-iot/bone-debian-buster-iot-armhf-2019-03-03-4gb.img.xz a shot --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fd63bd8..b956064 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ else: kernel41 = None -CFLAGS = ['-Wall', '-Werror', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing' ] +CFLAGS = ['-Wall', '-Werror', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing', '-Wno-cast-function-type', '-Wno-error=format-truncation=', '-Wno-error=sizeof-pointer-memaccess' ] classifiers = ['Development Status :: 3 - Alpha', 'Operating System :: POSIX :: Linux', From e06bec0d244a48265a3855e643167f8d1faae04a Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sat, 30 Mar 2019 15:04:45 +0000 Subject: [PATCH 122/157] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b956064..fd63bd8 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ else: kernel41 = None -CFLAGS = ['-Wall', '-Werror', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing', '-Wno-cast-function-type', '-Wno-error=format-truncation=', '-Wno-error=sizeof-pointer-memaccess' ] +CFLAGS = ['-Wall', '-Werror', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing' ] classifiers = ['Development Status :: 3 - Alpha', 'Operating System :: POSIX :: Linux', From 5df30a8b735470e9b47f4f416a955043d85576a9 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 1 Apr 2019 03:10:02 +0100 Subject: [PATCH 123/157] do not set pin mode for built-in USRn LEDs This fix resolves Adafruit_BBIO issue #310 and https://github.com/adafruit/Adafruit_Blinka/issues/96 which was preventing the USR LEDs from being used by the CircuitPython Blinka library --- source/c_pinmux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/c_pinmux.c b/source/c_pinmux.c index f08934a..a315b83 100644 --- a/source/c_pinmux.c +++ b/source/c_pinmux.c @@ -13,7 +13,12 @@ BBIO_err set_pin_mode(const char *key, const char *mode) char pinmux_dir[20]; // "ocp:P#_##_pinmux" char pin[6]; //"P#_##" FILE *f = NULL; - + + // pin mode can not be set for the built-in USRn LEDs + if (strncmp(key, "USR", 3) == 0) { + return BBIO_OK; + } + if (strlen(key) == 4) // Key P#_# format, must inject '0' to be P#_0# snprintf(pin, sizeof(pin), "%.3s0%c", key,key[3]); else //copy string From b867bbffe39c1ae0ce25c31781f8f2da5152fce6 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 3 Apr 2019 00:21:27 +0100 Subject: [PATCH 124/157] Change name of P1_3 to match bone.js --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index e003d22..a22cfe2 100644 --- a/source/common.c +++ b/source/common.c @@ -189,7 +189,7 @@ pins_t table[] = { // These are for the PocketBeagle { "VIN_AC", "P1_1", 0, -1, -1}, { "GPIO2_23", "P1_2", 87, -1, -1}, - { "USB1_VBUS_OUT", "P1_3", 0, -1, -1}, + { "USB1_DRVVBUS", "P1_3", 0, -1, -1}, { "GPIO2_25", "P1_4", 89, -1, -1}, { "USB1_VBUS_IN", "P1_5", 0, -1, -1}, { "SPI0_CS0", "P1_6", 5, -1, -1}, From 7032af7e5f93adec06e289037ee00d951103c7a9 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 6 Dec 2019 06:12:43 +0000 Subject: [PATCH 125/157] Fix warning about casting incompatible function types #308 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian 10 (Buster) has gcc 8.2 which warns about: cast between incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *, PyObject *)’ The solution is to cast to '(PyCFunction)(void *)' --- source/py_gpio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/py_gpio.c b/source/py_gpio.c index 1f37dda..2721cca 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -555,14 +555,14 @@ static PyObject *py_setwarnings(__attribute__ ((unused)) PyObject *self, __attri static const char moduledocstring[] = "GPIO functionality of a BeagleBone using Python"; PyMethodDef gpio_methods[] = { - {"setup", (PyCFunction)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up the GPIO channel, direction and (optional) pull/up down control\nchannel - Either: RPi board pin number (not BCM GPIO 00..nn number). Pins start from 1\n or : BCM GPIO number\ndirection - INPUT or OUTPUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel\n[delay] - Time in milliseconds to wait after exporting gpio pin"}, + {"setup", (PyCFunction)(void *)py_setup_channel, METH_VARARGS | METH_KEYWORDS, "Set up the GPIO channel, direction and (optional) pull/up down control\nchannel - Either: RPi board pin number (not BCM GPIO 00..nn number). Pins start from 1\n or : BCM GPIO number\ndirection - INPUT or OUTPUT\n[pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN\n[initial] - Initial value for an output channel\n[delay] - Time in milliseconds to wait after exporting gpio pin"}, {"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"}, {"output", py_output_gpio, METH_VARARGS, "Output to a GPIO channel\ngpio - gpio channel\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\ngpio - gpio channel"}, - {"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"}, + {"add_event_detect", (PyCFunction)(void *)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\ngpio - gpio channel"}, {"event_detected", py_event_detected, METH_VARARGS, "Returns True if an edge has occured on a given GPIO. You need to enable edge detection using add_event_detect() first.\ngpio - gpio channel"}, - {"add_event_callback", (PyCFunction)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\ngpio - gpio channel\ncallback - a callback function\n[bouncetime] - Switch bounce timeout in ms"}, + {"add_event_callback", (PyCFunction)(void *)py_add_event_callback, METH_VARARGS | METH_KEYWORDS, "Add a callback for an event already defined using add_event_detect()\ngpio - gpio channel\ncallback - a callback function\n[bouncetime] - Switch bounce timeout in ms"}, {"wait_for_edge", py_wait_for_edge, METH_VARARGS, "Wait for an edge.\ngpio - gpio channel\nedge - RISING, FALLING or BOTH\ntimeout (optional) - time to wait in miliseconds. -1 will wait forever (default)"}, {"gpio_function", py_gpio_function, METH_VARARGS, "Return the current GPIO function (IN, OUT, ALT0)\ngpio - gpio channel"}, {"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, From 9298393cf57e7fd9c2414cf8a736df022fecedb3 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 6 Dec 2019 10:24:47 +0000 Subject: [PATCH 126/157] Fix warning print format strings being truncated #308 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian 10 (Buster) has gcc 8.2 which warns about: error: ‘%s’ directive output may be truncated writing up to 19 bytes into a region of size between 10 and 59 [-Werror=format-truncation=] snprintf(path, sizeof(path), "%s/%s/state", ocp_dir, pinmux_dir); --- source/c_pinmux.c | 2 +- source/common.c | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/source/c_pinmux.c b/source/c_pinmux.c index a315b83..23f1030 100644 --- a/source/c_pinmux.c +++ b/source/c_pinmux.c @@ -9,7 +9,7 @@ BBIO_err set_pin_mode(const char *key, const char *mode) { // char ocp_dir[] defined in common.h - char path[60]; // "/sys/devices/platform/ocp/ocp:P#_##_pinmux/state" + char path[100]; // "/sys/devices/platform/ocp/ocp:P#_##_pinmux/state" char pinmux_dir[20]; // "ocp:P#_##_pinmux" char pin[6]; //"P#_##" FILE *f = NULL; diff --git a/source/common.c b/source/common.c index a22cfe2..cd03bd9 100644 --- a/source/common.c +++ b/source/common.c @@ -636,12 +636,10 @@ BBIO_err load_device_tree(const char *name) { char line[256]; FILE *file = NULL; - + char slots[100]; #ifdef BBBVERSION41 - char slots[41]; snprintf(ctrl_dir, sizeof(ctrl_dir), "/sys/devices/platform/bone_capemgr"); #else - char slots[40]; build_path("/sys/devices", "bone_capemgr", ctrl_dir, sizeof(ctrl_dir)); #endif @@ -698,11 +696,10 @@ BBIO_err load_device_tree(const char *name) int device_tree_loaded(const char *name) { FILE *file = NULL; + char slots[100]; #ifdef BBBVERSION41 - char slots[41]; snprintf(ctrl_dir, sizeof(ctrl_dir), "/sys/devices/platform/bone_capemgr"); #else - char slots[40]; build_path("/sys/devices", "bone_capemgr", ctrl_dir, sizeof(ctrl_dir)); #endif char line[256]; @@ -755,11 +752,10 @@ int device_tree_loaded(const char *name) BBIO_err unload_device_tree(const char *name) { FILE *file = NULL; + char slots[100]; #ifdef BBBVERSION41 - char slots[41]; snprintf(ctrl_dir, sizeof(ctrl_dir), "/sys/devices/platform/bone_capemgr"); #else - char slots[40]; build_path("/sys/devices", "bone_capemgr", ctrl_dir, sizeof(ctrl_dir)); #endif char line[256]; From 3a5d23d01bf2978b2ec59e2f017e0ed679d10a25 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Fri, 6 Dec 2019 10:26:49 +0000 Subject: [PATCH 127/157] Fix warning about casting incompatible function types #308 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian 10 (Buster) has gcc 8.2 which warns about: cast between incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *, PyObject *)’ The solution is to cast to '(PyCFunction)(void *)' --- source/py_pwm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/py_pwm.c b/source/py_pwm.c index 55f50f9..e5f10f8 100644 --- a/source/py_pwm.c +++ b/source/py_pwm.c @@ -215,10 +215,10 @@ static PyObject *py_set_frequency(__attribute__ ((unused)) PyObject *self, PyObj static const char moduledocstring[] = "PWM functionality of a BeagleBone using Python"; PyMethodDef pwm_methods[] = { - {"start", (PyCFunction)py_start_channel, METH_VARARGS | METH_KEYWORDS, "Set up and start the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, - {"stop", (PyCFunction)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, - { "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS | METH_KEYWORDS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, - { "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS | METH_KEYWORDS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, + {"start", (PyCFunction)(void *)py_start_channel, METH_VARARGS | METH_KEYWORDS, "Set up and start the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, + {"stop", (PyCFunction)(void *)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, + { "set_duty_cycle", (PyCFunction)(void *)py_set_duty_cycle, METH_VARARGS | METH_KEYWORDS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, + { "set_frequency", (PyCFunction)(void *)py_set_frequency, METH_VARARGS | METH_KEYWORDS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, {"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"}, //{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, {NULL, NULL, 0, NULL} From 7fb13f9f3d4c559b14c55721e0a51024fb12608a Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 11 Dec 2019 08:44:07 +0000 Subject: [PATCH 128/157] Fix warnings on format truncation and sizeof in strncpy #308 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian 10 (Buster) has gcc 8.2 which warns about: source/c_pwm.c:459:65: error: argument to ‘sizeof’ in ‘strncpy’ call is the same expression as the source; did you mean to use the size of the destination? [-Werror=sizeof-pointer-memaccess] source/c_pwm.c:396:43: error: ‘%s’ directive output may be truncated writing up to 199 bytes into a region of size 100 [-Werror=format-truncation=] --- source/c_adc.c | 8 ++++---- source/c_pwm.c | 52 +++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/source/c_adc.c b/source/c_adc.c index 21ad284..d496366 100644 --- a/source/c_adc.c +++ b/source/c_adc.c @@ -41,9 +41,9 @@ int adc_initialized = 0; BBIO_err initialize_adc(void) { #ifdef BBBVERSION41 - char test_path[49]; + char test_path[149]; #else - char test_path[40]; + char test_path[140]; #endif FILE *fh; BBIO_err err; @@ -94,10 +94,10 @@ BBIO_err read_value(unsigned int ain, float *value) { FILE * fh; #ifdef BBBVERSION41 - char ain_path[49]; + char ain_path[149]; snprintf(ain_path, sizeof(ain_path), "%s%d_raw", adc_prefix_dir, ain); #else - char ain_path[40]; + char ain_path[140]; snprintf(ain_path, sizeof(ain_path), "%s%d", adc_prefix_dir, ain); #endif diff --git a/source/c_pwm.c b/source/c_pwm.c index e1f917e..f03e1bd 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -119,7 +119,7 @@ BBIO_err initialize_pwm(void) BBIO_err pwm_set_frequency(const char *key, float freq) { int len; - char buffer[20]; + char buffer[100]; unsigned long period_ns; struct pwm_exp *pwm; @@ -195,7 +195,7 @@ BBIO_err pwm_set_frequency(const char *key, float freq) { // Only works before chip is enabled BBIO_err pwm_set_polarity(const char *key, int polarity) { int len; - char buffer[9]; /* allow room for trailing NUL byte */ + char buffer[100]; /* allow room for trailing NUL byte */ struct pwm_exp *pwm; #ifdef BBBVERSION41 int enabled; /* Maintain original state */ @@ -275,7 +275,7 @@ BBIO_err pwm_set_polarity(const char *key, int polarity) { BBIO_err pwm_set_duty_cycle(const char *key, float duty) { int len; - char buffer[20]; + char buffer[100]; struct pwm_exp *pwm; if (duty < 0.0 || duty > 100.0) @@ -309,17 +309,17 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri struct pwm_exp *new_pwm; #ifdef BBBVERSION41 - char pwm_dev_path[45]; // "/sys/devices/platform/ocp/48300000.epwmss" - char pwm_addr_path[60]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm" - char pwm_chip_path[75]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0" - char pwm_export_path[80]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/export" - char pwm_path[85]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm1" - char pwm_path_udev[85]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm-0:1" - char ecap_path_udev[85];// "/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0/pwm-0:0/" - char duty_path[95]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm1/duty_cycle" - char period_path[95]; - char polarity_path[95]; - char enable_path[90]; + char pwm_dev_path[100]; // "/sys/devices/platform/ocp/48300000.epwmss" + char pwm_addr_path[150]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm" + char pwm_chip_path[200]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0" + char pwm_export_path[250]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/export" + char pwm_path[250]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm2" + char pwm_path_udev[250]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm-0:2" + char ecap_path_udev[300]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ecap/pwm/pwmchip0/pwm-0:0/" + char duty_path[300]; // "/sys/devices/platform/ocp/48300000.epwmss/48300200.ehrpwm/pwm/pwmchip0/pwm2/duty_cycle" + char period_path[300]; + char polarity_path[300]; + char enable_path[300]; char pin_mode[PIN_MODE_LEN]; // "pwm" or "pwm2" int e; @@ -400,7 +400,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path_udev: %s", key, pwm_path_udev); //ecap output with udev patch - snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, pwm_path[67], p->index); + snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, ecap_path_udev: %s", key, ecap_path_udev); // Export PWM if hasn't already been @@ -456,11 +456,11 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri return BBIO_GEN; } } else { - strncpy(pwm_path, ecap_path_udev, sizeof(ecap_path_udev)); + strncpy(pwm_path, ecap_path_udev, sizeof(pwm_path)); } } } else { - strncpy(pwm_path, pwm_path_udev, sizeof(pwm_path_udev)); + strncpy(pwm_path, pwm_path_udev, sizeof(pwm_path)); usleep(100*1000); } } @@ -470,12 +470,12 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri snprintf(duty_path, sizeof(duty_path), "%s/duty_cycle", pwm_path); snprintf(enable_path, sizeof(enable_path), "%s/enable", pwm_path); #else - char fragment[18]; - char pwm_fragment[20]; - char pwm_path[45]; - char duty_path[56]; - char period_path[50]; - char polarity_path[55]; + char fragment[100]; + char pwm_fragment[100]; + char pwm_path[100]; + char duty_path[200]; + char period_path[100]; + char polarity_path[100]; int period_fd, duty_fd, polarity_fd; if (!pwm_initialized) { @@ -590,7 +590,7 @@ BBIO_err pwm_start(const char *key, float duty, float freq, int polarity) //fprintf(stderr, "Adafruit_BBIO: pwm_start: %s, %f, %f, %i\n", key, duty, freq, polarity); BBIO_err err; - char buffer[20]; + char buffer[100]; ssize_t len; struct pwm_exp *pwm = lookup_exported_pwm(key); @@ -694,7 +694,7 @@ BBIO_err pwm_disable(const char *key) #ifndef BBBVERSION41 BBIO_err err; - char fragment[18]; + char fragment[100]; snprintf(fragment, sizeof(fragment), "bone_pwm_%s", key); err = unload_device_tree(fragment); if (err != BBIO_OK) @@ -709,7 +709,7 @@ BBIO_err pwm_disable(const char *key) { #ifdef BBBVERSION41 - char buffer[2]; + char buffer[100]; size_t len; // Disable the PWM From eca84d64d7a2d23e5e287246740918914454705f Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 11 Dec 2019 09:06:12 +0000 Subject: [PATCH 129/157] Fix warning about casting incompatible function types #308 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Debian 10 (Buster) has gcc 8.2 which warns about: cast between incompatible function types from ‘PyObject * (*)(PyObject *, PyObject *, PyObject *)’ The solution is to cast to '(PyCFunction)(void *)' --- source/spimodule.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/spimodule.c b/source/spimodule.c index 3b94109..7e438bd 100644 --- a/source/spimodule.c +++ b/source/spimodule.c @@ -777,17 +777,17 @@ PyDoc_STRVAR(SPI_type_doc, "specified SPI device interface.\n"); static PyMethodDef SPI_methods[] = { - {"open", (PyCFunction)SPI_open, METH_VARARGS | METH_KEYWORDS, + {"open", (PyCFunction)(void *)SPI_open, METH_VARARGS | METH_KEYWORDS, SPI_open_doc}, - {"close", (PyCFunction)SPI_close, METH_NOARGS, + {"close", (PyCFunction)(void *)SPI_close, METH_NOARGS, SPI_close_doc}, - {"readbytes", (PyCFunction)SPI_readbytes, METH_VARARGS, + {"readbytes", (PyCFunction)(void *)SPI_readbytes, METH_VARARGS, SPI_read_doc}, - {"writebytes", (PyCFunction)SPI_writebytes, METH_VARARGS, + {"writebytes", (PyCFunction)(void *)SPI_writebytes, METH_VARARGS, SPI_write_doc}, - {"xfer", (PyCFunction)SPI_xfer, METH_VARARGS, + {"xfer", (PyCFunction)(void *)SPI_xfer, METH_VARARGS, SPI_xfer_doc}, - {"xfer2", (PyCFunction)SPI_xfer2, METH_VARARGS, + {"xfer2", (PyCFunction)(void *)SPI_xfer2, METH_VARARGS, SPI_xfer2_doc}, {NULL}, }; From 1ca2830828466cb54cdfac9108592751a8e947de Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 17 Dec 2019 05:27:46 +0000 Subject: [PATCH 130/157] Update travis config to specify Python 3.6 Attempt to fix Travis error: https://travis-ci.com/adafruit/adafruit-beaglebone-io-python/builds/140636005 ``` 1.74s$ git clone --depth=50 --branch=issue308 https://github.com/adafruit/adafruit-beaglebone-io-python.git adafruit/adafruit-beaglebone-io-python 0.01s0.01s$ source ~/virtualenv/python3.6/bin/activate $ python --version Python 3.6.7 $ pip --version pip 19.0.3 from /home/travis/virtualenv/python3.6.7/lib/python3.6/site-packages/pip (python 3.6) install 1.54s$ pip install tox 5.96s$ tox GLOB sdist-make: /home/travis/build/adafruit/adafruit-beaglebone-io-python/setup.py py27 create: /home/travis/build/adafruit/adafruit-beaglebone-io-python/.tox/py27 py27 inst: /home/travis/build/adafruit/adafruit-beaglebone-io-python/.tox/.tmp/package/1/Adafruit_BBIO-1.1.1.zip py27 installed: Adafruit-BBIO==1.1.1 py27 run-test-pre: PYTHONHASHSEED='645938357' py27 run-test: commands[0] | echo 'run pytest on beaglebone' run pytest on beaglebone py34 create: /home/travis/build/adafruit/adafruit-beaglebone-io-python/.tox/py34 ERROR: InterpreterNotFound: python3.4 ___________________________________ summary ____________________________________ py27: commands succeeded ERROR: py34: InterpreterNotFound: python3.4 The command "tox" exited with 1. Done. Your build exited with 1. ``` --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index df3bb3e..f515d75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: python +python: + - "3.6" install: - pip install tox script: From 59dcd957557b7e619ccddb2a275aeee75167cfb8 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 17 Dec 2019 05:34:03 +0000 Subject: [PATCH 131/157] Update tox.ini to Python 3.6 Try to fix TravisCI error that Python 3.4 does not exist --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index abaae1f..084648a 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py34 +envlist = py27, py36 [testenv] commands = echo "run pytest on beaglebone" From bf3e6b5bf032a919a6c9edf3a999a7dfa1cd7614 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 3 Feb 2020 02:21:49 +0100 Subject: [PATCH 132/157] Update ISSUE_TEMPLATE.md --- .github/ISSUE_TEMPLATE.md | 50 +++++++-------------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6344b2f..2916315 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,47 +1,13 @@ -Thank you for opening an issue on an Adafruit Python library repository. To -improve the speed of resolution please review the following guidelines and -common troubleshooting steps below before creating the issue: +Thank you for opening an issue on the Adafruit BeagleBone Python library repository. -- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use - the forums at http://forums.adafruit.com to ask questions and troubleshoot why - something isn't working as expected. In many cases the problem is a common issue - that you will more quickly receive help from the forum community. GitHub issues - are meant for known defects in the code. If you don't know if there is a defect - in the code then start with troubleshooting on the forum first. -- **If following a tutorial or guide be sure you didn't miss a step.** Carefully - check all of the steps and commands to run have been followed. Consult the - forum if you're unsure or have questions about steps in a guide/tutorial. +In order to understand your system configuration better, please run: +``` +sudo /opt/scripts/tools/version.sh +``` -- **For Python/Raspberry Pi projects check these very common issues to ensure they don't apply**: +and paste the output in a reply. - - If you are receiving an **ImportError: No module named...** error then a - library the code depends on is not installed. Check the tutorial/guide or - README to ensure you have installed the necessary libraries. Usually the - missing library can be installed with the `pip` tool, but check the tutorial/guide - for the exact command. +This script should be present for any image downloaded from: +https://beagleboard.org/ or https://rcn-ee.com/ - - **Be sure you are supplying adequate power to the board.** Check the specs of - your board and power in an external power supply. In many cases just - plugging a board into your computer is not enough to power it and other - peripherals. - - - **Double check all soldering joints and connections.** Flakey connections - cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. - -If you're sure this issue is a defect in the code and checked the steps above -please fill in the following fields to provide enough troubleshooting information. -You may delete the guideline and text above to just leave the following details: - -- Platform/operating system (i.e. Raspberry Pi with Raspbian operating system, - Windows 32-bit, Windows 64-bit, Mac OSX 64-bit, etc.): **INSERT PLATFORM/OPERATING - SYSTEM HERE** - -- Python version (run `python -version` or `python3 -version`): **INSERT PYTHON - VERSION HERE** - -- Error message you are receiving, including any Python exception traces: **INSERT - ERROR MESAGE/EXCEPTION TRACES HERE*** - -- List the steps to reproduce the problem below (if possible attach code or commands - to run): **LIST REPRO STEPS BELOW** From dd6de40ba0f84cae98cf88aa4819857c9249d9af Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 3 Feb 2020 02:25:02 +0100 Subject: [PATCH 133/157] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index cc179c2..d2bf405 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,18 @@ sudo pytest ``` NOTE: `sudo` should not be required when running [Debian 9.2 "Stretch" iot (2017-10-29)](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#microSD.2FStandalone:_.28stretch-iot.29_.28All_BeagleBone_Variants_.26_PocketBeagle.29) with [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29) as udev configures group ownership and permission for [GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) +## Reporting issues + +When reporting issues, plesae run the following script which will print the system configuration: +``` +sudo /opt/scripts/tools/version.sh +``` +and paste the output in a reply. + +This script should be present for any Debian or Ubunut image downloaded from: +https://beagleboard.org/ or https://rcn-ee.com/ + + ## Credits The BeagleBone IO Python library was originally forked from the excellent MIT Licensed [RPi.GPIO](https://code.google.com/p/raspberry-gpio-python) library written by Ben Croston. From bd4745da78919f8d10a535ad567d0967dcc26e78 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Mon, 3 Feb 2020 02:27:44 +0100 Subject: [PATCH 134/157] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d2bf405..7c3f591 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart), [SPI](README.md#spi) and [eQEP](README.md#eqep) (Quadrature Encoder) hardware access from Python applications running on the Beaglebone. * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) - * **Currently recommended image: [Debian 9.4 "Stretch" IoT (2018-06-17)](http://debian.beagleboard.org/images/bone-debian-9.4-iot-armhf-2018-06-17-4gb.img.xz)** - * Install [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29) to enable [non-root control of GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) [_(commit)_](https://github.com/adafruit/adafruit-beaglebone-io-python/commit/b65cbf8e41b444bad7c4ef6cfd4f88a30210fd78) + * **Currently recommended image: [Debian 9.9 "Stretch" IoT (2019-08-03)](https://debian.beagleboard.org/images/am57xx-debian-9.9-lxqt-armhf-2019-08-03-4gb.img.xz)** + * Install [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29), or newer, to enable [non-root control of GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) [_(commit)_](https://github.com/adafruit/adafruit-beaglebone-io-python/commit/b65cbf8e41b444bad7c4ef6cfd4f88a30210fd78) * Adafruit_BBIO supports Linux kernels 3.8 through 4.14 From 0be8cb523197c6053253b55ce1bf1a46b80f417f Mon Sep 17 00:00:00 2001 From: Daniel Nguyen <44187178+zer0cod3r@users.noreply.github.com> Date: Sat, 7 Mar 2020 14:15:49 -0800 Subject: [PATCH 135/157] Update common.c Added UART4 to Pocketbeagle --- source/common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/common.c b/source/common.c index cd03bd9..e135601 100644 --- a/source/common.c +++ b/source/common.c @@ -271,6 +271,8 @@ pins_t table[] = { // P2_09 uart1_txd // P1_08 uart2_rxd // P1_10 uart2_txd +// P2_05 uart4_rxd +// P2_07 uart4_txd uart_t uart_table[] = { { "UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P9_26", "P9_24"}, @@ -281,6 +283,7 @@ uart_t uart_table[] = { { "PB-UART0", "/dev/ttyO0", "ADAFRUIT-UART0", "P1_30", "P1_32"}, { "PB-UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P2_11", "P2_09"}, { "PB-UART2", "/dev/ttyO2", "ADAFRUIT-UART2", "P1_08", "P1_10"}, + "PB-UART4", "/dev/ttyO4", "ADAFRUIT-UART4", "P2_05", "P2_07"}, { NULL, NULL, 0, 0, 0 } }; From 61c29a1ecd6206e2657793a1bed048ea6a95b01d Mon Sep 17 00:00:00 2001 From: Daniel Nguyen <44187178+zer0cod3r@users.noreply.github.com> Date: Sat, 7 Mar 2020 14:19:39 -0800 Subject: [PATCH 136/157] Update common.c --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index e135601..393cdeb 100644 --- a/source/common.c +++ b/source/common.c @@ -283,7 +283,7 @@ uart_t uart_table[] = { { "PB-UART0", "/dev/ttyO0", "ADAFRUIT-UART0", "P1_30", "P1_32"}, { "PB-UART1", "/dev/ttyO1", "ADAFRUIT-UART1", "P2_11", "P2_09"}, { "PB-UART2", "/dev/ttyO2", "ADAFRUIT-UART2", "P1_08", "P1_10"}, - "PB-UART4", "/dev/ttyO4", "ADAFRUIT-UART4", "P2_05", "P2_07"}, + { "PB-UART4", "/dev/ttyO4", "ADAFRUIT-UART4", "P2_05", "P2_07"}, { NULL, NULL, 0, 0, 0 } }; From 40f1160ac34f1dcc745ea57a7820410d11149c80 Mon Sep 17 00:00:00 2001 From: Sam Povilus Date: Thu, 2 Jul 2020 19:54:43 -0600 Subject: [PATCH 137/157] fixing document locaiton and version as current location dosn't load --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index 393cdeb..1027bed 100644 --- a/source/common.c +++ b/source/common.c @@ -289,7 +289,7 @@ uart_t uart_table[] = { // Copied from https://github.com/jadonk/bonescript/blob/master/src/bone.js // See am335x technical manual, p. 183, for more info: -// http://www.ti.com/lit/ug/spruh73n/spruh73n.pdf +// https://www.ti.com/lit/ug/spruh73q/spruh73q.pdf pwm_t pwm_table[] = { { "ehrpwm2", 6, 1, 4, "ehrpwm.2:1", "EHRPWM2B", "48304000", "48304200", "P8_13"}, { "ehrpwm2", 5, 0, 4, "ehrpwm.2:0", "EHRPWM2A", "48304000", "48304200", "P8_19"}, From c70c9bad971bd4194aa29f51b73675deabb8220c Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 10:36:03 -0400 Subject: [PATCH 138/157] Add dmtimer PWM entries in table for PocketBeagle --- source/common.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/common.c b/source/common.c index 1027bed..f66968c 100644 --- a/source/common.c +++ b/source/common.c @@ -311,6 +311,11 @@ pwm_t pwm_table[] = { { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_33"}, { "ehrpwm1", 3, 0, 6, "ehrpwm.1:0", "EHRPWM1A", "48302000", "48302200", "P2_1"}, { "ehrpwm2", 6, 1, 3, "ehrpwm.2:1", "EHRPWM2B", "48304000", "48304200", "P2_3"}, + { "timer7", 0, 0, 4, "", "", "", "", "P1_20" }, + { "timer6", 0, 0, 1, "", "", "", "", "P1_26" }, + { "timer5", 0, 0, 1, "", "", "", "", "P1_28" }, + { "timer7", 0, 0, 5, "", "", "", "", "P2_27" }, + { "timer4", 0, 0, 2, "", "", "", "", "P2_31" }, { NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } }; From 0f9f472e36cb20b19bc3c3e238768bf5c4f76b63 Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 11:50:20 -0400 Subject: [PATCH 139/157] Add is_dmtimer_pin function --- source/c_pwm.c | 11 +++++++++++ source/common.c | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index f03e1bd..1e00eae 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -94,6 +94,17 @@ void export_pwm(struct pwm_exp *new_pwm) } } +int is_dmtimer_pin(pwm_t *p) { + if(strlen(p->module) < 5) + return 0; + + char temp[6]; + strncpy(temp, p->module, 5); + temp[5] = '\0'; + + return (strcmp(temp, "timer") == 0); +} + BBIO_err initialize_pwm(void) { #ifdef BBBVERSION41 // don't load overlay in 4.1+ diff --git a/source/common.c b/source/common.c index f66968c..a5964cf 100644 --- a/source/common.c +++ b/source/common.c @@ -206,15 +206,15 @@ pins_t table[] = { { "VREFN", "P1_17", 0, -1, -1}, { "VREFP", "P1_18", 0, -1, -1}, { "AIN0", "P1_19", 0, -1, 0}, - { "GPIO0_20", "P1_20", 20, -1, -1}, + { "GPIO0_20", "P1_20", 20, 4, -1}, { "AIN1", "P1_21", 0, -1, 1}, { "GND", "P1_22", 0, -1, -1}, { "AIN2", "P1_23", 0, -1, 2}, { "VOUT-5V", "P1_24", 0, -1, -1}, { "AIN3", "P1_25", 0, -1, 3}, - { "I2C2_SDA", "P1_26", 12, -1, -1}, + { "I2C2_SDA", "P1_26", 12, 1, -1}, { "AIN4", "P1_27", 0, -1, 4}, - { "I2C2_SCL", "P1_28", 13, -1, -1}, + { "I2C2_SCL", "P1_28", 13, 1, -1}, { "GPIO3_21", "P1_29", 117, -1, -1}, { "UART0_TXD", "P1_30", 43, -1, -1}, { "GPIO3_18", "P1_31", 114, -1, -1}, @@ -249,11 +249,11 @@ pins_t table[] = { { "GPIO1_12", "P2_24", 44, -1, -1}, { "SPI1_CS0", "P2_25", 41, -1, -1}, { "RESET#", "P2_26", 0, -1, -1}, - { "SPI1_D0", "P2_27", 40, -1, -1}, + { "SPI1_D0", "P2_27", 40, 5, -1}, { "GPIO3_20", "P2_28", 116, -1, -1}, { "SPI1_SCLK", "P2_29", 7, -1, -1}, { "GPIO3_17", "P2_30", 113, -1, -1}, - { "SPI1_CS1", "P2_31", 19, -1, -1}, + { "SPI1_CS1", "P2_31", 19, 2, -1}, { "GPIO3_16", "P2_32", 112, -1, -1}, { "GPIO1_13", "P2_33", 45, -1, -1}, { "GPIO3_19", "P2_34", 115, -1, -1}, From 4149f2d4bc5f2254e10e898e59f9df17848526bc Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 12:16:49 -0400 Subject: [PATCH 140/157] Change path for dmtimer PWM pins --- source/c_pwm.c | 27 ++++++++++++++++++--------- source/common.c | 10 +++++----- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 1e00eae..fd09490 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -386,16 +386,25 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri return err; } - err = build_path(ocp_dir, p->chip, pwm_dev_path, sizeof(pwm_dev_path)); - if (err != BBIO_OK) { - syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_dev_path: %i", key, err); - return err; - } + if(!is_dmtimer_pin(p)) { + err = build_path(ocp_dir, p->chip, pwm_dev_path, sizeof(pwm_dev_path)); + if (err != BBIO_OK) { + syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_dev_path: %i", key, err); + return err; + } - err = build_path(pwm_dev_path, p->addr, pwm_addr_path, sizeof(pwm_addr_path)); - if (err != BBIO_OK) { - syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_addr_path: %i", key, err); - return err; + err = build_path(pwm_dev_path, p->addr, pwm_addr_path, sizeof(pwm_addr_path)); + if (err != BBIO_OK) { + syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_addr_path: %i", key, err); + return err; + } + } + else { + err = build_path("/sys/devices/platform", p->addr, pwm_addr_path, sizeof(pwm_addr_path)); + if (err != BBIO_OK) { + syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_addr_path: %i", key, err); + return err; + } } err = build_path(pwm_addr_path, "pwm/pwmchip", pwm_chip_path, sizeof(pwm_chip_path)); diff --git a/source/common.c b/source/common.c index a5964cf..7c3c3c3 100644 --- a/source/common.c +++ b/source/common.c @@ -311,11 +311,11 @@ pwm_t pwm_table[] = { { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_33"}, { "ehrpwm1", 3, 0, 6, "ehrpwm.1:0", "EHRPWM1A", "48302000", "48302200", "P2_1"}, { "ehrpwm2", 6, 1, 3, "ehrpwm.2:1", "EHRPWM2B", "48304000", "48304200", "P2_3"}, - { "timer7", 0, 0, 4, "", "", "", "", "P1_20" }, - { "timer6", 0, 0, 1, "", "", "", "", "P1_26" }, - { "timer5", 0, 0, 1, "", "", "", "", "P1_28" }, - { "timer7", 0, 0, 5, "", "", "", "", "P2_27" }, - { "timer4", 0, 0, 2, "", "", "", "", "P2_31" }, + { "timer7", 0, 0, 4, "", "", "", "dmtimer-pwm-7", "P1_20" }, + { "timer6", 0, 0, 1, "", "", "", "dmtimer-pwm-6", "P1_26" }, + { "timer5", 0, 0, 1, "", "", "", "dmtimer-pwm-5", "P1_28" }, + { "timer7", 0, 0, 5, "", "", "", "dmtimer-pwm-7", "P2_27" }, + { "timer4", 0, 0, 2, "", "", "", "dmtimer-pwm-4", "P2_31" }, { NULL, 0, 0, 0, NULL, NULL, NULL, NULL, NULL } }; From dcdb1adae9470b022d8af3ba56dd0e1b9969826d Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 13:50:37 -0400 Subject: [PATCH 141/157] Improve error logging --- source/c_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index fd09490..22ed809 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -402,7 +402,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri else { err = build_path("/sys/devices/platform", p->addr, pwm_addr_path, sizeof(pwm_addr_path)); if (err != BBIO_OK) { - syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_addr_path: %i", key, err); + syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_addr_path, are you sure you've loaded the correct dmtimer device tree overlay?: %i", key, err); return err; } } From 1151dd9a8c0b3bda56b6f5a7f86dbcae924a5f9e Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 14:05:10 -0400 Subject: [PATCH 142/157] Add dmtimer PWM entries in table for BBB --- source/common.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source/common.c b/source/common.c index 7c3c3c3..44c8aa1 100644 --- a/source/common.c +++ b/source/common.c @@ -81,10 +81,10 @@ pins_t table[] = { { "GPIO1_7", "P8_4", 39, -1, -1}, { "GPIO1_2", "P8_5", 34, -1, -1}, { "GPIO1_3", "P8_6", 35, -1, -1}, - { "TIMER4", "P8_7", 66, -1, -1}, - { "TIMER7", "P8_8", 67, -1, -1}, - { "TIMER5", "P8_9", 69, -1, -1}, - { "TIMER6", "P8_10", 68, -1, -1}, + { "TIMER4", "P8_7", 66, 2, -1}, + { "TIMER7", "P8_8", 67, 2, -1}, + { "TIMER5", "P8_9", 69, 2, -1}, + { "TIMER6", "P8_10", 68, 2, -1}, { "GPIO1_13", "P8_11", 45, -1, -1}, { "GPIO1_12", "P8_12", 44, -1, -1}, { "EHRPWM2B", "P8_13", 23, 4, -1}, @@ -305,6 +305,10 @@ pwm_t pwm_table[] = { { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P9_29"}, { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P9_31"}, { "ecap0", 2, 0, 0, "ecap.0", "ECAPPWM0", "48300000", "48300100", "P9_42"}, + { "timer4", 0, 0, 2, "", "", "", "dmtimer-pwm-4", "P8_7" }, + { "timer7", 0, 0, 2, "", "", "", "dmtimer-pwm-7", "P8_8" }, + { "timer5", 0, 0, 2, "", "", "", "dmtimer-pwm-5", "P8_9" }, + { "timer6", 0, 0, 2, "", "", "", "dmtimer-pwm-6", "P8_10" } { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_8"}, { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_36"}, { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_10"}, From 1c012a42eda220108aab3515fb6f30449db592c2 Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 14:58:03 -0400 Subject: [PATCH 143/157] Add missing comma --- source/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common.c b/source/common.c index 44c8aa1..f911d49 100644 --- a/source/common.c +++ b/source/common.c @@ -308,7 +308,7 @@ pwm_t pwm_table[] = { { "timer4", 0, 0, 2, "", "", "", "dmtimer-pwm-4", "P8_7" }, { "timer7", 0, 0, 2, "", "", "", "dmtimer-pwm-7", "P8_8" }, { "timer5", 0, 0, 2, "", "", "", "dmtimer-pwm-5", "P8_9" }, - { "timer6", 0, 0, 2, "", "", "", "dmtimer-pwm-6", "P8_10" } + { "timer6", 0, 0, 2, "", "", "", "dmtimer-pwm-6", "P8_10" }, { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_8"}, { "ehrpwm0", 0, 0, 1, "ehrpwm.0:0", "EHRPWM0A", "48300000", "48300200", "P1_36"}, { "ehrpwm0", 1, 1, 1, "ehrpwm.0:1", "EHRPWM0B", "48300000", "48300200", "P1_10"}, From 928e8dc499c61f26f5428d2e1ab0dcae4d2967be Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Wed, 22 Jul 2020 15:25:24 -0400 Subject: [PATCH 144/157] Add udev PWM path for DMTimer pins --- source/c_pwm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 22ed809..4b40a72 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -386,7 +386,9 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri return err; } - if(!is_dmtimer_pin(p)) { + int dmtimer_pin = is_dmtimer_pin(p); + + if(!dmtimer_pin) { err = build_path(ocp_dir, p->chip, pwm_dev_path, sizeof(pwm_dev_path)); if (err != BBIO_OK) { syslog(LOG_ERR, "Adafruit_BBIO: pwm_setup: %s couldn't build pwm_dev_path: %i", key, err); @@ -417,10 +419,10 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path: %s", key, pwm_path); //pwm with udev patch - snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, pwm_path[66], p->index); + snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? p->module[5] : pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path_udev: %s", key, pwm_path_udev); //ecap output with udev patch - snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, pwm_path[66], p->index); + snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? p->module[5] : pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, ecap_path_udev: %s", key, ecap_path_udev); // Export PWM if hasn't already been From db0adf258cb3d73c51a1cbb6ae76cbc43ac3c522 Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Thu, 23 Jul 2020 12:01:49 -0400 Subject: [PATCH 145/157] Fix udev PWM path for DMTimer pins --- source/c_pwm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 4b40a72..117a607 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -419,10 +419,10 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path: %s", key, pwm_path); //pwm with udev patch - snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? p->module[5] : pwm_path[66], p->index); + snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? pwm_path[47] : pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path_udev: %s", key, pwm_path_udev); //ecap output with udev patch - snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? p->module[5] : pwm_path[66], p->index); + snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? pwm_path[47] : pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, ecap_path_udev: %s", key, ecap_path_udev); // Export PWM if hasn't already been From af9ea512e8aa7508d03109de6c7e5b8bfe739e2b Mon Sep 17 00:00:00 2001 From: Darren Schachter Date: Fri, 24 Jul 2020 10:45:40 -0400 Subject: [PATCH 146/157] Remove unnecessary conditional --- source/c_pwm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 117a607..1756e5f 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -94,10 +94,7 @@ void export_pwm(struct pwm_exp *new_pwm) } } -int is_dmtimer_pin(pwm_t *p) { - if(strlen(p->module) < 5) - return 0; - +int is_dmtimer_pin(pwm_t *p) { char temp[6]; strncpy(temp, p->module, 5); temp[5] = '\0'; From 536783c5334a14c5c14eada03a0d05884e48659a Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 10:41:33 -0500 Subject: [PATCH 147/157] Update README.md change link to current Debian image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c3f591..6711e1b 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart), [SPI](README.md#spi) and [eQEP](README.md#eqep) (Quadrature Encoder) hardware access from Python applications running on the Beaglebone. * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) - * **Currently recommended image: [Debian 9.9 "Stretch" IoT (2019-08-03)](https://debian.beagleboard.org/images/am57xx-debian-9.9-lxqt-armhf-2019-08-03-4gb.img.xz)** + * **Currently recommended image: [Debian 10.3 "Buster" IoT (2020-04-06)](http://beagleboard.org/latest-images)** * Install [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29), or newer, to enable [non-root control of GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) [_(commit)_](https://github.com/adafruit/adafruit-beaglebone-io-python/commit/b65cbf8e41b444bad7c4ef6cfd4f88a30210fd78) * Adafruit_BBIO supports Linux kernels 3.8 through 4.14 From c25f27a51d7932ba0a5c45311bde006ce6e760ee Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 10:44:16 -0500 Subject: [PATCH 148/157] Update README.md Change the kernel versions --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6711e1b..da76ee2 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@ Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md#pwm), [ADC](README.md#adc), [UART](README.md#uart), [SPI](README.md#spi) and [eQEP](README.md#eqep) (Quadrature Encoder) hardware access from Python applications running on the Beaglebone. * It is recommended to use an [official BeagleBoard.org Debian image](https://beagleboard.org/latest-images) - * **Currently recommended image: [Debian 10.3 "Buster" IoT (2020-04-06)](http://beagleboard.org/latest-images)** - * Install [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29), or newer, to enable [non-root control of GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) [_(commit)_](https://github.com/adafruit/adafruit-beaglebone-io-python/commit/b65cbf8e41b444bad7c4ef6cfd4f88a30210fd78) + * **Currently recommended image: [Debian 10.3 "Buster" IoT (2020-04-06)](http://beagleboard.org/latest-images)** _(default kernel is 4.19.x-ti)_ -* Adafruit_BBIO supports Linux kernels 3.8 through 4.14 +* Adafruit_BBIO supports Linux kernels 3.8 through 4.19 * New versions of Adafruit_BBIO may break backwards compatibility. Please read the [changelog](CHANGELOG.md). From 50fe27e928a9f959c0cd33e83218e5425e3de826 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 10:57:43 -0500 Subject: [PATCH 149/157] Update README.md update installation instructions to use python3 --- README.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index da76ee2..fba6863 100644 --- a/README.md +++ b/README.md @@ -13,29 +13,31 @@ Adafruit BBIO is an API to enable [GPIO](README.md#gpio-setup), [PWM](README.md# * New versions of Adafruit_BBIO may break backwards compatibility. Please read the [changelog](CHANGELOG.md). +* It is recommended to use Python 3 + ## Installation on Debian -Easiest: +Note: Follow the instructions on BeagleBoard.org to [get connected to the Internet](https://beagleboard.org/upgrade#connect) + +**Easiest:** ``` -sudo ntpdate pool.ntp.org sudo apt-get update -sudo apt-get install build-essential python-dev python-pip -y -sudo pip install Adafruit_BBIO +sudo apt-get install build-essential python3-dev python3-pip -y +sudo pip3 install Adafruit_BBIO ``` -Manual: +**Manual:** ``` -sudo ntpdate pool.ntp.org sudo apt-get update -sudo apt-get install build-essential python-dev python-pip -y +sudo apt-get install build-essential python3-dev python3-pip -y git clone git://github.com/adafruit/adafruit-beaglebone-io-python.git cd adafruit-beaglebone-io-python -sudo python setup.py install +sudo python3 setup.py install ``` Upgrade Adafruit_BBIO to latest version on [PyPI](https://pypi.python.org/pypi/Adafruit_BBIO): ``` -sudo pip install --upgrade Adafruit_BBIO +sudo pip3 install --upgrade Adafruit_BBIO ``` ## Usage @@ -264,13 +266,13 @@ To use the enhanced Quadrature Encoder Pulse (eQEP) module, please refer to the Install py.test to run the tests. You'll also need the python compiler package for pytest: ``` -sudo pip install pytest +sudo pip3 install pytest ``` Execute the following in the root of the project: ``` -sudo pytest +pytest ``` -NOTE: `sudo` should not be required when running [Debian 9.2 "Stretch" iot (2017-10-29)](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#microSD.2FStandalone:_.28stretch-iot.29_.28All_BeagleBone_Variants_.26_PocketBeagle.29) with [Linux kernel](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Kernel_Options) [4.14.x](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#Mainline_.284.14.x_lts.29) as udev configures group ownership and permission for [GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) +NOTE: `sudo` should not be required as udev configures group ownership and permission for [GPIO](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/80-gpio-noroot.rules) and [PWM](https://github.com/rcn-ee/repos/blob/master/bb-customizations/suite/stretch/debian/81-pwm-noroot.rules) ## Reporting issues From 24a617aecf7cee89d0b62452c86b899e2c02e51b Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 14:06:32 -0500 Subject: [PATCH 150/157] remove -Werror from CFLAGS In issue #335, @mvduin noted that it is a poor idea to have compilation fail on warnings because a newer compiler version may add new warnings and as a result break compilation. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fd63bd8..455f7b3 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ else: kernel41 = None -CFLAGS = ['-Wall', '-Werror', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing' ] +CFLAGS = ['-Wall', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing' ] classifiers = ['Development Status :: 3 - Alpha', 'Operating System :: POSIX :: Linux', From 8ba2f122a977ffff217467a0f0ac3abc1d92f5b5 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 14:21:47 -0500 Subject: [PATCH 151/157] Remove suppression of gcc warnings in CFLAGS #336 CFLAGS is only -Wall now. -Werror has been removed to the build will no longer fail on warnings. Therefore, there is no need to suppress certain warnings. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 455f7b3..81c98e9 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ else: kernel41 = None -CFLAGS = ['-Wall', '-Wextra', '-Wno-missing-field-initializers', '-Wno-strict-aliasing' ] +CFLAGS = ['-Wall'] classifiers = ['Development Status :: 3 - Alpha', 'Operating System :: POSIX :: Linux', From 1b2eb9d19dbf3f23aa33d225213c9c606461613a Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 15:34:41 -0500 Subject: [PATCH 152/157] Update version in setup.py to v1.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 81c98e9..184d71e 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ } setup(name = 'Adafruit_BBIO', - version = '1.1.1', + version = '1.2.0', author = 'Justin Cooper', author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', From d3bae3c1ab3cde1b489de7fe2e7448a3a177e53c Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Wed, 29 Jul 2020 21:37:42 -0500 Subject: [PATCH 153/157] update CHANGELOG --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3895c2..4f9325e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ +1.1.2 +--- +Daniel Nguyen (2): + Update common.c + Update common.c + +Drew Fustini (28): + upload to PyPI againt to resolve #293 + do not set pinmux on the beaglebone blue + remove deug output + Fix dead link to bone.js #296 + force Encoder period to be an integer #299 + Ignore new compiler warnings in gcc 8.2.0 + Update setup.py + do not set pin mode for built-in USRn LEDs + Change name of P1_3 to match bone.js + Fix warning about casting incompatible function types #308 + Fix warning print format strings being truncated #308 + Fix warning about casting incompatible function types #308 + Fix warnings on format truncation and sizeof in strncpy #308 + Fix warning about casting incompatible function types #308 + Update travis config to specify Python 3.6 + Update tox.ini to Python 3.6 + Merge pull request #321 from adafruit/issue308 + Update ISSUE_TEMPLATE.md + Update README.md + Update README.md + Merge pull request #327 from zer0cod3r/master + Merge pull request #337 from SamPovilus/docfix + Update README.md + Update README.md + Update README.md + remove -Werror from CFLAGS + Remove suppression of gcc warnings in CFLAGS #336 + Update version in setup.py to v1.2 + +Sam Povilus (1): + fixing document locaiton and version as current location dosn't load + 1.1.1 --- Attempt upload to PyPI again to avoid From dbecfcddad4399b8f0f51ad105a4572fa76e4261 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Thu, 30 Jul 2020 21:26:13 -0500 Subject: [PATCH 154/157] add long_description_content_type to satisfy pypi Refer to https://packaging.python.org/guides/making-a-pypi-friendly-readme/ --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 184d71e..a6f5891 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ author_email = 'justin@adafruit.com', description = 'A module to control BeagleBone IO channels', long_description = open_as_utf8('README.md').read() + open_as_utf8('CHANGELOG.md').read(), + long_description_content_type = 'text/markdown', license = 'MIT', keywords = 'Adafruit BeagleBone IO GPIO PWM ADC', url = 'https://github.com/adafruit/adafruit-beaglebone-io-python/', From be710eaf9bbcd232cc627e7a3e7073fdc47fb9ac Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 28 Nov 2020 00:03:09 +0100 Subject: [PATCH 155/157] fix link error due multiple variables definitions Building with GCC 10.2.1 fails due linking errors caused by having multiple definitions of the variables defined in the source/constants.h header file. Fix this by moving the variables definition to the source/constants.c file, to avoid the variables to be defined each time that the header is included. While being there, use a single variable instead of having one for each object that is added to the module. --- source/constants.c | 50 ++++++++++++++++++++++++---------------------- source/constants.h | 13 ------------ 2 files changed, 26 insertions(+), 37 deletions(-) diff --git a/source/constants.c b/source/constants.c index 5e284c8..23753c6 100644 --- a/source/constants.c +++ b/source/constants.c @@ -35,39 +35,41 @@ SOFTWARE. void define_constants(PyObject *module) { - high = Py_BuildValue("i", HIGH); - PyModule_AddObject(module, "HIGH", high); + PyObject *object; - low = Py_BuildValue("i", LOW); - PyModule_AddObject(module, "LOW", low); + object = Py_BuildValue("i", HIGH); + PyModule_AddObject(module, "HIGH", object); - output = Py_BuildValue("i", OUTPUT); - PyModule_AddObject(module, "OUT", output); + object = Py_BuildValue("i", LOW); + PyModule_AddObject(module, "LOW", object); - input = Py_BuildValue("i", INPUT); - PyModule_AddObject(module, "IN", input); + object = Py_BuildValue("i", OUTPUT); + PyModule_AddObject(module, "OUT", object); - alt0 = Py_BuildValue("i", ALT0); - PyModule_AddObject(module, "ALT0", alt0); + object = Py_BuildValue("i", INPUT); + PyModule_AddObject(module, "IN", object); - pud_off = Py_BuildValue("i", PUD_OFF); - PyModule_AddObject(module, "PUD_OFF", pud_off); + object = Py_BuildValue("i", ALT0); + PyModule_AddObject(module, "ALT0", object); - pud_up = Py_BuildValue("i", PUD_UP); - PyModule_AddObject(module, "PUD_UP", pud_up); + object = Py_BuildValue("i", PUD_OFF); + PyModule_AddObject(module, "PUD_OFF", object); - pud_down = Py_BuildValue("i", PUD_DOWN); - PyModule_AddObject(module, "PUD_DOWN", pud_down); + object = Py_BuildValue("i", PUD_UP); + PyModule_AddObject(module, "PUD_UP", object); + + object = Py_BuildValue("i", PUD_DOWN); + PyModule_AddObject(module, "PUD_DOWN", object); - rising_edge = Py_BuildValue("i", RISING_EDGE); - PyModule_AddObject(module, "RISING", rising_edge); + object = Py_BuildValue("i", RISING_EDGE); + PyModule_AddObject(module, "RISING", object); - falling_edge = Py_BuildValue("i", FALLING_EDGE); - PyModule_AddObject(module, "FALLING", falling_edge); + object = Py_BuildValue("i", FALLING_EDGE); + PyModule_AddObject(module, "FALLING", object); - both_edge = Py_BuildValue("i", BOTH_EDGE); - PyModule_AddObject(module, "BOTH", both_edge); + object = Py_BuildValue("i", BOTH_EDGE); + PyModule_AddObject(module, "BOTH", object); - version = Py_BuildValue("s", "0.0.20"); - PyModule_AddObject(module, "VERSION", version); + object = Py_BuildValue("s", "0.0.20"); + PyModule_AddObject(module, "VERSION", object); } diff --git a/source/constants.h b/source/constants.h index 0f6fdf5..82ebe5e 100644 --- a/source/constants.h +++ b/source/constants.h @@ -1,19 +1,6 @@ #ifndef CONSTANTS_H #define CONSTANTS_H -PyObject *high; -PyObject *low; -PyObject *input; -PyObject *output; -PyObject *alt0; -PyObject *pud_off; -PyObject *pud_up; -PyObject *pud_down; -PyObject *rising_edge; -PyObject *falling_edge; -PyObject *both_edge; -PyObject *version; - void define_constants(PyObject *module); #endif From fe2e30a8a622de66a98b88ee307d6ed459fc4f85 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sun, 24 Jan 2021 22:09:43 -0800 Subject: [PATCH 156/157] Fix pwm output for ecap pins P9_28 and P9_42 #342 PWM outputs on P9_28 and P9_42 are part of the ECAP hardware block. This causes 'ecap' to be in the path instead of 'pwm'. For example: `/sys/devices/platform/ocp/48300000.epwmss/48300100.ecap/pwm/pwmchip0/pwm0` is one character longer than: `/sys/devices/platform/ocp/48302000.epwmss/48302200.pwm/pwm/pwmchip4/pwm0` Thus the index in pwm_path must be adjusted for the ecap_path_udev path. This fixes issue #342 --- source/c_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 1756e5f..a5ef5ec 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -419,7 +419,7 @@ BBIO_err pwm_setup(const char *key, __attribute__ ((unused)) float duty, __attri snprintf(pwm_path_udev, sizeof(pwm_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? pwm_path[47] : pwm_path[66], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, pwm_path_udev: %s", key, pwm_path_udev); //ecap output with udev patch - snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? pwm_path[47] : pwm_path[66], p->index); + snprintf(ecap_path_udev, sizeof(ecap_path_udev), "%s/pwm-%c:%d", pwm_chip_path, dmtimer_pin ? pwm_path[47] : pwm_path[67], p->index); syslog(LOG_DEBUG, "Adafruit_BBIO: pwm_start: key: %s, ecap_path_udev: %s", key, ecap_path_udev); // Export PWM if hasn't already been From 57e630c1552ba12688995d4e201df6073002bea8 Mon Sep 17 00:00:00 2001 From: omerk Date: Sat, 22 Apr 2023 23:15:33 +0100 Subject: [PATCH 157/157] fix compilation for newer versions of Python PyEval_ThreadsInitialized() and PyEval_InitThreads() are deprecated and break the build, adding a version check to ignore if we are compiling with a newer Python version. --- source/py_gpio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/py_gpio.c b/source/py_gpio.c index 2721cca..99cb0e7 100644 --- a/source/py_gpio.c +++ b/source/py_gpio.c @@ -599,8 +599,10 @@ PyMODINIT_FUNC initGPIO(void) initlog(LOG_INFO, NULL, BBIO_LOG_OPTION); +#if PY_VERSION_HEX < 0x03090000 if (!PyEval_ThreadsInitialized()) PyEval_InitThreads(); +#endif if (Py_AtExit(event_cleanup) != 0) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy