From 45378d4e910b0373e46a8c2f2c8d5929bb8ba701 Mon Sep 17 00:00:00 2001 From: Benjamin Tayehanpour Date: Sat, 26 Sep 2026 09:27:56 +0000 Subject: [PATCH] asyncpio --- kladd/asyncpio.py | 5902 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5902 insertions(+) create mode 100644 kladd/asyncpio.py diff --git a/kladd/asyncpio.py b/kladd/asyncpio.py new file mode 100644 index 0000000..18d98d7 --- /dev/null +++ b/kladd/asyncpio.py @@ -0,0 +1,5902 @@ +""" +asyncpio is a Python module for the Raspberry which talks to +the pigpio daemon to allow control of the general purpose +input outputs (GPIO). + +[http://abyz.me.uk/rpi/pigpio/python.html] + +*Features* + +o the pigpio Python module can run on Windows, Macs, or Linux + +o controls one or more Pi's + +o hardware timed PWM on any of GPIO 0-31 + +o hardware timed servo pulses on any of GPIO 0-31 + +o callbacks when any of GPIO 0-31 change state + +o creating and transmitting precisely timed waveforms + +o reading/writing GPIO and setting their modes + +o wrappers for I2C, SPI, and serial links + +o creating and running scripts on the pigpio daemon + +*GPIO* + +ALL GPIO are identified by their Broadcom number. + +*Notes* + +Transmitted waveforms are accurate to a microsecond. + +Callback level changes are time-stamped and will be +accurate to within a few microseconds. + +*Settings* + +A number of settings are determined when the pigpio daemon is started. + +o the sample rate (1, 2, 4, 5, 8, or 10 us, default 5 us). + +o the set of GPIO which may be updated (generally written to). The + default set is those available on the Pi board revision. + +o the available PWM frequencies (see [*set_PWM_frequency*]). + +*Exceptions* + +By default a fatal exception is raised if you pass an invalid +argument to a pigpio function. + +If you wish to handle the returned status yourself you should set +asyncpio.exceptions to False. + +You may prefer to check the returned status in only a few parts +of your code. In that case do the following: + +... +asyncpio.exceptions = False + +# Code where you want to test the error status. + +asyncpio.exceptions = True +... + +*Usage* + +This module uses the services of the C pigpio library. pigpio +must be running on the Pi(s) whose GPIO are to be manipulated. + +The normal way to start pigpio is as a daemon (during system +start). + +sudo pigpiod + +Your Python program must import asyncpio and create one or more +instances of the asyncpio.pi class. This class gives access to +a specified Pi's GPIO. + +... +pi1 = asyncpio.pi() +await pi1.connect() # pi1 accesses the local Pi's GPIO +pi2 = asyncpio.pi() +await pi2.connect('tom') # pi2 accesses tom's GPIO +pi3 = asyncpio.pi() +await pi3.connect('dick') # pi3 accesses dick's GPIO + +await pi1.write(4, 0) # set local Pi's GPIO 4 low +await pi2.write(4, 1) # set tom's GPIO 4 to high +await pi3.read(4) # get level of dick's GPIO 4 +... + +The later example code snippets assume that pi is an instance of +the asyncpio.pi class. + +OVERVIEW + +ESSENTIAL + +asyncpio.pi Initialise Pi connection +stop Stop a Pi connection + +BASIC + +set_mode Set a GPIO mode +get_mode Get a GPIO mode + +set_pull_up_down Set/clear GPIO pull up/down resistor + +read Read a GPIO +write Write a GPIO + +PWM_(overrides_servo_commands_on_same_GPIO) + +set_PWM_dutycycle Start/stop PWM pulses on a GPIO +set_PWM_frequency Set PWM frequency of a GPIO +set_PWM_range Configure PWM range of a GPIO + +get_PWM_dutycycle Get PWM dutycycle set on a GPIO +get_PWM_frequency Get PWM frequency of a GPIO +get_PWM_range Get configured PWM range of a GPIO + +get_PWM_real_range Get underlying PWM range for a GPIO + +Servo_(overrides_PWM_commands_on_same_GPIO) + +set_servo_pulsewidth Start/Stop servo pulses on a GPIO + +get_servo_pulsewidth Get servo pulsewidth set on a GPIO + +INTERMEDIATE + +gpio_trigger Send a trigger pulse to a GPIO + +set_watchdog Set a watchdog on a GPIO + +read_bank_1 Read all bank 1 GPIO +read_bank_2 Read all bank 2 GPIO + +clear_bank_1 Clear selected GPIO in bank 1 +clear_bank_2 Clear selected GPIO in bank 2 + +set_bank_1 Set selected GPIO in bank 1 +set_bank_2 Set selected GPIO in bank 2 + +callback Create GPIO level change callback + +wait_for_edge Wait for GPIO level change + +ADVANCED + +notify_open Request a notification handle +notify_begin Start notifications for selected GPIO +notify_pause Pause notifications +notify_close Close a notification + +hardware_clock Start hardware clock on supported GPIO + +hardware_PWM Start hardware PWM on supported GPIO + +set_glitch_filter Set a glitch filter on a GPIO +set_noise_filter Set a noise filter on a GPIO + +set_pad_strength Sets a pads drive strength +get_pad_strength Gets a pads drive strength + +shell Executes a shell command + +Custom + +custom_1 User custom function 1 +custom_2 User custom function 2 + +Events + +event_callback Sets a callback for an event + +event_trigger Triggers an event + +wait_for_event Wait for an event + +Scripts + +store_script Store a script +run_script Run a stored script +update_script Set a scripts parameters +script_status Get script status and parameters +stop_script Stop a running script +delete_script Delete a stored script + +I2C + +i2c_open Opens an I2C device +i2c_close Closes an I2C device + +i2c_write_quick SMBus write quick + +i2c_read_byte SMBus read byte +i2c_write_byte SMBus write byte + +i2c_read_byte_data SMBus read byte data +i2c_write_byte_data SMBus write byte data + +i2c_read_word_data SMBus read word data +i2c_write_word_data SMBus write word data + +i2c_read_block_data SMBus read block data +i2c_write_block_data SMBus write block data + +i2c_read_i2c_block_data SMBus read I2C block data +i2c_write_i2c_block_data SMBus write I2C block data + +i2c_read_device Reads the raw I2C device +i2c_write_device Writes the raw I2C device + +i2c_process_call SMBus process call +i2c_block_process_call SMBus block process call + +i2c_zip Performs multiple I2C transactions + +I2C_BIT_BANG + +bb_i2c_open Opens GPIO for bit banging I2C +bb_i2c_close Closes GPIO for bit banging I2C + +bb_i2c_zip Performs multiple bit banged I2C transactions + +I2C/SPI_SLAVE + +bsc_xfer I2C/SPI as slave transfer +bsc_i2c I2C as slave transfer + +SERIAL + +serial_open Opens a serial device +serial_close Closes a serial device + +serial_read_byte Reads a byte from a serial device +serial_write_byte Writes a byte to a serial device + +serial_read Reads bytes from a serial device +serial_write Writes bytes to a serial device + +serial_data_available Returns number of bytes ready to be read + +SERIAL_BIT_BANG_(read_only) + +bb_serial_read_open Open a GPIO for bit bang serial reads +bb_serial_read_close Close a GPIO for bit bang serial reads + +bb_serial_invert Invert serial logic (1 invert, 0 normal) + +bb_serial_read Read bit bang serial data from a GPIO + +SPI + +spi_open Opens a SPI device +spi_close Closes a SPI device + +spi_read Reads bytes from a SPI device +spi_write Writes bytes to a SPI device +spi_xfer Transfers bytes with a SPI device + +SPI_BIT_BANG + +bb_spi_open Opens GPIO for bit banging SPI +bb_spi_close Closes GPIO for bit banging SPI +bb_spi_xfer Transfers bytes with bit banging SPI + +FILES + +file_open Opens a file +file_close Closes a file + +file_read Reads bytes from a file +file_write Writes bytes to a file + +file_seek Seeks to a position within a file + +file_list List files which match a pattern + +WAVES + +wave_clear Deletes all waveforms + +wave_add_new Starts a new waveform +wave_add_generic Adds a series of pulses to the waveform +wave_add_serial Adds serial data to the waveform + +wave_create Creates a waveform from added data +wave_create_and_pad Creates a waveform of fixed size from added data +wave_delete Deletes a waveform + +wave_send_once Transmits a waveform once +wave_send_repeat Transmits a waveform repeatedly +wave_send_using_mode Transmits a waveform in the chosen mode + +wave_chain Transmits a chain of waveforms + +wave_tx_at Returns the current transmitting waveform + +wave_tx_busy Checks to see if a waveform has ended + +wave_tx_stop Aborts the current waveform + +wave_get_cbs Length in cbs of the current waveform +wave_get_max_cbs Absolute maximum allowed cbs + +wave_get_micros Length in microseconds of the current waveform +wave_get_max_micros Absolute maximum allowed micros + +wave_get_pulses Length in pulses of the current waveform +wave_get_max_pulses Absolute maximum allowed pulses + +UTILITIES + +get_current_tick Get current tick (microseconds) + +get_hardware_revision Get hardware revision +get_pigpio_version Get the pigpio version + +asyncpio.error_text Gets error text from error number +asyncpio.tickDiff Returns difference between two ticks +""" + +import sys +import socket +import struct +import asyncio +import os +import atexit + +__version__ = '0.78.0' # asyncpio version, sync minor number to pigpio version +VERSION = "1.78" # Upstream pigpio version. + +exceptions = True + +# GPIO levels + +OFF = 0 +LOW = 0 +CLEAR = 0 + +ON = 1 +HIGH = 1 +SET = 1 + +TIMEOUT = 2 + +# GPIO edges + +RISING_EDGE = 0 +FALLING_EDGE = 1 +EITHER_EDGE = 2 + +# GPIO modes + +INPUT = 0 +OUTPUT = 1 +ALT0 = 4 +ALT1 = 5 +ALT2 = 6 +ALT3 = 7 +ALT4 = 3 +ALT5 = 2 + +# GPIO Pull Up Down + +PUD_OFF = 0 +PUD_DOWN = 1 +PUD_UP = 2 + +# script run status + +PI_SCRIPT_INITING=0 +PI_SCRIPT_HALTED =1 +PI_SCRIPT_RUNNING=2 +PI_SCRIPT_WAITING=3 +PI_SCRIPT_FAILED =4 + +# notification flags + +NTFY_FLAGS_EVENT = (1 << 7) +NTFY_FLAGS_ALIVE = (1 << 6) +NTFY_FLAGS_WDOG = (1 << 5) +NTFY_FLAGS_GPIO = 31 + +# wave modes + +WAVE_MODE_ONE_SHOT =0 +WAVE_MODE_REPEAT =1 +WAVE_MODE_ONE_SHOT_SYNC=2 +WAVE_MODE_REPEAT_SYNC =3 + +WAVE_NOT_FOUND = 9998 # Transmitted wave not found. +NO_TX_WAVE = 9999 # No wave being transmitted. + +FILE_READ=1 +FILE_WRITE=2 +FILE_RW=3 + +FILE_APPEND=4 +FILE_CREATE=8 +FILE_TRUNC=16 + +FROM_START=0 +FROM_CURRENT=1 +FROM_END=2 + +SPI_MODE_0 = 0 +SPI_MODE_1 = 1 +SPI_MODE_2 = 2 +SPI_MODE_3 = 3 + +SPI_CPHA = 1 << 0 +SPI_CPOL = 1 << 1 + +SPI_CS_HIGH_ACTIVE = 1 << 2 + +SPI_TX_LSBFIRST = 1 << 14 +SPI_RX_LSBFIRST = 1 << 15 + +EVENT_BSC = 31 + +_SOCK_CMD_LEN = 16 + +# pigpio command numbers + +_PI_CMD_MODES= 0 +_PI_CMD_MODEG= 1 +_PI_CMD_PUD= 2 +_PI_CMD_READ= 3 +_PI_CMD_WRITE= 4 +_PI_CMD_PWM= 5 +_PI_CMD_PRS= 6 +_PI_CMD_PFS= 7 +_PI_CMD_SERVO= 8 +_PI_CMD_WDOG= 9 +_PI_CMD_BR1= 10 +_PI_CMD_BR2= 11 +_PI_CMD_BC1= 12 +_PI_CMD_BC2= 13 +_PI_CMD_BS1= 14 +_PI_CMD_BS2= 15 +_PI_CMD_TICK= 16 +_PI_CMD_HWVER=17 + +_PI_CMD_NO= 18 +_PI_CMD_NB= 19 +_PI_CMD_NP= 20 +_PI_CMD_NC= 21 + +_PI_CMD_PRG= 22 +_PI_CMD_PFG= 23 +_PI_CMD_PRRG= 24 +_PI_CMD_HELP= 25 +_PI_CMD_PIGPV=26 + +_PI_CMD_WVCLR=27 +_PI_CMD_WVAG= 28 +_PI_CMD_WVAS= 29 +_PI_CMD_WVGO= 30 +_PI_CMD_WVGOR=31 +_PI_CMD_WVBSY=32 +_PI_CMD_WVHLT=33 +_PI_CMD_WVSM= 34 +_PI_CMD_WVSP= 35 +_PI_CMD_WVSC= 36 + +_PI_CMD_TRIG= 37 + +_PI_CMD_PROC= 38 +_PI_CMD_PROCD=39 +_PI_CMD_PROCR=40 +_PI_CMD_PROCS=41 + +_PI_CMD_SLRO= 42 +_PI_CMD_SLR= 43 +_PI_CMD_SLRC= 44 + +_PI_CMD_PROCP=45 +_PI_CMD_MICRO=46 +_PI_CMD_MILLI=47 +_PI_CMD_PARSE=48 + +_PI_CMD_WVCRE=49 +_PI_CMD_WVDEL=50 +_PI_CMD_WVTX =51 +_PI_CMD_WVTXR=52 +_PI_CMD_WVNEW=53 + +_PI_CMD_I2CO =54 +_PI_CMD_I2CC =55 +_PI_CMD_I2CRD=56 +_PI_CMD_I2CWD=57 +_PI_CMD_I2CWQ=58 +_PI_CMD_I2CRS=59 +_PI_CMD_I2CWS=60 +_PI_CMD_I2CRB=61 +_PI_CMD_I2CWB=62 +_PI_CMD_I2CRW=63 +_PI_CMD_I2CWW=64 +_PI_CMD_I2CRK=65 +_PI_CMD_I2CWK=66 +_PI_CMD_I2CRI=67 +_PI_CMD_I2CWI=68 +_PI_CMD_I2CPC=69 +_PI_CMD_I2CPK=70 + +_PI_CMD_SPIO =71 +_PI_CMD_SPIC =72 +_PI_CMD_SPIR =73 +_PI_CMD_SPIW =74 +_PI_CMD_SPIX =75 + +_PI_CMD_SERO =76 +_PI_CMD_SERC =77 +_PI_CMD_SERRB=78 +_PI_CMD_SERWB=79 +_PI_CMD_SERR =80 +_PI_CMD_SERW =81 +_PI_CMD_SERDA=82 + +_PI_CMD_GDC =83 +_PI_CMD_GPW =84 + +_PI_CMD_HC =85 +_PI_CMD_HP =86 + +_PI_CMD_CF1 =87 +_PI_CMD_CF2 =88 + +_PI_CMD_NOIB =99 + +_PI_CMD_BI2CC=89 +_PI_CMD_BI2CO=90 +_PI_CMD_BI2CZ=91 + +_PI_CMD_I2CZ =92 + +_PI_CMD_WVCHA=93 + +_PI_CMD_SLRI =94 + +_PI_CMD_CGI =95 +_PI_CMD_CSI =96 + +_PI_CMD_FG =97 +_PI_CMD_FN =98 + +_PI_CMD_WVTXM=100 +_PI_CMD_WVTAT=101 + +_PI_CMD_PADS =102 +_PI_CMD_PADG =103 + +_PI_CMD_FO =104 +_PI_CMD_FC =105 +_PI_CMD_FR =106 +_PI_CMD_FW =107 +_PI_CMD_FS =108 +_PI_CMD_FL =109 +_PI_CMD_SHELL=110 + +_PI_CMD_BSPIC=111 +_PI_CMD_BSPIO=112 +_PI_CMD_BSPIX=113 + +_PI_CMD_BSCX =114 + +_PI_CMD_EVM =115 +_PI_CMD_EVT =116 + +_PI_CMD_PROCU=117 +_PI_CMD_WVCAP=118 + +# pigpio error numbers + +_PI_INIT_FAILED =-1 +PI_BAD_USER_GPIO =-2 +PI_BAD_GPIO =-3 +PI_BAD_MODE =-4 +PI_BAD_LEVEL =-5 +PI_BAD_PUD =-6 +PI_BAD_PULSEWIDTH =-7 +PI_BAD_DUTYCYCLE =-8 +_PI_BAD_TIMER =-9 +_PI_BAD_MS =-10 +_PI_BAD_TIMETYPE =-11 +_PI_BAD_SECONDS =-12 +_PI_BAD_MICROS =-13 +_PI_TIMER_FAILED =-14 +PI_BAD_WDOG_TIMEOUT =-15 +_PI_NO_ALERT_FUNC =-16 +_PI_BAD_CLK_PERIPH =-17 +_PI_BAD_CLK_SOURCE =-18 +_PI_BAD_CLK_MICROS =-19 +_PI_BAD_BUF_MILLIS =-20 +PI_BAD_DUTYRANGE =-21 +_PI_BAD_SIGNUM =-22 +_PI_BAD_PATHNAME =-23 +PI_NO_HANDLE =-24 +PI_BAD_HANDLE =-25 +_PI_BAD_IF_FLAGS =-26 +_PI_BAD_CHANNEL =-27 +_PI_BAD_PRIM_CHANNEL=-27 +_PI_BAD_SOCKET_PORT =-28 +_PI_BAD_FIFO_COMMAND=-29 +_PI_BAD_SECO_CHANNEL=-30 +_PI_NOT_INITIALISED =-31 +_PI_INITIALISED =-32 +_PI_BAD_WAVE_MODE =-33 +_PI_BAD_CFG_INTERNAL=-34 +PI_BAD_WAVE_BAUD =-35 +PI_TOO_MANY_PULSES =-36 +PI_TOO_MANY_CHARS =-37 +PI_NOT_SERIAL_GPIO =-38 +_PI_BAD_SERIAL_STRUC=-39 +_PI_BAD_SERIAL_BUF =-40 +PI_NOT_PERMITTED =-41 +PI_SOME_PERMITTED =-42 +PI_BAD_WVSC_COMMND =-43 +PI_BAD_WVSM_COMMND =-44 +PI_BAD_WVSP_COMMND =-45 +PI_BAD_PULSELEN =-46 +PI_BAD_SCRIPT =-47 +PI_BAD_SCRIPT_ID =-48 +PI_BAD_SER_OFFSET =-49 +PI_GPIO_IN_USE =-50 +PI_BAD_SERIAL_COUNT =-51 +PI_BAD_PARAM_NUM =-52 +PI_DUP_TAG =-53 +PI_TOO_MANY_TAGS =-54 +PI_BAD_SCRIPT_CMD =-55 +PI_BAD_VAR_NUM =-56 +PI_NO_SCRIPT_ROOM =-57 +PI_NO_MEMORY =-58 +PI_SOCK_READ_FAILED =-59 +PI_SOCK_WRIT_FAILED =-60 +PI_TOO_MANY_PARAM =-61 +PI_SCRIPT_NOT_READY =-62 +PI_BAD_TAG =-63 +PI_BAD_MICS_DELAY =-64 +PI_BAD_MILS_DELAY =-65 +PI_BAD_WAVE_ID =-66 +PI_TOO_MANY_CBS =-67 +PI_TOO_MANY_OOL =-68 +PI_EMPTY_WAVEFORM =-69 +PI_NO_WAVEFORM_ID =-70 +PI_I2C_OPEN_FAILED =-71 +PI_SER_OPEN_FAILED =-72 +PI_SPI_OPEN_FAILED =-73 +PI_BAD_I2C_BUS =-74 +PI_BAD_I2C_ADDR =-75 +PI_BAD_SPI_CHANNEL =-76 +PI_BAD_FLAGS =-77 +PI_BAD_SPI_SPEED =-78 +PI_BAD_SER_DEVICE =-79 +PI_BAD_SER_SPEED =-80 +PI_BAD_PARAM =-81 +PI_I2C_WRITE_FAILED =-82 +PI_I2C_READ_FAILED =-83 +PI_BAD_SPI_COUNT =-84 +PI_SER_WRITE_FAILED =-85 +PI_SER_READ_FAILED =-86 +PI_SER_READ_NO_DATA =-87 +PI_UNKNOWN_COMMAND =-88 +PI_SPI_XFER_FAILED =-89 +_PI_BAD_POINTER =-90 +PI_NO_AUX_SPI =-91 +PI_NOT_PWM_GPIO =-92 +PI_NOT_SERVO_GPIO =-93 +PI_NOT_HCLK_GPIO =-94 +PI_NOT_HPWM_GPIO =-95 +PI_BAD_HPWM_FREQ =-96 +PI_BAD_HPWM_DUTY =-97 +PI_BAD_HCLK_FREQ =-98 +PI_BAD_HCLK_PASS =-99 +PI_HPWM_ILLEGAL =-100 +PI_BAD_DATABITS =-101 +PI_BAD_STOPBITS =-102 +PI_MSG_TOOBIG =-103 +PI_BAD_MALLOC_MODE =-104 +_PI_TOO_MANY_SEGS =-105 +_PI_BAD_I2C_SEG =-106 +PI_BAD_SMBUS_CMD =-107 +PI_NOT_I2C_GPIO =-108 +PI_BAD_I2C_WLEN =-109 +PI_BAD_I2C_RLEN =-110 +PI_BAD_I2C_CMD =-111 +PI_BAD_I2C_BAUD =-112 +PI_CHAIN_LOOP_CNT =-113 +PI_BAD_CHAIN_LOOP =-114 +PI_CHAIN_COUNTER =-115 +PI_BAD_CHAIN_CMD =-116 +PI_BAD_CHAIN_DELAY =-117 +PI_CHAIN_NESTING =-118 +PI_CHAIN_TOO_BIG =-119 +PI_DEPRECATED =-120 +PI_BAD_SER_INVERT =-121 +_PI_BAD_EDGE =-122 +_PI_BAD_ISR_INIT =-123 +PI_BAD_FOREVER =-124 +PI_BAD_FILTER =-125 +PI_BAD_PAD =-126 +PI_BAD_STRENGTH =-127 +PI_FIL_OPEN_FAILED =-128 +PI_BAD_FILE_MODE =-129 +PI_BAD_FILE_FLAG =-130 +PI_BAD_FILE_READ =-131 +PI_BAD_FILE_WRITE =-132 +PI_FILE_NOT_ROPEN =-133 +PI_FILE_NOT_WOPEN =-134 +PI_BAD_FILE_SEEK =-135 +PI_NO_FILE_MATCH =-136 +PI_NO_FILE_ACCESS =-137 +PI_FILE_IS_A_DIR =-138 +PI_BAD_SHELL_STATUS =-139 +PI_BAD_SCRIPT_NAME =-140 +PI_BAD_SPI_BAUD =-141 +PI_NOT_SPI_GPIO =-142 +PI_BAD_EVENT_ID =-143 +PI_CMD_INTERRUPTED =-144 +PI_NOT_ON_BCM2711 =-145 +PI_ONLY_ON_BCM2711 =-146 + +# pigpio error text + +_errors=[ + [_PI_INIT_FAILED , "pigpio initialisation failed"], + [PI_BAD_USER_GPIO , "GPIO not 0-31"], + [PI_BAD_GPIO , "GPIO not 0-53"], + [PI_BAD_MODE , "mode not 0-7"], + [PI_BAD_LEVEL , "level not 0-1"], + [PI_BAD_PUD , "pud not 0-2"], + [PI_BAD_PULSEWIDTH , "pulsewidth not 0 or 500-2500"], + [PI_BAD_DUTYCYCLE , "dutycycle not 0-range (default 255)"], + [_PI_BAD_TIMER , "timer not 0-9"], + [_PI_BAD_MS , "ms not 10-60000"], + [_PI_BAD_TIMETYPE , "timetype not 0-1"], + [_PI_BAD_SECONDS , "seconds < 0"], + [_PI_BAD_MICROS , "micros not 0-999999"], + [_PI_TIMER_FAILED , "gpioSetTimerFunc failed"], + [PI_BAD_WDOG_TIMEOUT , "timeout not 0-60000"], + [_PI_NO_ALERT_FUNC , "DEPRECATED"], + [_PI_BAD_CLK_PERIPH , "clock peripheral not 0-1"], + [_PI_BAD_CLK_SOURCE , "DEPRECATED"], + [_PI_BAD_CLK_MICROS , "clock micros not 1, 2, 4, 5, 8, or 10"], + [_PI_BAD_BUF_MILLIS , "buf millis not 100-10000"], + [PI_BAD_DUTYRANGE , "dutycycle range not 25-40000"], + [_PI_BAD_SIGNUM , "signum not 0-63"], + [_PI_BAD_PATHNAME , "can't open pathname"], + [PI_NO_HANDLE , "no handle available"], + [PI_BAD_HANDLE , "unknown handle"], + [_PI_BAD_IF_FLAGS , "ifFlags > 4"], + [_PI_BAD_CHANNEL , "DMA channel not 0-14"], + [_PI_BAD_SOCKET_PORT , "socket port not 1024-30000"], + [_PI_BAD_FIFO_COMMAND , "unknown fifo command"], + [_PI_BAD_SECO_CHANNEL , "DMA secondary channel not 0-14"], + [_PI_NOT_INITIALISED , "function called before gpioInitialise"], + [_PI_INITIALISED , "function called after gpioInitialise"], + [_PI_BAD_WAVE_MODE , "waveform mode not 0-1"], + [_PI_BAD_CFG_INTERNAL , "bad parameter in gpioCfgInternals call"], + [PI_BAD_WAVE_BAUD , "baud rate not 50-250000(RX)/1000000(TX)"], + [PI_TOO_MANY_PULSES , "waveform has too many pulses"], + [PI_TOO_MANY_CHARS , "waveform has too many chars"], + [PI_NOT_SERIAL_GPIO , "no bit bang serial read in progress on GPIO"], + [PI_NOT_PERMITTED , "no permission to update GPIO"], + [PI_SOME_PERMITTED , "no permission to update one or more GPIO"], + [PI_BAD_WVSC_COMMND , "bad WVSC subcommand"], + [PI_BAD_WVSM_COMMND , "bad WVSM subcommand"], + [PI_BAD_WVSP_COMMND , "bad WVSP subcommand"], + [PI_BAD_PULSELEN , "trigger pulse length not 1-100"], + [PI_BAD_SCRIPT , "invalid script"], + [PI_BAD_SCRIPT_ID , "unknown script id"], + [PI_BAD_SER_OFFSET , "add serial data offset > 30 minute"], + [PI_GPIO_IN_USE , "GPIO already in use"], + [PI_BAD_SERIAL_COUNT , "must read at least a byte at a time"], + [PI_BAD_PARAM_NUM , "script parameter id not 0-9"], + [PI_DUP_TAG , "script has duplicate tag"], + [PI_TOO_MANY_TAGS , "script has too many tags"], + [PI_BAD_SCRIPT_CMD , "illegal script command"], + [PI_BAD_VAR_NUM , "script variable id not 0-149"], + [PI_NO_SCRIPT_ROOM , "no more room for scripts"], + [PI_NO_MEMORY , "can't allocate temporary memory"], + [PI_SOCK_READ_FAILED , "socket read failed"], + [PI_SOCK_WRIT_FAILED , "socket write failed"], + [PI_TOO_MANY_PARAM , "too many script parameters (> 10)"], + [PI_SCRIPT_NOT_READY , "script initialising"], + [PI_BAD_TAG , "script has unresolved tag"], + [PI_BAD_MICS_DELAY , "bad MICS delay (too large)"], + [PI_BAD_MILS_DELAY , "bad MILS delay (too large)"], + [PI_BAD_WAVE_ID , "non existent wave id"], + [PI_TOO_MANY_CBS , "No more CBs for waveform"], + [PI_TOO_MANY_OOL , "No more OOL for waveform"], + [PI_EMPTY_WAVEFORM , "attempt to create an empty waveform"], + [PI_NO_WAVEFORM_ID , "No more waveform ids"], + [PI_I2C_OPEN_FAILED , "can't open I2C device"], + [PI_SER_OPEN_FAILED , "can't open serial device"], + [PI_SPI_OPEN_FAILED , "can't open SPI device"], + [PI_BAD_I2C_BUS , "bad I2C bus"], + [PI_BAD_I2C_ADDR , "bad I2C address"], + [PI_BAD_SPI_CHANNEL , "bad SPI channel"], + [PI_BAD_FLAGS , "bad i2c/spi/ser open flags"], + [PI_BAD_SPI_SPEED , "bad SPI speed"], + [PI_BAD_SER_DEVICE , "bad serial device name"], + [PI_BAD_SER_SPEED , "bad serial baud rate"], + [PI_BAD_PARAM , "bad i2c/spi/ser parameter"], + [PI_I2C_WRITE_FAILED , "I2C write failed"], + [PI_I2C_READ_FAILED , "I2C read failed"], + [PI_BAD_SPI_COUNT , "bad SPI count"], + [PI_SER_WRITE_FAILED , "ser write failed"], + [PI_SER_READ_FAILED , "ser read failed"], + [PI_SER_READ_NO_DATA , "ser read no data available"], + [PI_UNKNOWN_COMMAND , "unknown command"], + [PI_SPI_XFER_FAILED , "SPI xfer/read/write failed"], + [_PI_BAD_POINTER , "bad (NULL) pointer"], + [PI_NO_AUX_SPI , "no auxiliary SPI on Pi A or B"], + [PI_NOT_PWM_GPIO , "GPIO is not in use for PWM"], + [PI_NOT_SERVO_GPIO , "GPIO is not in use for servo pulses"], + [PI_NOT_HCLK_GPIO , "GPIO has no hardware clock"], + [PI_NOT_HPWM_GPIO , "GPIO has no hardware PWM"], + [PI_BAD_HPWM_FREQ , "invalid hardware PWM frequency"], + [PI_BAD_HPWM_DUTY , "hardware PWM dutycycle not 0-1M"], + [PI_BAD_HCLK_FREQ , "invalid hardware clock frequency"], + [PI_BAD_HCLK_PASS , "need password to use hardware clock 1"], + [PI_HPWM_ILLEGAL , "illegal, PWM in use for main clock"], + [PI_BAD_DATABITS , "serial data bits not 1-32"], + [PI_BAD_STOPBITS , "serial (half) stop bits not 2-8"], + [PI_MSG_TOOBIG , "socket/pipe message too big"], + [PI_BAD_MALLOC_MODE , "bad memory allocation mode"], + [_PI_TOO_MANY_SEGS , "too many I2C transaction segments"], + [_PI_BAD_I2C_SEG , "an I2C transaction segment failed"], + [PI_BAD_SMBUS_CMD , "SMBus command not supported"], + [PI_NOT_I2C_GPIO , "no bit bang I2C in progress on GPIO"], + [PI_BAD_I2C_WLEN , "bad I2C write length"], + [PI_BAD_I2C_RLEN , "bad I2C read length"], + [PI_BAD_I2C_CMD , "bad I2C command"], + [PI_BAD_I2C_BAUD , "bad I2C baud rate, not 50-500k"], + [PI_CHAIN_LOOP_CNT , "bad chain loop count"], + [PI_BAD_CHAIN_LOOP , "empty chain loop"], + [PI_CHAIN_COUNTER , "too many chain counters"], + [PI_BAD_CHAIN_CMD , "bad chain command"], + [PI_BAD_CHAIN_DELAY , "bad chain delay micros"], + [PI_CHAIN_NESTING , "chain counters nested too deeply"], + [PI_CHAIN_TOO_BIG , "chain is too long"], + [PI_DEPRECATED , "deprecated function removed"], + [PI_BAD_SER_INVERT , "bit bang serial invert not 0 or 1"], + [_PI_BAD_EDGE , "bad ISR edge value, not 0-2"], + [_PI_BAD_ISR_INIT , "bad ISR initialisation"], + [PI_BAD_FOREVER , "loop forever must be last chain command"], + [PI_BAD_FILTER , "bad filter parameter"], + [PI_BAD_PAD , "bad pad number"], + [PI_BAD_STRENGTH , "bad pad drive strength"], + [PI_FIL_OPEN_FAILED , "file open failed"], + [PI_BAD_FILE_MODE , "bad file mode"], + [PI_BAD_FILE_FLAG , "bad file flag"], + [PI_BAD_FILE_READ , "bad file read"], + [PI_BAD_FILE_WRITE , "bad file write"], + [PI_FILE_NOT_ROPEN , "file not open for read"], + [PI_FILE_NOT_WOPEN , "file not open for write"], + [PI_BAD_FILE_SEEK , "bad file seek"], + [PI_NO_FILE_MATCH , "no files match pattern"], + [PI_NO_FILE_ACCESS , "no permission to access file"], + [PI_FILE_IS_A_DIR , "file is a directory"], + [PI_BAD_SHELL_STATUS , "bad shell return status"], + [PI_BAD_SCRIPT_NAME , "bad script name"], + [PI_BAD_SPI_BAUD , "bad SPI baud rate, not 50-500k"], + [PI_NOT_SPI_GPIO , "no bit bang SPI in progress on GPIO"], + [PI_BAD_EVENT_ID , "bad event id"], + [PI_CMD_INTERRUPTED , "pigpio command interrupted"], + [PI_NOT_ON_BCM2711 , "not available on BCM2711"], + [PI_ONLY_ON_BCM2711 , "only available on BCM2711"], +] + +_except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}" + +_except_z = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" + +_except_1 = """ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +{} +Did you start the pigpio daemon? E.g. sudo pigpiod + +Did you specify the correct Pi host/port in the environment +variables PIGPIO_ADDR/PIGPIO_PORT? +E.g. export PIGPIO_ADDR=soft, export PIGPIO_PORT=8888 + +Did you specify the correct Pi host/port in the +asyncpio.pi.connect() function? E.g. await pi.connect('soft', 8888) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%""" + +_except_2 = """ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +{} +Do you have permission to access the pigpio daemon? +Perhaps it was started with sudo pigpiod -nlocalhost +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%""" + +_except_3 = """ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Can't create callback handler. +Perhaps too many simultaneous pigpio connections. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%""" + +class _cosocket: + """An asynchronous socket.""" + def __init__(self, loop, sock): + sock.setblocking(False) + self._loop = loop + self._socket = sock + + def close(self): + self._socket.close() + + async def recv(self, nbytes): + return await self._loop.sock_recv(self._socket, nbytes) + + async def send(self, data): + await self._loop.sock_sendall(self._socket, data) + + async def sendall(self, data): + await self._loop.sock_sendall(self._socket, data) + +class _socklock: + """ + A class to store socket and lock. + """ + def __init__(self): + self.s = None + self.l = asyncio.Lock() + +class error(Exception): + """pigpio module exception""" + pass + +class pulse: + """ + A class to store pulse information. + """ + + def __init__(self, gpio_on, gpio_off, delay): + """ + Initialises a pulse. + + gpio_on:= the GPIO to switch on at the start of the pulse. + gpio_off:= the GPIO to switch off at the start of the pulse. + delay:= the delay in microseconds before the next pulse. + + """ + self.gpio_on = gpio_on + self.gpio_off = gpio_off + self.delay = delay + +def error_text(errnum): + """ + Returns a text description of a pigpio error. + + errnum:= <0, the error number + + ... + print(asyncpio.error_text(-5)) + level not 0-1 + ... + """ + for e in _errors: + if e[0] == errnum: + return e[1] + return "unknown error ({})".format(errnum) + +def tickDiff(t1, t2): + """ + Returns the microsecond difference between two ticks. + + t1:= the earlier tick + t2:= the later tick + + ... + print(asyncpio.tickDiff(4294967272, 12)) + 36 + ... + """ + tDiff = t2 - t1 + if tDiff < 0: + tDiff += (1 << 32) + return tDiff + +# A couple of hacks to cope with different string handling +# between various Python versions +# 3 != 2.7.8 != 2.7.3 + +if sys.hexversion < 0x03000000: + def _b(x): + return x +else: + def _b(x): + return x.encode('latin-1') + +if sys.hexversion < 0x02070800: + def _str(x): + return buffer(x) +else: + def _str(x): + return x + +def u2i(uint32): + """ + Converts a 32 bit unsigned number to signed. + + uint32:= an unsigned 32 bit number + + ... + print(u2i(4294967272)) + -24 + print(u2i(37)) + 37 + ... + """ + mask = (2 ** 32) - 1 + if uint32 & (1 << 31): + v = uint32 | ~mask + else: + v = uint32 & mask + return v + +def _u2i(uint32): + """ + Converts a 32 bit unsigned number to signed. If the number + is negative it indicates an error. On error a pigpio + exception will be raised if exceptions is True. + """ + v = u2i(uint32) + if v < 0: + if exceptions: + raise error(error_text(v)) + return v + +async def _pigpio_command(sl, cmd, p1, p2): + """ + Runs a pigpio socket command. + + sl:= command socket and lock. + cmd:= the command to be executed. + p1:= command parameter 1 (if applicable). + p2:= command parameter 2 (if applicable). + """ + res = PI_CMD_INTERRUPTED + async with sl.l: + await sl.s.send(struct.pack('IIII', cmd, p1, p2, 0)) + raw_res = await sl.s.recv(_SOCK_CMD_LEN) + dummy, res = struct.unpack('12sI', raw_res) + return res + +async def _pigpio_command_nolock(sl, cmd, p1, p2): + """ + Runs a pigpio socket command. + + sl:= command socket and lock. + cmd:= the command to be executed. + p1:= command parameter 1 (if applicable). + p2:= command parameter 2 (if applicable). + """ + res = PI_CMD_INTERRUPTED + await sl.s.send(struct.pack('IIII', cmd, p1, p2, 0)) + raw_res = await sl.s.recv(_SOCK_CMD_LEN) + dummy, res = struct.unpack('12sI', raw_res) + return res + +async def _pigpio_command_ext(sl, cmd, p1, p2, p3, extents): + """ + Runs an extended pigpio socket command. + + sl:= command socket and lock. + cmd:= the command to be executed. + p1:= command parameter 1 (if applicable). + p2:= command parameter 2 (if applicable). + p3:= total size in bytes of following extents + extents:= additional data blocks + """ + ext = bytearray(struct.pack('IIII', cmd, p1, p2, p3)) + for x in extents: + if type(x) == type(""): + ext.extend(_b(x)) + else: + ext.extend(x) + res = PI_CMD_INTERRUPTED + async with sl.l: + await sl.s.sendall(ext) + raw_res = await sl.s.recv(_SOCK_CMD_LEN) + dummy, res = struct.unpack('12sI', raw_res) + return res + +async def _pigpio_command_ext_nolock(sl, cmd, p1, p2, p3, extents): + """ + Runs an extended pigpio socket command. + + sl:= command socket and lock. + cmd:= the command to be executed. + p1:= command parameter 1 (if applicable). + p2:= command parameter 2 (if applicable). + p3:= total size in bytes of following extents + extents:= additional data blocks + """ + res = PI_CMD_INTERRUPTED + ext = bytearray(struct.pack('IIII', cmd, p1, p2, p3)) + for x in extents: + if type(x) == type(""): + ext.extend(_b(x)) + else: + ext.extend(x) + await sl.s.sendall(ext) + raw_res = await sl.s.recv(_SOCK_CMD_LEN) + dummy, res = struct.unpack('12sI', raw_res) + return res + +def _ensure_coroutine(func): + if asyncio.iscoroutinefunction(func): + return func + + async def _call(*args, **kwargs): + return func(*args, **kwargs) + return _call + +class _event_ADT: + """ + An ADT class to hold event callback information. + """ + + def __init__(self, event, func): + """ + Initialises an event callback ADT. + + event:= the event id. + func:= a user function taking one argument, the event id. + """ + self.event = event + self.func = _ensure_coroutine(func) + self.bit = 1<= MSG_SIZ: + msgbuf = buf[offset:offset + MSG_SIZ] + offset += MSG_SIZ + seq, flags, tick, level = (struct.unpack('HHII', msgbuf)) + + if flags == 0: + changed = level ^ lastLevel + lastLevel = level + for cb in self.callbacks: + if cb.bit & changed: + newLevel = 0 + if cb.bit & level: + newLevel = 1 + if (cb.edge ^ newLevel): + await cb.func(cb.gpio, newLevel, tick) + else: + if flags & NTFY_FLAGS_WDOG: + gpio = flags & NTFY_FLAGS_GPIO + for cb in self.callbacks: + if cb.gpio == gpio: + await cb.func(gpio, TIMEOUT, tick) + elif flags & NTFY_FLAGS_EVENT: + event = flags & NTFY_FLAGS_GPIO + for cb in self.events: + if cb.event == event: + await cb.func(event, tick) + buf = buf[offset:] + await asyncio.sleep(0.0) + + self.sl.s.close() + +class _callback: + """A class to provide GPIO level change callbacks.""" + + def __init__(self, notify, user_gpio, edge=RISING_EDGE, func=None): + """ + Initialise a callback. + """ + self._notify = notify + self.count=0 + self._reset = False + if func is None: + func=self._tally + self.callb = _callback_ADT(user_gpio, edge, func) + + async def cancel(self): + """Cancel the callback.""" + await self._notify.remove(self.callb) + + def _tally(self, user_gpio, level, tick): + """Increment the callback called count.""" + if self._reset: + self._reset = False + self.count = 0 + self.count += 1 + + def tally(self): + """ + Provides a count of how many times the default tally + callback has triggered. + + The count will be zero if the user has supplied their own + callback function. + """ + return self.count + + def reset_tally(self): + """ + Resets the tally count to zero. + """ + self._reset = True + self.count = 0 + +class _event: + """A class to provide event callbacks.""" + + def __init__(self, notify, event, func=None): + """ + Initialise an event. + """ + self._notify = notify + self.count=0 + self._reset = False + if func is None: + func=self._tally + self.callb = _event_ADT(event, func) + + async def cancel(self): + """Cancel the event callback.""" + await self._notify.remove_event(self.callb) + + def _tally(self, event, tick): + """Increment the event callback called count.""" + if self._reset: + self._reset = False + self.count = 0 + self.count += 1 + + def tally(self): + """ + Provides a count of how many times the default tally + callback has triggered. + + The count will be zero if the user has supplied their own + callback function. + """ + return self.count + + def reset_tally(self): + """ + Resets the tally count to zero. + """ + self._reset = True + self.count = 0 + +class _wait_for_edge: + """Encapsulates waiting for a GPIO edge.""" + + def __init__(self, notify, gpio, edge): + """Initialises a wait_for_edge.""" + self._notify = notify + self._event = asyncio.Event() + self.callb = _callback_ADT(gpio, edge, self._func) + + async def wait_for(self, timeout): + """Waits on the GPIO edge.""" + await self._notify.append(self.callb) + try: + await asyncio.wait_for(self._event.wait(), timeout) + finally: + await self._notify.remove(self.callb) + + def _func(self, gpio, level, tick): + """To be called when done waiting for edge.""" + self._event.set() + +class _wait_for_event: + """Encapsulates waiting for an event.""" + + def __init__(self, notify, event): + """Initialises wait_for_event.""" + self._notify = notify + self._event = asyncio.Event() + self.callb = _event_ADT(event, self._func) + + async def wait_for(self, timeout): + """Wait on the event.""" + await self._notify.append(self.callb) + try: + await asyncio.wait_for(self._event.wait(), timeout) + finally: + await self._notify.remove(self.callb) + + def _func(self, event, tick): + """To be called when done waiting for event.""" + self._event.set() + +class pi(): + + async def _rxbuf(self, count): + """Returns count bytes from the command socket.""" + ext = bytearray(await self.sl.s.recv(count)) + while len(ext) < count: + ext.extend(await self.sl.s.recv(count - len(ext))) + return ext + + async def set_mode(self, gpio, mode): + """ + Sets the GPIO mode. + + gpio:= 0-53. + mode:= INPUT, OUTPUT, ALT0, ALT1, ALT2, ALT3, ALT4, ALT5. + + ... + await pi.set_mode( 4, asyncpio.INPUT) # GPIO 4 as input + await pi.set_mode(17, asyncpio.OUTPUT) # GPIO 17 as output + await pi.set_mode(24, asyncpio.ALT2) # GPIO 24 as ALT2 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_MODES, gpio, mode)) + + async def get_mode(self, gpio): + """ + Returns the GPIO mode. + + gpio:= 0-53. + + Returns a value as follows + + . . + 0 = INPUT + 1 = OUTPUT + 2 = ALT5 + 3 = ALT4 + 4 = ALT0 + 5 = ALT1 + 6 = ALT2 + 7 = ALT3 + . . + + ... + print(await pi.get_mode(0)) + 4 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_MODEG, gpio, 0)) + + async def set_pull_up_down(self, gpio, pud): + """ + Sets or clears the internal GPIO pull-up/down resistor. + + gpio:= 0-53. + pud:= PUD_UP, PUD_DOWN, PUD_OFF. + + ... + await pi.set_pull_up_down(17, asyncpio.PUD_OFF) + await pi.set_pull_up_down(23, asyncpio.PUD_UP) + await pi.set_pull_up_down(24, asyncpio.PUD_DOWN) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PUD, gpio, pud)) + + async def read(self, gpio): + """ + Returns the GPIO level. + + gpio:= 0-53. + + ... + await pi.set_mode(23, asyncpio.INPUT) + + await pi.set_pull_up_down(23, asyncpio.PUD_DOWN) + print(await pi.read(23)) + 0 + + await pi.set_pull_up_down(23, asyncpio.PUD_UP) + print(await pi.read(23)) + 1 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_READ, gpio, 0)) + + async def write(self, gpio, level): + """ + Sets the GPIO level. + + GPIO:= 0-53. + level:= 0, 1. + + If PWM or servo pulses are active on the GPIO they are + switched off. + + ... + await pi.set_mode(17, asyncpio.OUTPUT) + + await pi.write(17,0) + print(await pi.read(17)) + 0 + + await pi.write(17,1) + print(await pi.read(17)) + 1 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WRITE, gpio, level)) + + async def set_PWM_dutycycle(self, user_gpio, dutycycle): + """ + Starts (non-zero dutycycle) or stops (0) PWM pulses on the GPIO. + + user_gpio:= 0-31. + dutycycle:= 0-range (range defaults to 255). + + The [*set_PWM_range*] function can change the default range of 255. + + ... + await pi.set_PWM_dutycycle(4, 0) # PWM off + await pi.set_PWM_dutycycle(4, 64) # PWM 1/4 on + await pi.set_PWM_dutycycle(4, 128) # PWM 1/2 on + await pi.set_PWM_dutycycle(4, 192) # PWM 3/4 on + await pi.set_PWM_dutycycle(4, 255) # PWM full on + ... + """ + return _u2i(await _pigpio_command( + self.sl, _PI_CMD_PWM, user_gpio, int(dutycycle))) + + async def get_PWM_dutycycle(self, user_gpio): + """ + Returns the PWM dutycycle being used on the GPIO. + + user_gpio:= 0-31. + + Returns the PWM dutycycle. + + + For normal PWM the dutycycle will be out of the defined range + for the GPIO (see [*get_PWM_range*]). + + If a hardware clock is active on the GPIO the reported + dutycycle will be 500000 (500k) out of 1000000 (1M). + + If hardware PWM is active on the GPIO the reported dutycycle + will be out of a 1000000 (1M). + + ... + await pi.set_PWM_dutycycle(4, 25) + print(await pi.get_PWM_dutycycle(4)) + 25 + + await pi.set_PWM_dutycycle(4, 203) + print(await pi.get_PWM_dutycycle(4)) + 203 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_GDC, user_gpio, 0)) + + async def set_PWM_range(self, user_gpio, range_): + """ + Sets the range of PWM values to be used on the GPIO. + + user_gpio:= 0-31. + range_:= 25-40000. + + ... + await pi.set_PWM_range(9, 100) # now 25 1/4, 50 1/2, 75 3/4 on + await pi.set_PWM_range(9, 500) # now 125 1/4, 250 1/2, 375 3/4 on + await pi.set_PWM_range(9, 3000) # now 750 1/4, 1500 1/2, 2250 3/4 on + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PRS, user_gpio, range_)) + + async def get_PWM_range(self, user_gpio): + """ + Returns the range of PWM values being used on the GPIO. + + user_gpio:= 0-31. + + If a hardware clock or hardware PWM is active on the GPIO + the reported range will be 1000000 (1M). + + ... + await pi.set_PWM_range(9, 500) + print(await pi.get_PWM_range(9)) + 500 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PRG, user_gpio, 0)) + + async def get_PWM_real_range(self, user_gpio): + """ + Returns the real (underlying) range of PWM values being + used on the GPIO. + + user_gpio:= 0-31. + + If a hardware clock is active on the GPIO the reported + real range will be 1000000 (1M). + + If hardware PWM is active on the GPIO the reported real range + will be approximately 250M divided by the set PWM frequency. + + ... + await pi.set_PWM_frequency(4, 800) + print(await pi.get_PWM_real_range(4)) + 250 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PRRG, user_gpio, 0)) + + async def set_PWM_frequency(self, user_gpio, frequency): + """ + Sets the frequency (in Hz) of the PWM to be used on the GPIO. + + user_gpio:= 0-31. + frequency:= >=0 Hz + + Returns the numerically closest frequency if OK, otherwise + PI_BAD_USER_GPIO or PI_NOT_PERMITTED. + + If PWM is currently active on the GPIO it will be switched + off and then back on at the new frequency. + + Each GPIO can be independently set to one of 18 different + PWM frequencies. + + The selectable frequencies depend upon the sample rate which + may be 1, 2, 4, 5, 8, or 10 microseconds (default 5). The + sample rate is set when the pigpio daemon is started. + + The frequencies for each sample rate are: + + . . + Hertz + + 1: 40000 20000 10000 8000 5000 4000 2500 2000 1600 + 1250 1000 800 500 400 250 200 100 50 + + 2: 20000 10000 5000 4000 2500 2000 1250 1000 800 + 625 500 400 250 200 125 100 50 25 + + 4: 10000 5000 2500 2000 1250 1000 625 500 400 + 313 250 200 125 100 63 50 25 13 + sample + rate + (us) 5: 8000 4000 2000 1600 1000 800 500 400 320 + 250 200 160 100 80 50 40 20 10 + + 8: 5000 2500 1250 1000 625 500 313 250 200 + 156 125 100 63 50 31 25 13 6 + + 10: 4000 2000 1000 800 500 400 250 200 160 + 125 100 80 50 40 25 20 10 5 + . . + + ... + await pi.set_PWM_frequency(4,0) + print(await pi.get_PWM_frequency(4)) + 10 + + await pi.set_PWM_frequency(4,100000) + print(await pi.get_PWM_frequency(4)) + 8000 + ... + """ + return _u2i( + await _pigpio_command(self.sl, _PI_CMD_PFS, user_gpio, frequency)) + + async def get_PWM_frequency(self, user_gpio): + """ + Returns the frequency of PWM being used on the GPIO. + + user_gpio:= 0-31. + + Returns the frequency (in Hz) used for the GPIO. + + For normal PWM the frequency will be that defined for the GPIO + by [*set_PWM_frequency*]. + + If a hardware clock is active on the GPIO the reported frequency + will be that set by [*hardware_clock*]. + + If hardware PWM is active on the GPIO the reported frequency + will be that set by [*hardware_PWM*]. + + ... + await pi.set_PWM_frequency(4, 0) + print(await pi.get_PWM_frequency(4)) + 10 + + await pi.set_PWM_frequency(4, 800) + print(await pi.get_PWM_frequency(4)) + 800 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PFG, user_gpio, 0)) + + async def set_servo_pulsewidth(self, user_gpio, pulsewidth): + """ + Starts (500-2500) or stops (0) servo pulses on the GPIO. + + user_gpio:= 0-31. + pulsewidth:= 0 (off), + 500 (most anti-clockwise) - 2500 (most clockwise). + + The selected pulsewidth will continue to be transmitted until + changed by a subsequent call to set_servo_pulsewidth. + + The pulsewidths supported by servos varies and should probably + be determined by experiment. A value of 1500 should always be + safe and represents the mid-point of rotation. + + You can DAMAGE a servo if you command it to move beyond its + limits. + + ... + await pi.set_servo_pulsewidth(17, 0) # off + await pi.set_servo_pulsewidth(17, 1000) # safe anti-clockwise + await pi.set_servo_pulsewidth(17, 1500) # centre + await pi.set_servo_pulsewidth(17, 2000) # safe clockwise + ... + """ + return _u2i(await _pigpio_command( + self.sl, _PI_CMD_SERVO, user_gpio, int(pulsewidth))) + + async def get_servo_pulsewidth(self, user_gpio): + """ + Returns the servo pulsewidth being used on the GPIO. + + user_gpio:= 0-31. + + Returns the servo pulsewidth. + + ... + await pi.set_servo_pulsewidth(4, 525) + print(await pi.get_servo_pulsewidth(4)) + 525 + + await pi.set_servo_pulsewidth(4, 2130) + print(await pi.get_servo_pulsewidth(4)) + 2130 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_GPW, user_gpio, 0)) + + async def notify_open(self): + """ + Returns a notification handle (>=0). + + A notification is a method for being notified of GPIO state + changes via a pipe. + + Pipes are only accessible from the local machine so this + function serves no purpose if you are using Python from a + remote machine. The in-built (socket) notifications + provided by [*callback*] should be used instead. + + Notifications for handle x will be available at the pipe + named /dev/pigpiox (where x is the handle number). + + E.g. if the function returns 15 then the notifications must be + read from /dev/pigpio15. + + Notifications have the following structure: + + . . + H seqno + H flags + I tick + I level + . . + + seqno: starts at 0 each time the handle is opened and then + increments by one for each report. + + flags: three flags are defined, PI_NTFY_FLAGS_WDOG, + PI_NTFY_FLAGS_ALIVE, and PI_NTFY_FLAGS_EVENT. + + If bit 5 is set (PI_NTFY_FLAGS_WDOG) then bits 0-4 of the + flags indicate a GPIO which has had a watchdog timeout. + + If bit 6 is set (PI_NTFY_FLAGS_ALIVE) this indicates a keep + alive signal on the pipe/socket and is sent once a minute + in the absence of other notification activity. + + If bit 7 is set (PI_NTFY_FLAGS_EVENT) then bits 0-4 of the + flags indicate an event which has been triggered. + + + tick: the number of microseconds since system boot. It wraps + around after 1h12m. + + level: indicates the level of each GPIO. If bit 1<= 0: + await pi.notify_begin(h, 1234) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_NO, 0, 0)) + + async def notify_begin(self, handle, bits): + """ + Starts notifications on a handle. + + handle:= >=0 (as returned by a prior call to [*notify_open*]) + bits:= a 32 bit mask indicating the GPIO to be notified. + + The notification sends state changes for each GPIO whose + corresponding bit in bits is set. + + The following code starts notifications for GPIO 1, 4, + 6, 7, and 10 (1234 = 0x04D2 = 0b0000010011010010). + + ... + h = await pi.notify_open() + if h >= 0: + await pi.notify_begin(h, 1234) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_NB, handle, bits)) + + async def notify_pause(self, handle): + """ + Pauses notifications on a handle. + + handle:= >=0 (as returned by a prior call to [*notify_open*]) + + Notifications for the handle are suspended until + [*notify_begin*] is called again. + + ... + h = await pi.notify_open() + if h >= 0: + await pi.notify_begin(h, 1234) + ... + await pi.notify_pause(h) + ... + await pi.notify_begin(h, 1234) + ... + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_NB, handle, 0)) + + async def notify_close(self, handle): + """ + Stops notifications on a handle and releases the handle for reuse. + + handle:= >=0 (as returned by a prior call to [*notify_open*]) + + ... + h = await pi.notify_open() + if h >= 0: + await pi.notify_begin(h, 1234) + ... + await pi.notify_close(h) + ... + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_NC, handle, 0)) + + async def set_watchdog(self, user_gpio, wdog_timeout): + """ + Sets a watchdog timeout for a GPIO. + + user_gpio:= 0-31. + wdog_timeout:= 0-60000. + + The watchdog is nominally in milliseconds. + + Only one watchdog may be registered per GPIO. + + The watchdog may be cancelled by setting timeout to 0. + + Once a watchdog has been started callbacks for the GPIO + will be triggered every timeout interval after the last + GPIO activity. + + The callback will receive the special level TIMEOUT. + + ... + await pi.set_watchdog(23, 1000) # 1000 ms watchdog on GPIO 23 + await pi.set_watchdog(23, 0) # cancel watchdog on GPIO 23 + ... + """ + return _u2i(await _pigpio_command( + self.sl, _PI_CMD_WDOG, user_gpio, int(wdog_timeout))) + + async def read_bank_1(self): + """ + Returns the levels of the bank 1 GPIO (GPIO 0-31). + + The returned 32 bit integer has a bit set if the corresponding + GPIO is high. GPIO n has bit value (1<=0) if OK, otherwise PI_EMPTY_WAVEFORM, + PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. + + The data provided by the [*wave_add_**] functions is consumed by + this function. + + As many waveforms may be created as there is space available. + The wave id is passed to [*wave_send_**] to specify the waveform + to transmit. + + Normal usage would be + + Step 1. [*wave_clear*] to clear all waveforms and added data. + + Step 2. [*wave_add_**] calls to supply the waveform data. + + Step 3. [*wave_create*] to create the waveform and get a unique id + + Repeat steps 2 and 3 as needed. + + Step 4. [*wave_send_**] with the id of the waveform to transmit. + + A waveform comprises one or more pulses. + + A pulse specifies + + 1) the GPIO to be switched on at the start of the pulse. + 2) the GPIO to be switched off at the start of the pulse. + 3) the delay in microseconds before the next pulse. + + Any or all the fields can be zero. It doesn't make any sense + to set all the fields to zero (the pulse will be ignored). + + When a waveform is started each pulse is executed in order with + the specified delay between the pulse and the next. + + ... + wid = await pi.wave_create() + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVCRE, 0, 0)) + + async def wave_create_and_pad(self, percent): + """ + This function creates a waveform like [*wave_create*] but pads the consumed + resources. Where percent gives the percentage of the resources to use + (in terms of the theoretical maximum, not the current amount free). + This allows the reuse of deleted waves while a transmission is active. + + Upon success a wave id greater than or equal to 0 is returned, otherwise + PI_EMPTY_WAVEFORM, PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. + + . . + percent: 0-100, size of waveform as percentage of maximum available. + . . + + The data provided by the [*wave_add_**] functions are consumed by this + function. + + As many waveforms may be created as there is space available. The + wave id is passed to [*wave_send_**] to specify the waveform to transmit. + + A usage would be the creation of two waves where one is filled while the + other is being transmitted. Each wave is assigned 50% of the resources. + This buffer structure allows the transmission of infinite wave sequences. + + Normal usage: + + Step 1. [*wave_clear*] to clear all waveforms and added data. + + Step 2. [*wave_add_**] calls to supply the waveform data. + + Step 3. [*wave_create_and_pad*] to create a waveform of uniform size. + + Step 4. [*wave_send_**] with the id of the waveform to transmit. + + Repeat steps 2-4 as needed. + + Step 5. Any wave id can now be deleted and another wave of the same size + can be created in its place. + + ... + wid = await pi.wave_create_and_pad(50) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVCAP, percent, 0)) + + async def wave_delete(self, wave_id): + """ + This function deletes the waveform with id wave_id. + + wave_id:= >=0 (as returned by a prior call to [*wave_create*]). + + Wave ids are allocated in order, 0, 1, 2, etc. + + The wave is flagged for deletion. The resources used by the wave + will only be reused when either of the following apply. + + - all waves with higher numbered wave ids have been deleted or have + been flagged for deletion. + + - a new wave is created which uses exactly the same resources as + the current wave (see the C source for gpioWaveCreate for details). + + ... + await pi.wave_delete(6) # delete waveform with id 6 + + await pi.wave_delete(0) # delete waveform with id 0 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVDEL, wave_id, 0)) + + async def wave_tx_start(self): # DEPRECATED + """ + This function is deprecated and has been removed. + + Use [*wave_create*]/[*wave_send_**] instead. + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVGO, 0, 0)) + + async def wave_tx_repeat(self): # DEPRECATED + """ + This function is deprecated and has beeen removed. + + Use [*wave_create*]/[*wave_send_**] instead. + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVGOR, 0, 0)) + + async def wave_send_once(self, wave_id): + """ + Transmits the waveform with id wave_id. The waveform is sent + once. + + NOTE: Any hardware PWM started by [*hardware_PWM*] will + be cancelled. + + wave_id:= >=0 (as returned by a prior call to [*wave_create*]). + + Returns the number of DMA control blocks used in the waveform. + + ... + cbs = await pi.wave_send_once(wid) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVTX, wave_id, 0)) + + async def wave_send_repeat(self, wave_id): + """ + Transmits the waveform with id wave_id. The waveform repeats + until wave_tx_stop is called or another call to [*wave_send_**] + is made. + + NOTE: Any hardware PWM started by [*hardware_PWM*] will + be cancelled. + + wave_id:= >=0 (as returned by a prior call to [*wave_create*]). + + Returns the number of DMA control blocks used in the waveform. + + ... + cbs = await pi.wave_send_repeat(wid) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVTXR, wave_id, 0)) + + async def wave_send_using_mode(self, wave_id, mode): + """ + Transmits the waveform with id wave_id using mode mode. + + wave_id:= >=0 (as returned by a prior call to [*wave_create*]). + mode:= WAVE_MODE_ONE_SHOT, WAVE_MODE_REPEAT, + WAVE_MODE_ONE_SHOT_SYNC, or WAVE_MODE_REPEAT_SYNC. + + WAVE_MODE_ONE_SHOT: same as [*wave_send_once*]. + + WAVE_MODE_REPEAT same as [*wave_send_repeat*]. + + WAVE_MODE_ONE_SHOT_SYNC same as [*wave_send_once*] but tries + to sync with the previous waveform. + + WAVE_MODE_REPEAT_SYNC same as [*wave_send_repeat*] but tries + to sync with the previous waveform. + + WARNING: bad things may happen if you delete the previous + waveform before it has been synced to the new waveform. + + NOTE: Any hardware PWM started by [*hardware_PWM*] will + be cancelled. + + wave_id:= >=0 (as returned by a prior call to [*wave_create*]). + + Returns the number of DMA control blocks used in the waveform. + + ... + cbs = await pi.wave_send_using_mode(wid, WAVE_MODE_REPEAT_SYNC) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVTXM, wave_id, mode)) + + async def wave_tx_at(self): + """ + Returns the id of the waveform currently being + transmitted using [*wave_send**]. Chained waves are not supported. + + Returns the waveform id or one of the following special + values: + + WAVE_NOT_FOUND (9998) - transmitted wave not found. + NO_TX_WAVE (9999) - no wave being transmitted. + + ... + wid = await pi.wave_tx_at() + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVTAT, 0, 0)) + + async def wave_tx_busy(self): + """ + Returns 1 if a waveform is currently being transmitted, + otherwise 0. + + ... + await pi.wave_send_once(0) # send first waveform + + while await pi.wave_tx_busy(): # wait for waveform to be sent + await asyncio.sleep(0.1) + + await pi.wave_send_once(1) # send next waveform + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVBSY, 0, 0)) + + async def wave_tx_stop(self): + """ + Stops the transmission of the current waveform. + + This function is intended to stop a waveform started with + wave_send_repeat. + + ... + await pi.wave_send_repeat(3) + + await asyncio.sleep(5) + + await pi.wave_tx_stop() + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_WVHLT, 0, 0)) + + async def wave_chain(self, data): + """ + This function transmits a chain of waveforms. + + NOTE: Any hardware PWM started by [*hardware_PWM*] + will be cancelled. + + The waves to be transmitted are specified by the contents + of data which contains an ordered list of [*wave_id*]s + and optional command codes and related data. + + Returns 0 if OK, otherwise PI_CHAIN_NESTING, + PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, + PI_CHAIN_COUNTER, PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, + or PI_BAD_WAVE_ID. + + Each wave is transmitted in the order specified. A wave + may occur multiple times per chain. + + A blocks of waves may be transmitted multiple times by + using the loop commands. The block is bracketed by loop + start and end commands. Loops may be nested. + + Delays between waves may be added with the delay command. + + The following command codes are supported: + + Name @ Cmd & Data @ Meaning + Loop Start @ 255 0 @ Identify start of a wave block + Loop Repeat @ 255 1 x y @ loop x + y*256 times + Delay @ 255 2 x y @ delay x + y*256 microseconds + Loop Forever @ 255 3 @ loop forever + + If present Loop Forever must be the last entry in the chain. + + The code is currently dimensioned to support a chain with + roughly 600 entries and 20 loop counters. + + ... + #!/usr/bin/env python + + import asyncio + import asyncpio + + WAVES=5 + GPIO=4 + + wid=[0]*WAVES + + async def main(pi): + await pi.connect() # Connect to local Pi. + await pi.set_mode(GPIO, asyncpio.OUTPUT); + + for i in range(WAVES): + await pi.wave_add_generic([ + asyncpio.pulse(1<=0) for the device at the I2C bus address. + + i2c_bus:= >=0. + i2c_address:= 0-0x7F. + i2c_flags:= 0, no flags are currently defined. + + Physically buses 0 and 1 are available on the Pi. Higher + numbered buses will be available if a kernel supported bus + multiplexor is being used. + + The GPIO used are given in the following table. + + @ SDA @ SCL + I2C 0 @ 0 @ 1 + I2C 1 @ 2 @ 3 + + For the SMBus commands the low level transactions are shown + at the end of the function description. The following + abbreviations are used: + + . . + S (1 bit) : Start bit + P (1 bit) : Stop bit + Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0. + A, NA (1 bit) : Accept and not accept bit. + Addr (7 bits): I2C 7 bit address. + reg (8 bits): Command byte, which often selects a register. + Data (8 bits): A data byte. + Count (8 bits): A byte defining the length of a block operation. + + [..]: Data sent by the device. + . . + + ... + h = await pi.i2c_open(1, 0x53) # open device at address 0x53 on bus 1 + ... + """ + # I p1 i2c_bus + # I p2 i2c_addr + # I p3 4 + ## extension ## + # I i2c_flags + extents = [struct.pack("I", i2c_flags)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CO, i2c_bus, i2c_address, 4, extents)) + + async def i2c_close(self, handle): + """ + Closes the I2C device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + + ... + await pi.i2c_close(h) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_I2CC, handle, 0)) + + async def i2c_write_quick(self, handle, bit): + """ + Sends a single bit to the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + bit:= 0 or 1, the value to write. + + SMBus 2.0 5.5.1 - Quick command. + . . + S Addr bit [A] P + . . + + ... + await pi.i2c_write_quick(0, 1) # send 1 to device 0 + await pi.i2c_write_quick(3, 0) # send 0 to device 3 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_I2CWQ, handle, bit)) + + async def i2c_write_byte(self, handle, byte_val): + """ + Sends a single byte to the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + byte_val:= 0-255, the value to write. + + SMBus 2.0 5.5.2 - Send byte. + . . + S Addr Wr [A] byte_val [A] P + . . + + ... + await pi.i2c_write_byte(1, 17) # send byte 17 to device 1 + await pi.i2c_write_byte(2, 0x23) # send byte 0x23 to device 2 + ... + """ + return _u2i( + await _pigpio_command(self.sl, _PI_CMD_I2CWS, handle, byte_val)) + + async def i2c_read_byte(self, handle): + """ + Reads a single byte from the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + + SMBus 2.0 5.5.3 - Receive byte. + . . + S Addr Rd [A] [Data] NA P + . . + + ... + b = await pi.i2c_read_byte(2) # read a byte from device 2 + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_I2CRS, handle, 0)) + + async def i2c_write_byte_data(self, handle, reg, byte_val): + """ + Writes a single byte to the specified register of the device + associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + byte_val:= 0-255, the value to write. + + SMBus 2.0 5.5.4 - Write byte. + . . + S Addr Wr [A] reg [A] byte_val [A] P + . . + + ... + # send byte 0xC5 to reg 2 of device 1 + await pi.i2c_write_byte_data(1, 2, 0xC5) + + # send byte 9 to reg 4 of device 2 + await pi.i2c_write_byte_data(2, 4, 9) + ... + """ + # I p1 handle + # I p2 reg + # I p3 4 + ## extension ## + # I byte_val + extents = [struct.pack("I", byte_val)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CWB, handle, reg, 4, extents)) + + async def i2c_write_word_data(self, handle, reg, word_val): + """ + Writes a single 16 bit word to the specified register of the + device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + word_val:= 0-65535, the value to write. + + SMBus 2.0 5.5.4 - Write word. + . . + S Addr Wr [A] reg [A] word_val_Low [A] word_val_High [A] P + . . + + ... + # send word 0xA0C5 to reg 5 of device 4 + await pi.i2c_write_word_data(4, 5, 0xA0C5) + + # send word 2 to reg 2 of device 5 + await pi.i2c_write_word_data(5, 2, 23) + ... + """ + # I p1 handle + # I p2 reg + # I p3 4 + ## extension ## + # I word_val + extents = [struct.pack("I", word_val)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CWW, handle, reg, 4, extents)) + + async def i2c_read_byte_data(self, handle, reg): + """ + Reads a single byte from the specified register of the device + associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + + SMBus 2.0 5.5.5 - Read byte. + . . + S Addr Wr [A] reg [A] S Addr Rd [A] [Data] NA P + . . + + ... + # read byte from reg 17 of device 2 + b = await pi.i2c_read_byte_data(2, 17) + + # read byte from reg 1 of device 0 + b = await pi.i2c_read_byte_data(0, 1) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_I2CRB, handle, reg)) + + async def i2c_read_word_data(self, handle, reg): + """ + Reads a single 16 bit word from the specified register of the + device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + + SMBus 2.0 5.5.5 - Read word. + . . + S Addr Wr [A] reg [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P + . . + + ... + # read word from reg 2 of device 3 + w = await pi.i2c_read_word_data(3, 2) + + # read word from reg 7 of device 2 + w = await pi.i2c_read_word_data(2, 7) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_I2CRW, handle, reg)) + + async def i2c_process_call(self, handle, reg, word_val): + """ + Writes 16 bits of data to the specified register of the device + associated with handle and reads 16 bits of data in return. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + word_val:= 0-65535, the value to write. + + SMBus 2.0 5.5.6 - Process call. + . . + S Addr Wr [A] reg [A] word_val_Low [A] word_val_High [A] + S Addr Rd [A] [DataLow] A [DataHigh] NA P + . . + + ... + r = await pi.i2c_process_call(h, 4, 0x1231) + r = await pi.i2c_process_call(h, 6, 0) + ... + """ + # I p1 handle + # I p2 reg + # I p3 4 + ## extension ## + # I word_val + extents = [struct.pack("I", word_val)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CPC, handle, reg, 4, extents)) + + async def i2c_write_block_data(self, handle, reg, data): + """ + Writes up to 32 bytes to the specified register of the device + associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + data:= the bytes to write. + + SMBus 2.0 5.5.7 - Block write. + . . + S Addr Wr [A] reg [A] len(data) [A] data0 [A] data1 [A] ... [A] + datan [A] P + . . + + ... + await pi.i2c_write_block_data(4, 5, b'hello') + + await pi.i2c_write_block_data(4, 5, "data bytes") + + await pi.i2c_write_block_data(5, 0, b'\\x00\\x01\\x22') + + await pi.i2c_write_block_data(6, 2, [0, 1, 0x22]) + ... + """ + # I p1 handle + # I p2 reg + # I p3 len + ## extension ## + # s len data bytes + if len(data): + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CWK, handle, reg, len(data), [data])) + else: + return 0 + + async def i2c_read_block_data(self, handle, reg): + """ + Reads a block of up to 32 bytes from the specified register of + the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + + SMBus 2.0 5.5.7 - Block read. + . . + S Addr Wr [A] reg [A] + S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P + . . + + The amount of returned data is set by the device. + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (b, d) = await pi.i2c_read_block_data(h, 10) + if b >= 0: + # process data + else: + # process read failure + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_nolock( + self.sl, _PI_CMD_I2CRK, handle, reg)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def i2c_block_process_call(self, handle, reg, data): + """ + Writes data bytes to the specified register of the device + associated with handle and reads a device specified number + of bytes of data in return. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + data:= the bytes to write. + + The SMBus 2.0 documentation states that a minimum of 1 byte may + be sent and a minimum of 1 byte may be received. The total + number of bytes sent/received must be 32 or less. + + SMBus 2.0 5.5.8 - Block write-block read. + . . + S Addr Wr [A] reg [A] len(data) [A] data0 [A] ... datan [A] + S Addr Rd [A] [Count] A [Data] ... A P + . . + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (b, d) = await pi.i2c_block_process_call(h, 10, b'\\x02\\x05\\x00') + + (b, d) = await pi.i2c_block_process_call(h, 10, b'abcdr') + + (b, d) = await pi.i2c_block_process_call(h, 10, "abracad") + + (b, d) = await pi.i2c_block_process_call(h, 10, [2, 5, 16]) + ... + """ + # I p1 handle + # I p2 reg + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_I2CPK, handle, reg, len(data), [data])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def i2c_write_i2c_block_data(self, handle, reg, data): + """ + Writes data bytes to the specified register of the device + associated with handle . 1-32 bytes may be written. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + data:= the bytes to write. + + . . + S Addr Wr [A] reg [A] data0 [A] data1 [A] ... [A] datan [NA] P + . . + + ... + await pi.i2c_write_i2c_block_data(4, 5, 'hello') + + await pi.i2c_write_i2c_block_data(4, 5, b'hello') + + await pi.i2c_write_i2c_block_data(5, 0, b'\\x00\\x01\\x22') + + await pi.i2c_write_i2c_block_data(6, 2, [0, 1, 0x22]) + ... + """ + # I p1 handle + # I p2 reg + # I p3 len + ## extension ## + # s len data bytes + if len(data): + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CWI, handle, reg, len(data), [data])) + else: + return 0 + + async def i2c_read_i2c_block_data(self, handle, reg, count): + """ + Reads count bytes from the specified register of the device + associated with handle . The count may be 1-32. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + reg:= >=0, the device register. + count:= >0, the number of bytes to read. + + . . + S Addr Wr [A] reg [A] + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + . . + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (b, d) = await pi.i2c_read_i2c_block_data(h, 4, 32) + if b >= 0: + # process data + else: + # process read failure + ... + """ + # I p1 handle + # I p2 reg + # I p3 4 + ## extension ## + # I count + extents = [struct.pack("I", count)] + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_I2CRI, handle, reg, 4, extents)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def i2c_read_device(self, handle, count): + """ + Returns count bytes read from the raw device associated + with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + count:= >0, the number of bytes to read. + + . . + S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P + . . + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (count, data) = await pi.i2c_read_device(h, 12) + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i( + await _pigpio_command_nolock(self.sl, _PI_CMD_I2CRD, handle, count)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def i2c_write_device(self, handle, data): + """ + Writes the data bytes to the raw device associated with handle. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + data:= the bytes to write. + + . . + S Addr Wr [A] data0 [A] data1 [A] ... [A] datan [A] P + . . + + ... + await pi.i2c_write_device(h, b"\\x12\\x34\\xA8") + + await pi.i2c_write_device(h, b"help") + + await pi.i2c_write_device(h, 'help') + + await pi.i2c_write_device(h, [23, 56, 231]) + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + if len(data): + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_I2CWD, handle, 0, len(data), [data])) + else: + return 0 + + + async def i2c_zip(self, handle, data): + """ + This function executes a sequence of I2C operations. The + operations to be performed are specified by the contents of data + which contains the concatenated command codes and associated data. + + handle:= >=0 (as returned by a prior call to [*i2c_open*]). + data:= the concatenated I2C commands, see below + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (count, data) = await pi.i2c_zip(h, [4, 0x53, 7, 1, 0x32, 6, 6, 0]) + ... + + The following command codes are supported: + + Name @ Cmd & Data @ Meaning + End @ 0 @ No more commands + Escape @ 1 @ Next P is two bytes + On @ 2 @ Switch combined flag on + Off @ 3 @ Switch combined flag off + Address @ 4 P @ Set I2C address to P + Flags @ 5 lsb msb @ Set I2C flags to lsb + (msb << 8) + Read @ 6 P @ Read P bytes of data + Write @ 7 P ... @ Write P bytes of data + + The address, read, and write commands take a parameter P. + Normally P is one byte (0-255). If the command is preceded by + the Escape command then P is two bytes (0-65535, least significant + byte first). + + The address defaults to that associated with the handle. + The flags default to 0. The address and flags maintain their + previous value until updated. + + Any read I2C data is concatenated in the returned bytearray. + + ... + Set address 0x53, write 0x32, read 6 bytes + Set address 0x1E, write 0x03, read 6 bytes + Set address 0x68, write 0x1B, read 8 bytes + End + + 0x04 0x53 0x07 0x01 0x32 0x06 0x06 + 0x04 0x1E 0x07 0x01 0x03 0x06 0x06 + 0x04 0x68 0x07 0x01 0x1B 0x06 0x08 + 0x00 + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_I2CZ, handle, 0, len(data), [data])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + + async def bb_spi_open(self, CS, MISO, MOSI, SCLK, baud=100000, spi_flags=0): + """ + This function selects a set of GPIO for bit banging SPI at a + specified baud rate. + + CS := 0-31 + MISO := 0-31 + MOSI := 0-31 + SCLK := 0-31 + baud := 50-250000 + spiFlags := see below + + spiFlags consists of the least significant 22 bits. + + . . + 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + 0 0 0 0 0 0 R T 0 0 0 0 0 0 0 0 0 0 0 p m m + . . + + mm defines the SPI mode, defaults to 0 + + . . + Mode CPOL CPHA + 0 0 0 + 1 0 1 + 2 1 0 + 3 1 1 + . . + + The following constants may be used to set the mode: + + . . + asyncpio.SPI_MODE_0 + asyncpio.SPI_MODE_1 + asyncpio.SPI_MODE_2 + asyncpio.SPI_MODE_3 + . . + + Alternatively asyncpio.SPI_CPOL and/or asyncpio.SPI_CPHA + may be used. + + p is 0 if CS is active low (default) and 1 for active high. + asyncpio.SPI_CS_HIGH_ACTIVE may be used to set this flag. + + T is 1 if the least significant bit is transmitted on MOSI first, + the default (0) shifts the most significant bit out first. + asyncpio.SPI_TX_LSBFIRST may be used to set this flag. + + R is 1 if the least significant bit is received on MISO first, + the default (0) receives the most significant bit first. + asyncpio.SPI_RX_LSBFIRST may be used to set this flag. + + The other bits in spiFlags should be set to zero. + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or + PI_GPIO_IN_USE. + + If more than one device is connected to the SPI bus (defined by + SCLK, MOSI, and MISO) each must have its own CS. + + ... + bb_spi_open(10, MISO, MOSI, SCLK, 10000, 0); // device 1 + bb_spi_open(11, MISO, MOSI, SCLK, 20000, 3); // device 2 + ... + """ + # I p1 CS + # I p2 0 + # I p3 20 + ## extension ## + # I MISO + # I MOSI + # I SCLK + # I baud + # I spi_flags + + extents = [struct.pack("IIIII", MISO, MOSI, SCLK, baud, spi_flags)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_BSPIO, CS, 0, 20, extents)) + + + async def bb_spi_close(self, CS): + """ + This function stops bit banging SPI on a set of GPIO + opened with [*bb_spi_open*]. + + CS:= 0-31, the CS GPIO used in a prior call to [*bb_spi_open*] + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO. + + ... + await pi.bb_spi_close(CS) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_BSPIC, CS, 0)) + + + async def bb_spi_xfer(self, CS, data): + """ + This function executes a bit banged SPI transfer. + + CS:= 0-31 (as used in a prior call to [*bb_spi_open*]) + data:= data to be sent + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + #!/usr/bin/env python + import asyncio + import asyncpio + + CE0=5 + CE1=6 + MISO=13 + MOSI=19 + SCLK=12 + + async def main(pi): + try: + await pi.connect() + except: + exit() + + await pi.bb_spi_open(CE0, MISO, MOSI, SCLK, 10000, 0) # MCP4251 DAC + await pi.bb_spi_open(CE1, MISO, MOSI, SCLK, 20000, 3) # MCP3008 ADC + + for i in range(256): + + count, data = await pi.bb_spi_xfer(CE0, [0, i]) # Set DAC value + + if count == 2: + + count, data = await pi.bb_spi_xfer(CE0, [12, 0]) # Read back DAC + + if count == 2: + + set_val = data[1] + + count, data = await pi.bb_spi_xfer(CE1, [1, 128, 0]) # Read ADC + + if count == 3: + + read_val = ((data[1]&3)<<8) | data[2] + + print("{} {}".format(set_val, read_val)) + + await pi.bb_spi_close(CE0) + await pi.bb_spi_close(CE1) + + await pi.stop() + + pi = asyncpio.pi() + loop = asyncio.get_event_loop() + loop.run_until_complete(main(pi)) + ... + """ + # I p1 CS + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_BSPIX, CS, 0, len(data), [data])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + + async def bb_i2c_open(self, SDA, SCL, baud=100000): + """ + This function selects a pair of GPIO for bit banging I2C at a + specified baud rate. + + Bit banging I2C allows for certain operations which are not possible + with the standard I2C driver. + + o baud rates as low as 50 + o repeated starts + o clock stretching + o I2C on any pair of spare GPIO + + SDA:= 0-31 + SCL:= 0-31 + baud:= 50-500000 + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_I2C_BAUD, or + PI_GPIO_IN_USE. + + NOTE: + + The GPIO used for SDA and SCL must have pull-ups to 3V3 connected. + As a guide the hardware pull-ups on pins 3 and 5 are 1k8 in value. + + ... + h = await pi.bb_i2c_open(4, 5, 50000) # bit bang on GPIO 4/5 at 50kbps + ... + """ + # I p1 SDA + # I p2 SCL + # I p3 4 + ## extension ## + # I baud + extents = [struct.pack("I", baud)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_BI2CO, SDA, SCL, 4, extents)) + + + async def bb_i2c_close(self, SDA): + """ + This function stops bit banging I2C on a pair of GPIO + previously opened with [*bb_i2c_open*]. + + SDA:= 0-31, the SDA GPIO used in a prior call to [*bb_i2c_open*] + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO. + + ... + await pi.bb_i2c_close(SDA) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_BI2CC, SDA, 0)) + + + async def bb_i2c_zip(self, SDA, data): + """ + This function executes a sequence of bit banged I2C operations. + The operations to be performed are specified by the contents + of data which contains the concatenated command codes and + associated data. + + SDA:= 0-31 (as used in a prior call to [*bb_i2c_open*]) + data:= the concatenated I2C commands, see below + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (count, data) = await pi.bb_i2c_zip( + SDA, [4, 0x53, 2, 7, 1, 0x32, 2, 6, 6, 3, 0]) + ... + + The following command codes are supported: + + Name @ Cmd & Data @ Meaning + End @ 0 @ No more commands + Escape @ 1 @ Next P is two bytes + Start @ 2 @ Start condition + Stop @ 3 @ Stop condition + Address @ 4 P @ Set I2C address to P + Flags @ 5 lsb msb @ Set I2C flags to lsb + (msb << 8) + Read @ 6 P @ Read P bytes of data + Write @ 7 P ... @ Write P bytes of data + + The address, read, and write commands take a parameter P. + Normally P is one byte (0-255). If the command is preceded by + the Escape command then P is two bytes (0-65535, least significant + byte first). + + The address and flags default to 0. The address and flags maintain + their previous value until updated. + + No flags are currently defined. + + Any read I2C data is concatenated in the returned bytearray. + + ... + Set address 0x53 + start, write 0x32, (re)start, read 6 bytes, stop + Set address 0x1E + start, write 0x03, (re)start, read 6 bytes, stop + Set address 0x68 + start, write 0x1B, (re)start, read 8 bytes, stop + End + + 0x04 0x53 + 0x02 0x07 0x01 0x32 0x02 0x06 0x06 0x03 + + 0x04 0x1E + 0x02 0x07 0x01 0x03 0x02 0x06 0x06 0x03 + + 0x04 0x68 + 0x02 0x07 0x01 0x1B 0x02 0x06 0x08 0x03 + + 0x00 + ... + """ + # I p1 SDA + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_BI2CZ, SDA, 0, len(data), [data])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def event_trigger(self, event): + """ + This function signals the occurrence of an event. + + event:= 0-31, the event + + Returns 0 if OK, otherwise PI_BAD_EVENT_ID. + + An event is a signal used to inform one or more consumers + to start an action. Each consumer which has registered an + interest in the event (e.g. by calling [*event_callback*]) will + be informed by a callback. + + One event, EVENT_BSC (31) is predefined. This event is + auto generated on BSC slave activity. + + The meaning of other events is arbitrary. + + Note that other than its id and its tick there is no data associated + with an event. + + ... + await pi.event_trigger(23) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_EVT, event, 0)) + + + async def bsc_xfer(self, bsc_control, data): + """ + This function provides a low-level interface to the SPI/I2C Slave + peripheral on the BCM chip. + + This peripheral allows the Pi to act as a hardware slave device + on an I2C or SPI bus. + + This is not a bit bang version and as such is OS timing + independent. The bus timing is handled directly by the chip. + + The output process is simple. You simply append data to the FIFO + buffer on the chip. This works like a queue, you add data to the + queue and the master removes it. + + The function sets the BSC mode, writes any data in + the transmit buffer to the BSC transmit FIFO, and + copies any data in the BSC receive FIFO to the + receive buffer. + + bsc_control:= see below + data:= the data bytes to place in the transmit FIFO. + + The returned value is a tuple of the status (see below), + the number of bytes read, and a bytearray containing the + read bytes. If there was an error the status will be less + than zero (and will contain the error code). + + Note that the control word sets the BSC mode. The BSC will + stay in that mode until a different control word is sent. + + GPIO used for models other than those based on the BCM2711. + + @ SDA @ SCL @ MOSI @ SCLK @ MISO @ CE + I2C @ 18 @ 19 @ - @ - @ - @ - + SPI @ - @ - @ 20 @ 19 @ 18 @ 21 + + GPIO used for models based on the BCM2711 (e.g. the Pi4B). + + @ SDA @ SCL @ MOSI @ SCLK @ MISO @ CE + I2C @ 10 @ 11 @ - @ - @ - @ - + SPI @ - @ - @ 9 @ 11 @ 10 @ 8 + + When a zero control word is received the used GPIO will be reset + to INPUT mode. + + bsc_control consists of the following bits: + + . . + 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + a a a a a a a - - IT HC TF IR RE TE BK EC ES PL PH I2 SP EN + . . + + Bits 0-13 are copied unchanged to the BSC CR register. See + pages 163-165 of the Broadcom peripherals document for full + details. + + aaaaaaa @ defines the I2C slave address (only relevant in I2C mode) + IT @ invert transmit status flags + HC @ enable host control + TF @ enable test FIFO + IR @ invert receive status flags + RE @ enable receive + TE @ enable transmit + BK @ abort operation and clear FIFOs + EC @ send control register as first I2C byte + ES @ send status register as first I2C byte + PL @ set SPI polarity high + PH @ set SPI phase high + I2 @ enable I2C mode + SP @ enable SPI mode + EN @ enable BSC peripheral + + The status has the following format: + + . . + 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + S S S S S R R R R R T T T T T RB TE RF TF RE TB + . . + + Bits 0-15 are copied unchanged from the BSC FR register. See + pages 165-166 of the Broadcom peripherals document for full + details. + + SSSSS @ number of bytes successfully copied to transmit FIFO + RRRRR @ number of bytes in receive FIFO + TTTTT @ number of bytes in transmit FIFO + RB @ receive busy + TE @ transmit FIFO empty + RF @ receive FIFO full + TF @ transmit FIFO full + RE @ receive FIFO empty + TB @ transmit busy + + ... + (status, count, data) = await pi.bsc_xfer(0x330305, "Hello!") + ... + + The BSC slave in SPI mode deserializes data from the MOSI pin into its + receiver/FIFO when the LSB of the first byte is a 0. No data is output on + the MISO pin. When the LSB of the first byte on MOSI is a 1, the + transmitter/FIFO data is serialized onto the MISO pin while all other data + on the MOSI pin is ignored. + + The BK bit of the BSC control register is non-functional when in the SPI + mode. The transmitter along with its FIFO can be dequeued by successively + disabling and re-enabling the TE bit on the BSC control register while in + SPI mode. + + This example demonstrates a SPI master talking to the BSC as SPI slave: + Requires SPI master SCLK / MOSI / MISO / CE GPIO are connected to + BSC peripheral GPIO 11 / 9 / 10 / 8 respectively, on a Pi4B (BCM2711). + + ... + #!/usr/bin/env python + + import asyncpio + + # Choose some random GPIO for the bit-bang SPI master + CE=15 + MISO=26 + MOSI=13 + SCLK=14 + + async def main(pi): + try: + await pi.connect() + except: + exit() + + pi.bb_spi_open(CE, MISO, MOSI, SCLK, 10000, 0) # open SPI master + pi.bsc_xfer(0x303, []) # start BSC as SPI slave + pi.bb_spi_xfer(CE, '\0' + 'hello') # write 'hello' to BSC + status, count, bsc_data = pi.bsc_xfer(0x303, 'world') + print bsc_data # hello + count, spi_data = pi.bb_spi_xfer(CE, [1,0,0,0,0,0]) + print spi_data # world + + pi.bsc_xfer(0, []) + pi.bb_spi_close(CE) + + await pi.stop() + + pi = asyncpio.pi() + loop = asyncio.get_event_loop() + loop.run_until_complete(main(pi)) + ... + """ + # I p1 control + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + status = PI_CMD_INTERRUPTED + bytes = 0 + rdata = bytearray(b'') + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_BSCX, bsc_control, 0, len(data), [data])) + if bytes > 0: + rx = await self._rxbuf(bytes) + status = struct.unpack('I', rx[0:4])[0] + bytes -= 4 + rdata = rx[4:] + else: + status = bytes + bytes = 0 + return status, bytes, rdata + + async def bsc_i2c(self, i2c_address, data=[]): + """ + This function allows the Pi to act as a slave I2C device. + + The data bytes (if any) are written to the BSC transmit + FIFO and the bytes in the BSC receive FIFO are returned. + + i2c_address:= the I2C slave address. + data:= the data bytes to transmit. + + The returned value is a tuple of the status, the number + of bytes read, and a bytearray containing the read bytes. + + See [*bsc_xfer*] for details of the status value. + + If there was an error the status will be less than zero + (and will contain the error code). + + Note that an i2c_address of 0 may be used to close + the BSC device and reassign the used GPIO as inputs. + + This example assumes GPIO 2/3 are connected to GPIO 18/19 + (GPIO 10/11 on the BCM2711). + + ... + #!/usr/bin/env python + import asyncio + import time + import asyncpio + + I2C_ADDR=0x13 + + async def i2c(id, tick): + global pi + + s, b, d = await pi.bsc_i2c(I2C_ADDR) + if b: + if d[0] == ord('t'): # 116 send 'HH:MM:SS*' + + print("sent={} FR={} received={} [{}]". + format(s>>16, s&0xfff,b,d)) + + s, b, d = await pi.bsc_i2c(I2C_ADDR, + "{}*".format(time.asctime()[11:19])) + + elif d[0] == ord('d'): # 100 send 'Sun Oct 30*' + + print("sent={} FR={} received={} [{}]". + format(s>>16, s&0xfff,b,d)) + + s, b, d = await pi.bsc_i2c(I2C_ADDR, + "{}*".format(time.asctime()[:10])) + + async def main(pi): + try: + await pi.connect() + except: + exit() + + # Respond to BSC slave activity + + e = await pi.event_callback(asyncpio.EVENT_BSC, i2c) + + await pi.bsc_i2c(I2C_ADDR) # Configure BSC as I2C slave + + await asyncio.sleep(600) + + e.cancel() + + await pi.bsc_i2c(0) # Disable BSC peripheral + + await pi.stop() + + pi = asyncpio.pi() + loop = asyncio.get_event_loop() + loop.run_until_complete(main(pi)) + ... + + While running the above. + + . . + $ i2cdetect -y 1 + 0 1 2 3 4 5 6 7 8 9 a b c d e f + 00: -- -- -- -- -- -- -- -- -- -- -- -- -- + 10: -- -- -- 13 -- -- -- -- -- -- -- -- -- -- -- -- + 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + 70: -- -- -- -- -- -- -- -- + + $ pigs i2co 1 0x13 0 + 0 + + $ pigs i2cwd 0 116 + $ pigs i2crd 0 9 -a + 9 10:13:58* + + $ pigs i2cwd 0 116 + $ pigs i2crd 0 9 -a + 9 10:14:29* + + $ pigs i2cwd 0 100 + $ pigs i2crd 0 11 -a + 11 Sun Oct 30* + + $ pigs i2cwd 0 100 + $ pigs i2crd 0 11 -a + 11 Sun Oct 30* + + $ pigs i2cwd 0 116 + $ pigs i2crd 0 9 -a + 9 10:23:16* + + $ pigs i2cwd 0 100 + $ pigs i2crd 0 11 -a + 11 Sun Oct 30* + . . + """ + if i2c_address: + control = (i2c_address<<16)|0x305 + else: + control = 0 + return await self.bsc_xfer(control, data) + + async def spi_open(self, spi_channel, baud, spi_flags=0): + """ + Returns a handle for the SPI device on the channel. Data + will be transferred at baud bits per second. The flags + may be used to modify the default behaviour of 4-wire + operation, mode 0, active low chip select. + + The Pi has two SPI peripherals: main and auxiliary. + + The main SPI has two chip selects (channels), the auxiliary + has three. + + The auxiliary SPI is available on all models but the A and B. + + The GPIO used are given in the following table. + + @ MISO @ MOSI @ SCLK @ CE0 @ CE1 @ CE2 + Main SPI @ 9 @ 10 @ 11 @ 8 @ 7 @ - + Aux SPI @ 19 @ 20 @ 21 @ 18 @ 17 @ 16 + + spi_channel:= 0-1 (0-2 for the auxiliary SPI). + baud:= 32K-125M (values above 30M are unlikely to work). + spi_flags:= see below. + + spi_flags consists of the least significant 22 bits. + + . . + 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m + . . + + mm defines the SPI mode. + + WARNING: modes 1 and 3 do not appear to work on + the auxiliary SPI. + + . . + Mode POL PHA + 0 0 0 + 1 0 1 + 2 1 0 + 3 1 1 + . . + + px is 0 if CEx is active low (default) and 1 for active high. + + ux is 0 if the CEx GPIO is reserved for SPI (default) + and 1 otherwise. + + A is 0 for the main SPI, 1 for the auxiliary SPI. + + W is 0 if the device is not 3-wire, 1 if the device is 3-wire. + Main SPI only. + + nnnn defines the number of bytes (0-15) to write before + switching the MOSI line to MISO to read data. This field + is ignored if W is not set. Main SPI only. + + T is 1 if the least significant bit is transmitted on MOSI + first, the default (0) shifts the most significant bit out + first. Auxiliary SPI only. + + R is 1 if the least significant bit is received on MISO + first, the default (0) receives the most significant bit + first. Auxiliary SPI only. + + bbbbbb defines the word size in bits (0-32). The default (0) + sets 8 bits per word. Auxiliary SPI only. + + The [*spi_read*], [*spi_write*], and [*spi_xfer*] functions + transfer data packed into 1, 2, or 4 bytes according to + the word size in bits. + + For bits 1-8 there will be one byte per character. + For bits 9-16 there will be two bytes per character. + For bits 17-32 there will be four bytes per character. + + Multi-byte transfers are made in least significant byte + first order. + + E.g. to transfer 32 11-bit words data should + contain 64 bytes. + + E.g. to transfer the 14 bit value 0x1ABC send the + bytes 0xBC followed by 0x1A. + + The other bits in flags should be set to zero. + + ... + # open SPI device on channel 1 in mode 3 at 50000 bits per second + + h = await pi.spi_open(1, 50000, 3) + ... + """ + # I p1 spi_channel + # I p2 baud + # I p3 4 + ## extension ## + # I spi_flags + extents = [struct.pack("I", spi_flags)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SPIO, spi_channel, baud, 4, extents)) + + async def spi_close(self, handle): + """ + Closes the SPI device associated with handle. + + handle:= >=0 (as returned by a prior call to [*spi_open*]). + + ... + await pi.spi_close(h) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SPIC, handle, 0)) + + async def spi_read(self, handle, count): + """ + Reads count bytes from the SPI device associated with handle. + + handle:= >=0 (as returned by a prior call to [*spi_open*]). + count:= >0, the number of bytes to read. + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (b, d) = await pi.spi_read(h, 60) # read 60 bytes from device h + if b == 60: + # process read data + else: + # error path + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_nolock( + self.sl, _PI_CMD_SPIR, handle, count)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def spi_write(self, handle, data): + """ + Writes the data bytes to the SPI device associated with handle. + + handle:= >=0 (as returned by a prior call to [*spi_open*]). + data:= the bytes to write. + + ... + await pi.spi_write(0, b'\\x02\\xc0\\x80') # write 3 bytes to device 0 + + await pi.spi_write(0, b'defgh') # write 5 bytes to device 0 + + await pi.spi_write(0, "def") # write 3 bytes to device 0 + + await pi.spi_write(1, [2, 192, 128]) # write 3 bytes to device 1 + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SPIW, handle, 0, len(data), [data])) + + async def spi_xfer(self, handle, data): + """ + Writes the data bytes to the SPI device associated with handle, + returning the data bytes read from the device. + + handle:= >=0 (as returned by a prior call to [*spi_open*]). + data:= the bytes to write. + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (count, rx_data) = await pi.spi_xfer(h, b'\\x01\\x80\\x00') + + (count, rx_data) = await pi.spi_xfer(h, [1, 128, 0]) + + (count, rx_data) = await pi.spi_xfer(h, b"hello") + + (count, rx_data) = await pi.spi_xfer(h, "hello") + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_SPIX, handle, 0, len(data), [data])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def serial_open(self, tty, baud, ser_flags=0): + """ + Returns a handle for the serial tty device opened + at baud bits per second. The device name must start + with /dev/tty or /dev/serial. + + tty:= the serial device to open. + baud:= baud rate in bits per second, see below. + ser_flags:= 0, no flags are currently defined. + + Normally you would only use the [*serial_**] functions if + you are or will be connecting to the Pi over a network. If + you will always run on the local Pi use the standard serial + module instead. + + The baud rate must be one of 50, 75, 110, 134, 150, + 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, + 38400, 57600, 115200, or 230400. + + ... + h1 = await pi.serial_open("/dev/ttyAMA0", 300) + + h2 = await pi.serial_open("/dev/ttyUSB1", 19200, 0) + + h3 = await pi.serial_open("/dev/serial0", 9600) + ... + """ + # I p1 baud + # I p2 ser_flags + # I p3 len + ## extension ## + # s len data bytes + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SERO, baud, ser_flags, len(tty), [tty])) + + async def serial_close(self, handle): + """ + Closes the serial device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + + ... + await pi.serial_close(h1) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SERC, handle, 0)) + + async def serial_read_byte(self, handle): + """ + Returns a single byte from the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + + If no data is ready a negative error code will be returned. + + ... + b = await pi.serial_read_byte(h1) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SERRB, handle, 0)) + + async def serial_write_byte(self, handle, byte_val): + """ + Writes a single byte to the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + byte_val:= 0-255, the value to write. + + ... + await pi.serial_write_byte(h1, 23) + + await pi.serial_write_byte(h1, ord('Z')) + ... + """ + return _u2i( + await _pigpio_command(self.sl, _PI_CMD_SERWB, handle, byte_val)) + + async def serial_read(self, handle, count=1000): + """ + Reads up to count bytes from the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + count:= >0, the number of bytes to read (defaults to 1000). + + The returned value is a tuple of the number of bytes read and + a bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + If no data is ready a bytes read of zero is returned. + ... + (b, d) = await pi.serial_read(h2, 100) + if b > 0: + # process read data + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i( + await _pigpio_command_nolock(self.sl, _PI_CMD_SERR, handle, count)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def serial_write(self, handle, data): + """ + Writes the data bytes to the device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + data:= the bytes to write. + + ... + await pi.serial_write(h1, b'\\x02\\x03\\x04') + + await pi.serial_write(h2, b'help') + + await pi.serial_write(h2, "hello") + + await pi.serial_write(h1, [2, 3, 4]) + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SERW, handle, 0, len(data), [data])) + + async def serial_data_available(self, handle): + """ + Returns the number of bytes available to be read from the + device associated with handle. + + handle:= >=0 (as returned by a prior call to [*serial_open*]). + + ... + rdy = await pi.serial_data_available(h1) + + if rdy > 0: + (b, d) = await pi.serial_read(h1, rdy) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SERDA, handle, 0)) + + async def gpio_trigger(self, user_gpio, pulse_len=10, level=1): + """ + Send a trigger pulse to a GPIO. The GPIO is set to + level for pulse_len microseconds and then reset to not level. + + user_gpio:= 0-31 + pulse_len:= 1-100 + level:= 0-1 + + ... + await pi.gpio_trigger(23, 10, 1) + ... + """ + # pigpio message format + + # I p1 user_gpio + # I p2 pulse_len + # I p3 4 + ## extension ## + # I level + extents = [struct.pack("I", level)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_TRIG, user_gpio, pulse_len, 4, extents)) + + async def set_glitch_filter(self, user_gpio, steady): + """ + Sets a glitch filter on a GPIO. + + Level changes on the GPIO are not reported unless the level + has been stable for at least [*steady*] microseconds. The + level is then reported. Level changes of less than [*steady*] + microseconds are ignored. + + user_gpio:= 0-31 + steady:= 0-300000 + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER. + + This filter affects the GPIO samples returned to callbacks set up + with [*callback*] and [*wait_for_edge*]. + + It does not affect levels read by [*read*], + [*read_bank_1*], or [*read_bank_2*]. + + Each (stable) edge will be timestamped [*steady*] + microseconds after it was first detected. + + ... + await pi.set_glitch_filter(23, 100) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_FG, user_gpio, steady)) + + async def set_noise_filter(self, user_gpio, steady, active): + """ + Sets a noise filter on a GPIO. + + Level changes on the GPIO are ignored until a level which has + been stable for [*steady*] microseconds is detected. Level + changes on the GPIO are then reported for [*active*] + microseconds after which the process repeats. + + user_gpio:= 0-31 + steady:= 0-300000 + active:= 0-1000000 + + Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_BAD_FILTER. + + This filter affects the GPIO samples returned to callbacks set up + with [*callback*] and [*wait_for_edge*]. + + It does not affect levels read by [*read*], + [*read_bank_1*], or [*read_bank_2*]. + + Level changes before and after the active period may + be reported. Your software must be designed to cope with + such reports. + + ... + await pi.set_noise_filter(23, 1000, 5000) + ... + """ + # pigpio message format + + # I p1 user_gpio + # I p2 steady + # I p3 4 + ## extension ## + # I active + extents = [struct.pack("I", active)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_FN, user_gpio, steady, 4, extents)) + + async def store_script(self, script): + """ + Store a script for later execution. + + See [[http://abyz.me.uk/rpi/pigpio/pigs.html#Scripts]] for + details. + + script:= the script text as a series of bytes. + + Returns a >=0 script id if OK. + + ... + sid = await pi.store_script( + b'tag 0 w 22 1 mils 100 w 22 0 mils 100 dcr p0 jp 0') + ... + """ + # I p1 0 + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + if len(script): + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_PROC, 0, 0, len(script), [script])) + else: + return 0 + + async def run_script(self, script_id, params=None): + """ + Runs a stored script. + + script_id:= id of stored script. + params:= up to 10 parameters required by the script. + + ... + s = await pi.run_script(sid, [par1, par2]) + + s = await pi.run_script(sid) + + s = await pi.run_script(sid, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + ... + """ + # I p1 script id + # I p2 0 + # I p3 params * 4 (0-10 params) + ## (optional) extension ## + # I[] params + if params is not None: + ext = bytearray() + for p in params: + ext.extend(struct.pack("I", p)) + nump = len(params) + extents = [ext] + else: + nump = 0 + extents = [] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_PROCR, script_id, 0, nump*4, extents)) + + async def update_script(self, script_id, params=None): + """ + Sets the parameters of a script. The script may or + may not be running. The first parameters of the script are + overwritten with the new values. + + script_id:= id of stored script. + params:= up to 10 parameters required by the script. + + ... + s = await pi.update_script(sid, [par1, par2]) + + s = await pi.update_script(sid, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + ... + """ + # I p1 script id + # I p2 0 + # I p3 params * 4 (0-10 params) + ## (optional) extension ## + # I[] params + if params is not None: + ext = bytearray() + for p in params: + ext.extend(struct.pack("I", p)) + nump = len(params) + extents = [ext] + else: + nump = 0 + extents = [] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_PROCU, script_id, 0, nump*4, extents)) + + async def script_status(self, script_id): + """ + Returns the run status of a stored script as well as the + current values of parameters 0 to 9. + + script_id:= id of stored script. + + The run status may be + + . . + PI_SCRIPT_INITING + PI_SCRIPT_HALTED + PI_SCRIPT_RUNNING + PI_SCRIPT_WAITING + PI_SCRIPT_FAILED + . . + + The return value is a tuple of run status and a list of + the 10 parameters. On error the run status will be negative + and the parameter list will be empty. + + ... + (s, pars) = await pi.script_status(sid) + ... + """ + status = PI_CMD_INTERRUPTED + params = () + async with self.sl.l: + bytes = u2i( + await _pigpio_command_nolock(self.sl, _PI_CMD_PROCP, script_id, 0)) + if bytes > 0: + data = await self._rxbuf(bytes) + pars = struct.unpack('11i', _str(data)) + status = pars[0] + params = pars[1:] + else: + status = bytes + return status, params + + async def stop_script(self, script_id): + """ + Stops a running script. + + script_id:= id of stored script. + + ... + status = await pi.stop_script(sid) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PROCS, script_id, 0)) + + async def delete_script(self, script_id): + """ + Deletes a stored script. + + script_id:= id of stored script. + + ... + status = await pi.delete_script(sid) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PROCD, script_id, 0)) + + async def bb_serial_read_open(self, user_gpio, baud, bb_bits=8): + """ + Opens a GPIO for bit bang reading of serial data. + + user_gpio:= 0-31, the GPIO to use. + baud:= 50-250000, the baud rate. + bb_bits:= 1-32, the number of bits per word, default 8. + + The serial data is held in a cyclic buffer and is read using + [*bb_serial_read*]. + + It is the caller's responsibility to read data from the cyclic + buffer in a timely fashion. + + ... + status = await pi.bb_serial_read_open(4, 19200) + status = await pi.bb_serial_read_open(17, 9600) + ... + """ + # pigpio message format + + # I p1 user_gpio + # I p2 baud + # I p3 4 + ## extension ## + # I bb_bits + extents = [struct.pack("I", bb_bits)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SLRO, user_gpio, baud, 4, extents)) + + async def bb_serial_read(self, user_gpio): + """ + Returns data from the bit bang serial cyclic buffer. + + user_gpio:= 0-31 (opened in a prior call to [*bb_serial_read_open*]) + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + The bytes returned for each character depend upon the number of + data bits [*bb_bits*] specified in the [*bb_serial_read_open*] + command. + + For [*bb_bits*] 1-8 there will be one byte per character. + For [*bb_bits*] 9-16 there will be two bytes per character. + For [*bb_bits*] 17-32 there will be four bytes per character. + + ... + (count, data) = await pi.bb_serial_read(4) + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i( + await _pigpio_command_nolock(self.sl, _PI_CMD_SLR, user_gpio, 10000)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def bb_serial_read_close(self, user_gpio): + """ + Closes a GPIO for bit bang reading of serial data. + + user_gpio:= 0-31 (opened in a prior call to [*bb_serial_read_open*]) + + ... + status = await pi.bb_serial_read_close(17) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SLRC, user_gpio, 0)) + + async def bb_serial_invert(self, user_gpio, invert): + """ + Invert serial logic. + + user_gpio:= 0-31 (opened in a prior call to [*bb_serial_read_open*]) + invert:= 0-1 (1 invert, 0 normal) + + ... + status = await pi.bb_serial_invert(17, 1) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_SLRI, user_gpio, invert)) + + + async def custom_1(self, arg1=0, arg2=0, argx=[]): + """ + Calls a pigpio function customised by the user. + + arg1:= >=0, default 0. + arg2:= >=0, default 0. + argx:= extra arguments (each 0-255), default empty. + + The returned value is an integer which by convention + should be >=0 for OK and <0 for error. + + ... + value = await pi.custom_1() + + value = await pi.custom_1(23) + + value = await pi.custom_1(0, 55) + + value = await pi.custom_1(23, 56, [1, 5, 7]) + + value = await pi.custom_1(23, 56, b"hello") + + value = await pi.custom_1(23, 56, "hello") + ... + """ + # I p1 arg1 + # I p2 arg2 + # I p3 len + ## extension ## + # s len argx bytes + + return u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_CF1, arg1, arg2, len(argx), [argx])) + + async def custom_2(self, arg1=0, argx=[], retMax=8192): + """ + Calls a pigpio function customised by the user. + + arg1:= >=0, default 0. + argx:= extra arguments (each 0-255), default empty. + retMax:= >=0, maximum number of bytes to return, default 8192. + + The returned value is a tuple of the number of bytes + returned and a bytearray containing the bytes. If + there was an error the number of bytes read will be + less than zero (and will contain the error code). + + ... + (count, data) = await pi.custom_2() + + (count, data) = await pi.custom_2(23) + + (count, data) = await pi.custom_2(23, [1, 5, 7]) + + (count, data) = await pi.custom_2(23, b"hello") + + (count, data) = await pi.custom_2(23, "hello", 128) + ... + """ + # I p1 arg1 + # I p2 retMax + # I p3 len + ## extension ## + # s len argx bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_CF2, arg1, retMax, len(argx), [argx])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def get_pad_strength(self, pad): + """ + This function returns the pad drive strength in mA. + + pad:= 0-2, the pad to get. + + Returns the pad drive strength if OK, otherwise PI_BAD_PAD. + + Pad @ GPIO + 0 @ 0-27 + 1 @ 28-45 + 2 @ 46-53 + + ... + strength = await pi.get_pad_strength(0) # Get pad 0 strength. + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PADG, pad, 0)) + + async def set_pad_strength(self, pad, pad_strength): + """ + This function sets the pad drive strength in mA. + + + pad:= 0-2, the pad to set. + pad_strength:= 1-16 mA. + + Returns 0 if OK, otherwise PI_BAD_PAD, or PI_BAD_STRENGTH. + + Pad @ GPIO + 0 @ 0-27 + 1 @ 28-45 + 2 @ 46-53 + + ... + await pi.set_pad_strength(2, 14) # Set pad 2 to 14 mA. + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_PADS, pad, pad_strength)) + + + async def file_open(self, file_name, file_mode): + """ + This function returns a handle to a file opened in a specified mode. + + file_name:= the file to open. + file_mode:= the file open mode. + + Returns a handle (>=0) if OK, otherwise PI_NO_HANDLE, + PI_NO_FILE_ACCESS, PI_BAD_FILE_MODE, + PI_FILE_OPEN_FAILED, or PI_FILE_IS_A_DIR. + + ... + h = await pi.file_open("/home/pi/shared/dir_3/file.txt", + asyncpio.FILE_WRITE | asyncpio.FILE_CREATE) + + await pi.file_write(h, "Hello world") + + await pi.file_close(h) + ... + + File + + A file may only be opened if permission is granted by an entry + in /opt/pigpio/access. This is intended to allow remote access + to files in a more or less controlled manner. + + Each entry in /opt/pigpio/access takes the form of a file path + which may contain wildcards followed by a single letter permission. + The permission may be R for read, W for write, U for read/write, + and N for no access. + + Where more than one entry matches a file the most specific rule + applies. If no entry matches a file then access is denied. + + Suppose /opt/pigpio/access contains the following entries: + + . . + /home/* n + /home/pi/shared/dir_1/* w + /home/pi/shared/dir_2/* r + /home/pi/shared/dir_3/* u + /home/pi/shared/dir_1/file.txt n + . . + + Files may be written in directory dir_1 with the exception + of file.txt. + + Files may be read in directory dir_2. + + Files may be read and written in directory dir_3. + + If a directory allows read, write, or read/write access then files + may be created in that directory. + + In an attempt to prevent risky permissions the following paths are + ignored in /opt/pigpio/access: + + . . + a path containing .. + a path containing only wildcards (*?) + a path containing less than two non-wildcard parts + . . + + Mode + + The mode may have the following values: + + Constant @ Value @ Meaning + FILE_READ @ 1 @ open file for reading + FILE_WRITE @ 2 @ open file for writing + FILE_RW @ 3 @ open file for reading and writing + + The following values may be or'd into the mode: + + Name @ Value @ Meaning + FILE_APPEND @ 4 @ All writes append data to the end of the file + FILE_CREATE @ 8 @ The file is created if it doesn't exist + FILE_TRUNC @ 16 @ The file is truncated + + Newly created files are owned by root with permissions owner + read and write. + + ... + #!/usr/bin/env python + import asyncio + import asyncpio + + async def main(pi): + try: + await pi.connect() + except: + exit() + + # Assumes /opt/pigpio/access contains the following line: + # /ram/*.c r + + handle = await pi.file_open("/ram/pigpio.c", asyncpio.FILE_READ) + + done = False + + while not done: + c, d = await pi.file_read(handle, 60000) + if c > 0: + print(d) + else: + done = True + + await pi.file_close(handle) + + await pi.stop() + + pi = asyncpio.pi() + loop = asyncio.get_event_loop() + loop.run_until_complete(main(pi)) + ... + """ + # I p1 file_mode + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_FO, file_mode, 0, len(file_name), [file_name])) + + async def file_close(self, handle): + """ + Closes the file associated with handle. + + handle:= >=0 (as returned by a prior call to [*file_open*]). + + ... + await pi.file_close(handle) + ... + """ + return _u2i(await _pigpio_command(self.sl, _PI_CMD_FC, handle, 0)) + + async def file_read(self, handle, count): + """ + Reads up to count bytes from the file associated with handle. + + handle:= >=0 (as returned by a prior call to [*file_open*]). + count:= >0, the number of bytes to read. + + The returned value is a tuple of the number of bytes read and a + bytearray containing the bytes. If there was an error the + number of bytes read will be less than zero (and will contain + the error code). + + ... + (b, d) = await pi.file_read(h2, 100) + if b > 0: + # process read data + ... + """ + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i( + await _pigpio_command_nolock(self.sl, _PI_CMD_FR, handle, count)) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def file_write(self, handle, data): + """ + Writes the data bytes to the file associated with handle. + + handle:= >=0 (as returned by a prior call to [*file_open*]). + data:= the bytes to write. + + ... + await pi.file_write(h1, b'\\x02\\x03\\x04') + + await pi.file_write(h2, b'help') + + await pi.file_write(h2, "hello") + + await pi.file_write(h1, [2, 3, 4]) + ... + """ + # I p1 handle + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_FW, handle, 0, len(data), [data])) + + async def file_seek(self, handle, seek_offset, seek_from): + """ + Seeks to a position relative to the start, current position, + or end of the file. Returns the new position. + + handle:= >=0 (as returned by a prior call to [*file_open*]). + seek_offset:= byte offset. + seek_from:= FROM_START, FROM_CURRENT, or FROM_END. + + ... + new_pos = await pi.file_seek(h, 100, asyncpio.FROM_START) + + cur_pos = await pi.file_seek(h, 0, asyncpio.FROM_CURRENT) + + file_size = await pi.file_seek(h, 0, asyncpio.FROM_END) + ... + """ + # I p1 handle + # I p2 seek_offset + # I p3 4 + ## extension ## + # I seek_from + extents = [struct.pack("I", seek_from)] + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_FS, handle, seek_offset, 4, extents)) + + async def file_list(self, fpattern): + """ + Returns a list of files which match a pattern. + + fpattern:= file pattern to match. + + Returns the number of returned bytes if OK, otherwise + PI_NO_FILE_ACCESS, or PI_NO_FILE_MATCH. + + The pattern must match an entry in /opt/pigpio/access. The + pattern may contain wildcards. See [*file_open*]. + + NOTE + + The returned value is not the number of files, it is the number + of bytes in the buffer. The file names are separated by newline + characters. + + ... + #!/usr/bin/env python + import asyncio + import asyncpio + + async def main(pi): + try: + await pi.connect() + except: + exit() + + # Assumes /opt/pigpio/access contains the following line: + # /ram/*.c r + + c, d = await pi.file_list("/ram/p*.c") + if c > 0: + print(d) + + await pi.stop() + + pi = asyncpio.pi() + loop = asyncio.get_event_loop() + loop.run_until_complete(main(pi)) + ... + """ + # I p1 60000 + # I p2 0 + # I p3 len + ## extension ## + # s len data bytes + + bytes = PI_CMD_INTERRUPTED + rdata = "" + async with self.sl.l: + bytes = u2i(await _pigpio_command_ext_nolock( + self.sl, _PI_CMD_FL, 60000, 0, len(fpattern), [fpattern])) + if bytes > 0: + rdata = await self._rxbuf(bytes) + return bytes, rdata + + async def shell(self, shellscr, pstring=""): + """ + This function uses the system call to execute a shell script + with the given string as its parameter. + + shellscr:= the name of the script, only alphanumerics, + '-' and '_' are allowed in the name + pstring := the parameter string to pass to the script + + The exit status of the system call is returned if OK, + otherwise PI_BAD_SHELL_STATUS. + + [*shellscr*] must exist in /opt/pigpio/cgi and must be executable. + + The returned exit status is normally 256 times that set by + the shell script exit function. If the script can't be + found 32512 will be returned. + + The following table gives some example returned statuses: + + Script exit status @ Returned system call status + 1 @ 256 + 5 @ 1280 + 10 @ 2560 + 200 @ 51200 + script not found @ 32512 + + ... + // pass two parameters, hello and world + status = await pi.shell("scr1", "hello world"); + + // pass three parameters, hello, string with spaces, and world + status = await pi.shell("scr1", "hello 'string with spaces' world"); + + // pass one parameter, hello string with spaces world + status = await pi.shell("scr1", "\\"hello string with spaces world\\""); + ... + """ + # I p1 len(shellscr) + # I p2 0 + # I p3 len(shellscr)+len(pstring)+1 + ## extension ## + # s len data bytes + + ls = len(shellscr) + lp = len(pstring) + return _u2i(await _pigpio_command_ext( + self.sl, _PI_CMD_SHELL, ls, 0, ls+lp+1, [shellscr+'\x00'+pstring])) + + + async def callback(self, user_gpio, edge=RISING_EDGE, func=None): + """ + Calls a user supplied function (a callback) whenever the + specified GPIO edge is detected. + + user_gpio:= 0-31. + edge:= EITHER_EDGE, RISING_EDGE (default), or FALLING_EDGE. + func:= user supplied callback function. + + The user supplied callback receives three parameters, the GPIO, + the level, and the tick. + + . . + Parameter Value Meaning + + GPIO 0-31 The GPIO which has changed state + + level 0-2 0 = change to low (a falling edge) + 1 = change to high (a rising edge) + 2 = no level change (a watchdog timeout) + + tick 32 bit The number of microseconds since boot + WARNING: this wraps around from + 4294967295 to 0 roughly every 72 minutes + . . + + If a user callback is not specified a default tally callback is + provided which simply counts edges. The count may be retrieved + by calling the tally function. The count may be reset to zero + by calling the reset_tally function. + + The callback may be cancelled by calling the cancel function. + + A GPIO may have multiple callbacks. + + The GPIO are sampled at a rate set when the pigpio daemon + is started (default 5 us). + + The number of samples per second is given in the following table. + + . . + samples + per sec + + 1 1,000,000 + 2 500,000 + sample 4 250,000 + rate 5 200,000 + (us) 8 125,000 + 10 100,000 + . . + + GPIO level changes shorter than the sample rate may be missed. + + The daemon software which generates the callbacks is triggered + 1000 times per second. The callbacks will be called once per + level change since the last time they were called. + i.e. The callbacks will get all level changes but there will + be a latency. + + If you want to track the level of more than one GPIO do so by + maintaining the state in the callback. Do not use [*read*]. + Remember the event that triggered the callback may have + happened several milliseconds before and the GPIO may have + changed level many times since then. + + ... + def cbf(gpio, level, tick): + print(gpio, level, tick) + + cb1 = await pi.callback(22, asyncpio.EITHER_EDGE, cbf) + + cb2 = await pi.callback(4, asyncpio.EITHER_EDGE) + + cb3 = await pi.callback(17) + + print(cb3.tally()) + + cb3.reset_tally() + + await cb1.cancel() # To cancel callback cb1. + ... + """ + cb = _callback(self._notify, user_gpio, edge, func) + await self._notify.append(cb.callb) + return cb + + async def event_callback(self, event, func=None): + """ + Calls a user supplied function (a callback) whenever the + specified event is signalled. + + event:= 0-31. + func:= user supplied callback function. + + The user supplied callback receives two parameters, the event id, + and the tick. + + If a user callback is not specified a default tally callback is + provided which simply counts events. The count may be retrieved + by calling the tally function. The count may be reset to zero + by calling the reset_tally function. + + The callback may be cancelled by calling the cancel function. + + An event may have multiple callbacks (although I can't think of + a reason to do so). + + ... + def cbf(event, tick): + print(event, tick) + + cb1 = await pi.event_callback(22, cbf) + + cb2 = await pi.event_callback(4) + + print(cb2.tally()) + + cb2.reset_tally() + + await cb1.cancel() # To cancel callback cb1. + ... + """ + + ecb = _event(self._notify, event, func) + await self._notify.append_event(ecb.callb) + return ecb + + async def wait_for_edge(self, user_gpio, edge=RISING_EDGE, wait_timeout=60.0): + """ + Wait for an edge event on a GPIO. + + user_gpio:= 0-31. + edge:= EITHER_EDGE, RISING_EDGE (default), or + FALLING_EDGE. + wait_timeout:= >=0.0 (default 60.0). + + The function returns when the edge is detected, else + raises an asyncio.TimeoutError after the number of seconds + specified by timeout has elapsed. + + Do not use this function for precise timing purposes. + Whenever you need to know the accurate time of GPIO events + use a [*callback*] function. + + ... + try: + await pi.wait_for_edge(23) + print("Rising edge detected") + except asyncio.TimeoutError: + print("wait for edge timed out") + + try: + await pi.wait_for_edge(23, asyncpio.FALLING_EDGE, 5.0) + print("Falling edge detected") + except asyncio.TimeoutError: + print("wait for falling edge timed out") + ... + """ + ew = _wait_for_edge(self._notify, user_gpio, edge) + await ew.wait_for(wait_timeout) + + async def wait_for_event(self, event, wait_timeout=60.0): + """ + Wait for an event. + + event:= 0-31. + wait_timeout:= >=0.0 (default 60.0). + + The function returns when the event is signalled, else + raises an asyncio.TimoutError after the number of seconds + specified by timeout has elapsed. + + Do not use this function for precise timing purposes. + Whenever you need to know the accurate time of GPIO events + use a [*callback*] function. + + ... + try: + await pi.wait_for_event(23) + print("event detected") + except asyncio.TimeoutError: + print("wait for event timed out") + ... + """ + ew = _wait_for_event(self._notify, event) + await ew.wait_for(wait_timeout) + + def __init__(self, loop=None): + """ + An API for accessing a Pi's GPIO. + + loop:= the asyncio event loop on which to run. By default, + run on the default asyncio event loop. + """ + if loop is None: + loop = asyncio.get_event_loop() + + self.sl = _socklock() + self._notify = None + self._loop = loop + + async def connect(self, + host = os.getenv("PIGPIO_ADDR", 'localhost'), + port = os.getenv("PIGPIO_PORT", 8888)): + """ + Connect to a pigpio daemon at (host, port). + + host:= the host name of the Pi on which the pigpio daemon is + running. The default is localhost unless overridden by + the PIGPIO_ADDR environment variable. + + port:= the port number on which the pigpio daemon is listening. + The default is 8888 unless overridden by the PIGPIO_PORT + environment variable. The pigpio daemon must have been + started with the same port number. + + This connects to the pigpio daemon and reserves resources + to be used for sending commands and receiving notifications. + + A asyncpio.error is raised if the connection cannot be + established. + + ... + pi = asyncpio.pi() + await pi.connect() # use defaults + pi = asyncpio.pi() + await pi.connect('mypi') # specify host, default port + pi = asyncpio.pi() + await pi.connect('mypi', 7777) # specify host and port + + + pi = asyncpio.pi() + try: + await pi.connect() + except asyncpio.error: + exit() # exit script if no connection + """ + self._port = int(port) + self._host = host + + try: + sock = socket.create_connection((self._host, self._port), None) + # Disable the Nagle algorithm. + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + + self.sl.s = _cosocket(self._loop, sock) + self._notify = _callback_handler(self.sl, loop=self._loop) + await self._notify.listen(self._host, self._port) + except: + s = "Can't connect to pigpio at {}({})".format(self._host, str(self._port)) + try: + raise + except socket.error as e: + raise error(_except_1.format(s)) from e + except struct.error as e: + raise error(_except_2.format(s)) from e + except error as e: + # Raised from _u2i on getting a negative value (an error) for the + # notification handle. + # Assume no handle available. + raise error(_except_3) from e + finally: + await self.stop() + + def __repr__(self): + return "".format(self._host, self._port) + + async def stop(self): + """Release pigpio daemon resources. + + ... + await pi.stop() + ... + """ + if self._notify is not None: + await self._notify.stop() + self._notify = None + + if self.sl.s is not None: + self.sl.s.close() + self.sl.s = None + +def xref(): + """ + active: 0-1000000 + The number of microseconds level changes are reported for once + a noise filter has been triggered (by [*steady*] microseconds of + a stable level). + + + arg1: + An unsigned argument passed to a user customised function. Its + meaning is defined by the customiser. + + arg2: + An unsigned argument passed to a user customised function. Its + meaning is defined by the customiser. + + argx: + An array of bytes passed to a user customised function. + Its meaning and content is defined by the customiser. + + baud: + The speed of serial communication (I2C, SPI, serial link, waves) + in bits per second. + + bb_bits: 1-32 + The number of data bits to be used when adding serial data to a + waveform. + + bb_stop: 2-8 + The number of (half) stop bits to be used when adding serial data + to a waveform. + + bit: 0-1 + A value of 0 or 1. + + bits: 32 bit number + A mask used to select GPIO to be operated on. If bit n is set + then GPIO n is selected. A convenient way of setting bit n is to + bit or in the value (1<=1 + The length of a pulse in microseconds. + + dutycycle: 0-range_ + A number between 0 and range_. + + The dutycycle sets the proportion of time on versus time off during each + PWM cycle. + + Dutycycle @ On time + 0 @ Off + range_ * 0.25 @ 25% On + range_ * 0.50 @ 50% On + range_ * 0.75 @ 75% On + range_ @ Fully On + + edge: 0-2 + + . . + EITHER_EDGE = 2 + FALLING_EDGE = 1 + RISING_EDGE = 0 + . . + + errnum: <0 + + . . + PI_BAD_USER_GPIO = -2 + PI_BAD_GPIO = -3 + PI_BAD_MODE = -4 + PI_BAD_LEVEL = -5 + PI_BAD_PUD = -6 + PI_BAD_PULSEWIDTH = -7 + PI_BAD_DUTYCYCLE = -8 + PI_BAD_WDOG_TIMEOUT = -15 + PI_BAD_DUTYRANGE = -21 + PI_NO_HANDLE = -24 + PI_BAD_HANDLE = -25 + PI_BAD_WAVE_BAUD = -35 + PI_TOO_MANY_PULSES = -36 + PI_TOO_MANY_CHARS = -37 + PI_NOT_SERIAL_GPIO = -38 + PI_NOT_PERMITTED = -41 + PI_SOME_PERMITTED = -42 + PI_BAD_WVSC_COMMND = -43 + PI_BAD_WVSM_COMMND = -44 + PI_BAD_WVSP_COMMND = -45 + PI_BAD_PULSELEN = -46 + PI_BAD_SCRIPT = -47 + PI_BAD_SCRIPT_ID = -48 + PI_BAD_SER_OFFSET = -49 + PI_GPIO_IN_USE = -50 + PI_BAD_SERIAL_COUNT = -51 + PI_BAD_PARAM_NUM = -52 + PI_DUP_TAG = -53 + PI_TOO_MANY_TAGS = -54 + PI_BAD_SCRIPT_CMD = -55 + PI_BAD_VAR_NUM = -56 + PI_NO_SCRIPT_ROOM = -57 + PI_NO_MEMORY = -58 + PI_SOCK_READ_FAILED = -59 + PI_SOCK_WRIT_FAILED = -60 + PI_TOO_MANY_PARAM = -61 + PI_SCRIPT_NOT_READY = -62 + PI_BAD_TAG = -63 + PI_BAD_MICS_DELAY = -64 + PI_BAD_MILS_DELAY = -65 + PI_BAD_WAVE_ID = -66 + PI_TOO_MANY_CBS = -67 + PI_TOO_MANY_OOL = -68 + PI_EMPTY_WAVEFORM = -69 + PI_NO_WAVEFORM_ID = -70 + PI_I2C_OPEN_FAILED = -71 + PI_SER_OPEN_FAILED = -72 + PI_SPI_OPEN_FAILED = -73 + PI_BAD_I2C_BUS = -74 + PI_BAD_I2C_ADDR = -75 + PI_BAD_SPI_CHANNEL = -76 + PI_BAD_FLAGS = -77 + PI_BAD_SPI_SPEED = -78 + PI_BAD_SER_DEVICE = -79 + PI_BAD_SER_SPEED = -80 + PI_BAD_PARAM = -81 + PI_I2C_WRITE_FAILED = -82 + PI_I2C_READ_FAILED = -83 + PI_BAD_SPI_COUNT = -84 + PI_SER_WRITE_FAILED = -85 + PI_SER_READ_FAILED = -86 + PI_SER_READ_NO_DATA = -87 + PI_UNKNOWN_COMMAND = -88 + PI_SPI_XFER_FAILED = -89 + PI_NO_AUX_SPI = -91 + PI_NOT_PWM_GPIO = -92 + PI_NOT_SERVO_GPIO = -93 + PI_NOT_HCLK_GPIO = -94 + PI_NOT_HPWM_GPIO = -95 + PI_BAD_HPWM_FREQ = -96 + PI_BAD_HPWM_DUTY = -97 + PI_BAD_HCLK_FREQ = -98 + PI_BAD_HCLK_PASS = -99 + PI_HPWM_ILLEGAL = -100 + PI_BAD_DATABITS = -101 + PI_BAD_STOPBITS = -102 + PI_MSG_TOOBIG = -103 + PI_BAD_MALLOC_MODE = -104 + PI_BAD_SMBUS_CMD = -107 + PI_NOT_I2C_GPIO = -108 + PI_BAD_I2C_WLEN = -109 + PI_BAD_I2C_RLEN = -110 + PI_BAD_I2C_CMD = -111 + PI_BAD_I2C_BAUD = -112 + PI_CHAIN_LOOP_CNT = -113 + PI_BAD_CHAIN_LOOP = -114 + PI_CHAIN_COUNTER = -115 + PI_BAD_CHAIN_CMD = -116 + PI_BAD_CHAIN_DELAY = -117 + PI_CHAIN_NESTING = -118 + PI_CHAIN_TOO_BIG = -119 + PI_DEPRECATED = -120 + PI_BAD_SER_INVERT = -121 + PI_BAD_FOREVER = -124 + PI_BAD_FILTER = -125 + PI_BAD_PAD = -126 + PI_BAD_STRENGTH = -127 + PI_FIL_OPEN_FAILED = -128 + PI_BAD_FILE_MODE = -129 + PI_BAD_FILE_FLAG = -130 + PI_BAD_FILE_READ = -131 + PI_BAD_FILE_WRITE = -132 + PI_FILE_NOT_ROPEN = -133 + PI_FILE_NOT_WOPEN = -134 + PI_BAD_FILE_SEEK = -135 + PI_NO_FILE_MATCH = -136 + PI_NO_FILE_ACCESS = -137 + PI_FILE_IS_A_DIR = -138 + PI_BAD_SHELL_STATUS = -139 + PI_BAD_SCRIPT_NAME = -140 + PI_BAD_SPI_BAUD = -141 + PI_NOT_SPI_GPIO = -142 + PI_BAD_EVENT_ID = -143 + PI_CMD_INTERRUPTED = -144 + PI_NOT_ON_BCM2711 = -145 + PI_ONLY_ON_BCM2711 = -146 + . . + + event:0-31 + An event is a signal used to inform one or more consumers + to start an action. + + file_mode: + The mode may have the following values + + . . + FILE_READ 1 + FILE_WRITE 2 + FILE_RW 3 + . . + + The following values can be or'd into the file open mode + + . . + FILE_APPEND 4 + FILE_CREATE 8 + FILE_TRUNC 16 + . . + + file_name: + A full file path. To be accessible the path must match + an entry in /opt/pigpio/access. + + fpattern: + A file path which may contain wildcards. To be accessible the path + must match an entry in /opt/pigpio/access. + + frequency: 0-40000 + Defines the frequency to be used for PWM on a GPIO. + The closest permitted frequency will be used. + + func: + A user supplied callback function. + + gpio: 0-53 + A Broadcom numbered GPIO. All the user GPIO are in the range 0-31. + + There are 54 General Purpose Input Outputs (GPIO) named GPIO0 + through GPIO53. + + They are split into two banks. Bank 1 consists of GPIO0 + through GPIO31. Bank 2 consists of GPIO32 through GPIO53. + + All the GPIO which are safe for the user to read and write are in + bank 1. Not all GPIO in bank 1 are safe though. Type 1 boards + have 17 safe GPIO. Type 2 boards have 21. Type 3 boards have 26. + + See [*get_hardware_revision*]. + + The user GPIO are marked with an X in the following table + + . . + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + Type 1 X X - - X - - X X X X X - - X X + Type 2 - - X X X - - X X X X X - - X X + Type 3 X X X X X X X X X X X X X X + + 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 + Type 1 - X X - - X X X X X - - - - - - + Type 2 - X X - - - X X X X - X X X X X + Type 3 X X X X X X X X X X X X - - - - + . . + + gpio_off: + A mask used to select GPIO to be operated on. See [*bits*]. + + This mask selects the GPIO to be switched off at the start + of a pulse. + + gpio_on: + A mask used to select GPIO to be operated on. See [*bits*]. + + This mask selects the GPIO to be switched on at the start + of a pulse. + + handle: >=0 + A number referencing an object opened by one of the following + + [*file_open*] + [*i2c_open*] + [*notify_open*] + [*serial_open*] + [*spi_open*] + + host: + The name or IP address of the Pi running the pigpio daemon. + + i2c_address: 0-0x7F + The address of a device on the I2C bus. + + i2c_bus: >=0 + An I2C bus number. + + i2c_flags: 0 + No I2C flags are currently defined. + + invert: 0-1 + A flag used to set normal or inverted bit bang serial data + level logic. + + level: 0-1 (2) + + . . + CLEAR = 0 + HIGH = 1 + LOW = 0 + OFF = 0 + ON = 1 + SET = 1 + TIMEOUT = 2 # only returned for a watchdog timeout + . . + + MISO: + The GPIO used for the MISO signal when bit banging SPI. + + mode: + + 1.The operational mode of a GPIO, normally INPUT or OUTPUT. + + . . + ALT0 = 4 + ALT1 = 5 + ALT2 = 6 + ALT3 = 7 + ALT4 = 3 + ALT5 = 2 + INPUT = 0 + OUTPUT = 1 + . . + + 2. The mode of waveform transmission. + + . . + WAVE_MODE_ONE_SHOT = 0 + WAVE_MODE_REPEAT = 1 + WAVE_MODE_ONE_SHOT_SYNC = 2 + WAVE_MODE_REPEAT_SYNC = 3 + . . + + MOSI: + The GPIO used for the MOSI signal when bit banging SPI. + + offset: >=0 + The offset wave data starts from the beginning of the waveform + being currently defined. + + pad: 0-2 + A set of GPIO which share common drivers. + + Pad @ GPIO + 0 @ 0-27 + 1 @ 28-45 + 2 @ 46-53 + + pad_strength: 1-16 + The mA which may be drawn from each GPIO whilst still guaranteeing the + high and low levels. + + params: 32 bit number + When scripts are started they can receive up to 10 parameters + to define their operation. + + percent:: 0-100 + The size of waveform as percentage of maximum available. + + port: + The port used by the pigpio daemon, defaults to 8888. + + pstring: + The string to be passed to a [*shell*] script to be executed. + + pud: 0-2 + . . + PUD_DOWN = 1 + PUD_OFF = 0 + PUD_UP = 2 + . . + + pulse_len: 1-100 + The length of the trigger pulse in microseconds. + + pulses: + A list of class pulse objects defining the characteristics of a + waveform. + + pulsewidth: + The servo pulsewidth in microseconds. 0 switches pulses off. + + PWMduty: 0-1000000 (1M) + The hardware PWM dutycycle. + + PWMfreq: 1-125M (1-187.5M for the BCM2711) + The hardware PWM frequency. + + range_: 25-40000 + Defines the limits for the [*dutycycle*] parameter. + + range_ defaults to 255. + + reg: 0-255 + An I2C device register. The usable registers depend on the + actual device. + + retMax: >=0 + The maximum number of bytes a user customised function + should return, default 8192. + + SCL: + The user GPIO to use for the clock when bit banging I2C. + + SCLK:: + The GPIO used for the SCLK signal when bit banging SPI. + + script: + The text of a script to store on the pigpio daemon. + + script_id: >=0 + A number referencing a script created by [*store_script*]. + + SDA: + The user GPIO to use for data when bit banging I2C. + + seek_from: 0-2 + Direction to seek for [*file_seek*]. + + . . + FROM_START=0 + FROM_CURRENT=1 + FROM_END=2 + . . + + seek_offset: + The number of bytes to move forward (positive) or backwards + (negative) from the seek position (start, current, or end of file). + + ser_flags: 32 bit + No serial flags are currently defined. + + serial_*: + One of the serial_ functions. + + shellscr: + The name of a shell script. The script must exist + in /opt/pigpio/cgi and must be executable. + + spi_*: + One of the spi_ functions. + + spi_channel: 0-2 + A SPI channel. + + spi_flags: 32 bit + See [*spi_open*]. + + steady: 0-300000 + + The number of microseconds level changes must be stable for + before reporting the level changed ([*set_glitch_filter*]) + or triggering the active part of a noise filter + ([*set_noise_filter*]). + + t1: + A tick (earlier). + + t2: + A tick (later). + + tty: + A Pi serial tty device, e.g. /dev/ttyAMA0, /dev/ttyUSB0 + + uint32: + An unsigned 32 bit number. + + user_gpio: 0-31 + A Broadcom numbered GPIO. + + All the user GPIO are in the range 0-31. + + Not all the GPIO within this range are usable, some are reserved + for system use. + + See [*gpio*]. + + wait_timeout: 0.0 - + The number of seconds to wait in [*wait_for_edge*] before timing out. + + wave_add_*: + One of the following + + [*wave_add_new*] + [*wave_add_generic*] + [*wave_add_serial*] + + wave_id: >=0 + A number referencing a wave created by [*wave_create*]. + + wave_send_*: + One of the following + + [*wave_send_once*] + [*wave_send_repeat*] + + wdog_timeout: 0-60000 + Defines a GPIO watchdog timeout in milliseconds. If no level + change is detected on the GPIO for timeout millisecond a watchdog + timeout report is issued (with level TIMEOUT). + + word_val: 0-65535 + A whole number. + """ + pass +