diff --git a/DOC/dbase/lg.sqlite b/DOC/dbase/lg.sqlite index ffbdf7b..fd05e93 100644 Binary files a/DOC/dbase/lg.sqlite and b/DOC/dbase/lg.sqlite differ diff --git a/DOC/src/defs/examples.def b/DOC/src/defs/examples.def index 6567d1f..2e639ac 100644 --- a/DOC/src/defs/examples.def +++ b/DOC/src/defs/examples.def @@ -58,6 +58,17 @@ E.g. ./rotary_encoder 2 7 5 # gpiochip 2, gpioA 7, gpioB 5 +?4|sonar_ranger.c|2020-11-20|Sonar Ranger +Code to find the distance between a sonar ranger and the nearest object. The code assumes the sonar ranger is the type with separate trigger and echo lines. + +./sonar_ranger [chip] trigger echo + +E.g. + +./sonar_ranger 20 21 # gpiochip 0, trigger 20, echo 21 + +./sonar_ranger 2 7 5 # gpiochip 2, trigger 7, echo 5 + ?4|tx_pulse.c|2020-11-18|Tx Pulse Demonstrates usage of the tx pulse function. @@ -107,6 +118,17 @@ E.g. ./rotary_encoder.py 2 7 5 # gpiochip 2, gpioA 7, gpioB 5 +?4|sonar_ranger.py|2020-11-20|Sonar Ranger +Code to find the distance between a sonar ranger and the nearest object. The code assumes the sonar ranger is the type with separate trigger and echo lines. + +./sonar_ranger.py [chip] trigger echo + +E.g. + +./sonar_ranger.py 20 21 # gpiochip 0, trigger 20, echo 21 + +./sonar_ranger.py 2 7 5 # gpiochip 2, trigger 7, echo 5 + ?4|testbed.py|2020-11-18|Testbed Exercises SPI, I2C, and serial links with miscellaneous hardware. @@ -171,6 +193,16 @@ E.g. ./rotary_encoder 2 7 5 # gpiochip 2, gpioA 7, gpioB 5 +?4|sonar_ranger.c|2020-11-20|Sonar Ranger +Code to find the distance between a sonar ranger and the nearest object. The code assumes the sonar ranger is the type with separate trigger and echo lines. + +./sonar_ranger [chip] trigger echo + +E.g. + +./sonar_ranger 20 21 # gpiochip 0, trigger 20, echo 21 + +./sonar_ranger 2 7 5 # gpiochip 2, trigger 7, echo 5 ?4|tx_pulse.c|2020-11-18|Tx Pulse Demonstrates usage of the tx pulse function. @@ -231,6 +263,17 @@ E.g. ./rotary_encoder.py 2 7 5 # gpiochip 2, gpioA 7, gpioB 5 +?4|sonar_ranger.py|2020-11-20|Sonar Ranger +Code to find the distance between a sonar ranger and the nearest object. The code assumes the sonar ranger is the type with separate trigger and echo lines. + +./sonar_ranger.py [chip] trigger echo + +E.g. + +./sonar_ranger.py 20 21 # gpiochip 0, trigger 20, echo 21 + +./sonar_ranger.py 2 7 5 # gpiochip 2, trigger 7, echo 5 + ?4|testbed.py|2020-11-18|Testbed Exercises SPI, I2C, and serial links with miscellaneous hardware. diff --git a/EXAMPLES/lgpio/chipline.c b/EXAMPLES/lgpio/chipline.c index 120d8f0..94e8be4 100644 --- a/EXAMPLES/lgpio/chipline.c +++ b/EXAMPLES/lgpio/chipline.c @@ -1,13 +1,13 @@ /* -bench.c +chipline.c 2020-11-18 Public Domain http://abyz.me.uk/lg/lgpio.html -gcc -Wall -o bench bench.c -llgpio +gcc -Wall -o chipline chipline.c -llgpio -./bench +./chipline */ #include diff --git a/EXAMPLES/lgpio/sonar_ranger.c b/EXAMPLES/lgpio/sonar_ranger.c new file mode 100644 index 0000000..eb7110e --- /dev/null +++ b/EXAMPLES/lgpio/sonar_ranger.c @@ -0,0 +1,140 @@ +/* +sonar_ranger.c +2020-11-20 +Public Domain + +http://abyz.me.uk/lg/lgpio.html + +gcc -Wall -o sonar_ranger sonar_ranger.c -llgpio + +./sonar_ranger [chip] trigger echo + +E.g. + +./sonar_ranger 20 21 # ping gpiochip 0, trigger 20, echo 21 + +./sonar_ranger 2 7 5 # gpiochip 2, trigger 7, echo 5 +*/ + +#include +#include + +#include + +int pinged = 0; +uint64_t ping_time; + +void cbf(int e, lgGpioAlert_p evt, void *userdata) +{ + int i; + static uint64_t _high = 0; + + for (i=0; i 0.3) return 0.0; + lguSleep(0.01); + } + + return 17015.0 * ping_time / 1e9; +} + +int main(int argc, char *argv[]) +{ + int h; + int chip, trigger, echo; + int cb_echo; + int err; + + if (argc == 4) /* chip trigger echo */ + { + chip = atoi(argv[1]); + trigger = atoi(argv[2]); + echo = atoi(argv[3]); + } + + else if (argc == 3) /* trigger echo (chip 0) */ + { + chip = 0; + trigger = atoi(argv[1]); + echo = atoi(argv[2]); + } + + else + { + fprintf(stderr, "Usage: ./sonar_ranger [chip] trigger echo\n"); + return -1; + } + + h = lgGpiochipOpen(chip); + + if (h < 0) + { + fprintf(stderr, "can't open /dev/gpiochip%d (%s)\n", + chip, lgErrStr(h)); + return -1; + } + + err = lgGpioClaimOutput(h, 0, trigger, 0); + + if (err < 0) + { + fprintf(stderr, "can't claim GPIO %d (%s)\n", + trigger, lgErrStr(err)); + return -1; + } + + err = lgGpioClaimAlert(h, 0, LG_BOTH_EDGES, echo, -1); + + if (err < 0) + { + fprintf(stderr, "can't claim GPIO %d (%s)\n", + echo, lgErrStr(err)); + return -1; + } + + err = lgGpioSetAlertsFunc(h, echo, cbf, NULL); + + if (err < 0) + { + fprintf(stderr, "can't create callback for GPIO %d (%s)\n", + echo, lgErrStr(cb_echo)); + return -1; + } + + while (1) + { + printf("cms=%.1f\n", readRanger(h, trigger)); + lguSleep(0.2); + } +} + diff --git a/EXAMPLES/py_lgpio/sonar_ranger.py b/EXAMPLES/py_lgpio/sonar_ranger.py new file mode 100644 index 0000000..a78d3c0 --- /dev/null +++ b/EXAMPLES/py_lgpio/sonar_ranger.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +""" +sonar_ranger.py +2020-11-20 +Public Domain + +http://abyz.me.uk/lg/py_rgpio.html + +./sonar_ranger.py [chip] trigger echo + +chip specifies a gpiochip number. gpio is a GPIO in the previous +gpiochip (gpiochip0 if there is no previous gpiochip). + +e.g. + +./sonar_ranger.py 1 24 25 # ping gpiochip1: trigger 24, echo 25 +./sonar_ranger.py 24 25 # ping gpiochip0: trigger 24, echo 25 +""" + +import time +import lgpio + +class ranger: + """ + This class encapsulates a type of acoustic ranger. In particular + the type of ranger with separate trigger and echo pins. + + A pulse on the trigger initiates the sonar ping and shortly + afterwards a sonar pulse is transmitted and the echo pin + goes high. The echo pins stays high until a sonar echo is + received (or the response times-out). The time between + the high and low edges indicates the sonar round trip time. + """ + + def __init__(self, sbc, chip, trigger, echo): + """ + The class is instantiated with the SBC to use, the gpiochip, + and the GPIO connected to the trigger and echo pins. + """ + self._sbc = sbc + self._chip = chip + self._trigger = trigger + self._echo = echo + + self._ping = False + self._high = None + self._time = None + + self._handle = sbc.gpiochip_open(chip) + + sbc.gpio_claim_output(self._handle, trigger) + + sbc.gpio_claim_alert(self._handle, echo, sbc.BOTH_EDGES) + + self._cb = sbc.callback(self._handle, echo, sbc.BOTH_EDGES, self._cbf) + + self._inited = True + + def _cbf(self, chip, gpio, level, tick): + if level == 1: + self._high = tick + else: + if self._high is not None: + self._time = tick - self._high + self._high = None + self._ping = True + + def read(self): + """ + Return the distance in cms if okay, otherwise 0. + """ + if self._inited: + self._ping = False + # send a 15 microsecond high pulse as trigger + self._sbc.tx_pulse(self._handle, self._trigger, 15, 0, 0, 1) + start = time.time() + while not self._ping: + if (time.time()-start) > 0.3: + return 0 + time.sleep(0.01) + return 17015 * self._time / 1e9 + else: + return None + + def cancel(self): + """ + Cancels the ranger and returns the gpios to their + original mode. + """ + if self._inited: + self._inited = False + self._cb.cancel() + self._sbc.gpio_free(self._chip, self._trigger) + self._sbc.gpio_free(self._chip, self._echo) + self._sbc.gpiochip_close(self._chip) +if __name__ == "__main__": + + import sys + import time + import lgpio as sbc + import sonar_ranger + + if len(sys.argv) == 4: # chip trigger echo + chip = int(sys.argv[1]) + trigger = int(sys.argv[2]) + echo = int(sys.argv[3]) + + elif len(sys.argv) == 3: # trigger echo (chip 0) + chip = 0 + trigger = int(sys.argv[1]) + echo = int(sys.argv[2]) + + else: + print("Usage: ./sonar_ranger.py [chip] trigger echo") + exit() + + ranger = sonar_ranger.ranger(sbc, chip, trigger, echo) + + try: + while True: + print("cms={:.1f}".format(ranger.read())) + time.sleep(0.2) + except KeyboardInterrupt: + pass + + ranger.cancel() + diff --git a/EXAMPLES/py_rgpio/sonar_ranger.py b/EXAMPLES/py_rgpio/sonar_ranger.py new file mode 100755 index 0000000..75bada9 --- /dev/null +++ b/EXAMPLES/py_rgpio/sonar_ranger.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +""" +sonar_ranger.py +2020-11-20 +Public Domain + +http://abyz.me.uk/lg/py_rgpio.html + +./sonar_ranger.py [chip] trigger echo + +chip specifies a gpiochip number. gpio is a GPIO in the previous +gpiochip (gpiochip0 if there is no previous gpiochip). + +e.g. + +./sonar_ranger.py 1 24 25 # ping gpiochip1: trigger 24, echo 25 +./sonar_ranger.py 24 25 # ping gpiochip0: trigger 24, echo 25 +""" + +import time +import rgpio + +class ranger: + """ + This class encapsulates a type of acoustic ranger. In particular + the type of ranger with separate trigger and echo pins. + + A pulse on the trigger initiates the sonar ping and shortly + afterwards a sonar pulse is transmitted and the echo pin + goes high. The echo pins stays high until a sonar echo is + received (or the response times-out). The time between + the high and low edges indicates the sonar round trip time. + """ + + def __init__(self, sbc, chip, trigger, echo): + """ + The class is instantiated with the SBC to use, the gpiochip, + and the GPIO connected to the trigger and echo pins. + """ + self._sbc = sbc + self._chip = chip + self._trigger = trigger + self._echo = echo + + self._ping = False + self._high = None + self._time = None + + self._handle = sbc.gpiochip_open(chip) + + sbc.gpio_claim_output(self._handle, trigger) + + sbc.gpio_claim_alert(self._handle, echo, rgpio.BOTH_EDGES) + + self._cb = sbc.callback(self._handle, echo, rgpio.BOTH_EDGES, self._cbf) + + self._inited = True + + def _cbf(self, chip, gpio, level, tick): + if level == 1: + self._high = tick + else: + if self._high is not None: + self._time = tick - self._high + self._high = None + self._ping = True + + def read(self): + """ + Return the distance in cms if okay, otherwise 0. + """ + if self._inited: + self._ping = False + # send a 15 microsecond high pulse as trigger + self._sbc.tx_pulse(self._handle, self._trigger, 15, 0, 0, 1) + start = time.time() + while not self._ping: + if (time.time()-start) > 0.3: + return 0 + time.sleep(0.01) + return 17015 * self._time / 1e9 + else: + return None + + def cancel(self): + """ + Cancels the ranger and returns the gpios to their + original mode. + """ + if self._inited: + self._inited = False + self._cb.cancel() + self._sbc.gpio_free(self._chip, self._trigger) + self._sbc.gpio_free(self._chip, self._echo) + self._sbc.gpiochip_close(self._chip) +if __name__ == "__main__": + + import sys + import time + import rgpio + import sonar_ranger + + sbc = rgpio.sbc() + if not sbc.connected: + exit() + + if len(sys.argv) == 4: # chip trigger echo + chip = int(sys.argv[1]) + trigger = int(sys.argv[2]) + echo = int(sys.argv[3]) + + elif len(sys.argv) == 3: # trigger echo (chip 0) + chip = 0 + trigger = int(sys.argv[1]) + echo = int(sys.argv[2]) + + else: + print("Usage: ./sonar_ranger.py [chip] trigger echo") + exit() + + ranger = sonar_ranger.ranger(sbc, chip, trigger, echo) + + try: + while True: + print("cms={:.1f}".format(ranger.read())) + time.sleep(0.2) + except KeyboardInterrupt: + pass + + ranger.cancel() + + sbc.stop() + diff --git a/EXAMPLES/rgpio/sonar_ranger.c b/EXAMPLES/rgpio/sonar_ranger.c new file mode 100644 index 0000000..50cb643 --- /dev/null +++ b/EXAMPLES/rgpio/sonar_ranger.c @@ -0,0 +1,148 @@ +/* +sonar_ranger.c +2020-11-20 +Public Domain + +http://abyz.me.uk/lg/rgpio.html + +gcc -Wall -o sonar_ranger sonar_ranger.c -lrgpio + +./sonar_ranger [chip] trigger echo + +E.g. + +./sonar_ranger 20 21 # ping gpiochip 0, trigger 20, echo 21 + +./sonar_ranger 2 7 5 # gpiochip 2, trigger 7, echo 5 +*/ + +#include +#include + +#include +#include + +int pinged = 0; +uint64_t ping_time; + +void cbf( + int sbc, int chip, int gpio, int level, + uint64_t timestamp, void *userdata) +{ + static uint64_t _high = 0; + + if (level == 1) _high = timestamp; + else + { + if (_high != 0) + { + ping_time = timestamp - _high; + _high = 0; + pinged = 1; + } + } +} + +float read_ranger(int sbc, int h, int trigger) +{ + double start; + + /* + Return the distance in cms if okay, otherwise 0. + */ + + pinged = 0; + + /* send a 15 microsecond high pulse as trigger */ + tx_pulse(sbc, h, trigger, 15, 0, 0, 1); + + start = lgu_time(); + + while (!pinged) + { + if ((lgu_time() - start) > 0.3) return 0.0; + lgu_sleep(0.01); + } + + return 17015.0 * ping_time / 1e9; +} + +int main(int argc, char *argv[]) +{ + int sbc; + int h; + int chip, trigger, echo; + int cb_echo; + int err; + + if (argc == 4) /* chip trigger echo */ + { + chip = atoi(argv[1]); + trigger = atoi(argv[2]); + echo = atoi(argv[3]); + } + + else if (argc == 3) /* trigger echo (chip 0) */ + { + chip = 0; + trigger = atoi(argv[1]); + echo = atoi(argv[2]); + } + + else + { + fprintf(stderr, "Usage: ./sonar_ranger [chip] trigger echo\n"); + return -1; + } + + sbc = rgpiod_start(NULL, NULL); + + if (sbc < 0) + { + printf("connection failed\n"); + exit(-1); + } + + h = gpiochip_open(sbc, chip); + + if (h < 0) + { + fprintf(stderr, "can't open /dev/gpiochip%d (%s)\n", + chip, lgu_error_text(h)); + return -1; + } + + err = gpio_claim_output(sbc, h, 0, trigger, 0); + + if (err < 0) + { + fprintf(stderr, "can't claim GPIO %d (%s)\n", + trigger, lgu_error_text(err)); + return -1; + } + + err = gpio_claim_alert(sbc, h, 0, LG_BOTH_EDGES, echo, -1); + + if (err < 0) + { + fprintf(stderr, "can't claim GPIO %d (%s)\n", + echo, lgu_error_text(err)); + return -1; + } + + cb_echo = callback(sbc, h, echo, LG_BOTH_EDGES, cbf, NULL); + + if (cb_echo < 0) + { + fprintf(stderr, "can't create callback for GPIO %d (%s)\n", + echo, lgu_error_text(cb_echo)); + return -1; + } + + while (1) + { + printf("cms=%.1f\n", read_ranger(sbc, h, trigger)); + lgu_sleep(0.2); + } +} + diff --git a/v0.0.4.2 b/v0.0.4.3 similarity index 100% rename from v0.0.4.2 rename to v0.0.4.3