zmatt

simple gpio.py

Apr 24th, 2021 (edited)
893
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.42 KB | None | 0 0
  1. # This code assumes /dev/gpio contains symlinks for sysfs gpios.
  2. #
  3. # Example udev rule:
  4. #
  5. #   SUBSYSTEM=="subsystem", KERNEL=="gpio", ACTION=="add", \
  6. #       RUN+="/bin/mkdir -p /dev/gpio"
  7. #
  8. #   SUBSYSTEM=="gpio", ACTION=="add", TEST=="value", ATTR{label}!="sysfs", \
  9. #       RUN+="/bin/ln -sT '/sys/class/gpio/%k' /dev/gpio/%s{label}"
  10. #
  11. # To install, save as e.g. /etc/udev/rules.d/gpio-symlinks.rules
  12. # then "sudo update-initramfs -u" (unless you don't use initramfs) and reboot.
  13. #
  14. # Alternatively, the "name" argument of the functions below also accepts an
  15. # absolute path to the sysfs gpio (e.g. "/sys/class/gpio/gpio42").
  16. #
  17. #
  18. # This code is written to be simple and correct, not necessarily efficient.
  19. # Performance can probably be greatly improved by keeping a file descriptor
  20. # open for the 'value' attribute and using os.pread() and os.write().  This
  21. # would also be step 1 towards supporting input change events.
  22.  
  23.  
  24. from pathlib import Path
  25.  
  26.  
  27. # internal helper functions
  28.  
  29. def _gpio_attribute_path( name, attr ):
  30.     return Path( '/dev/gpio', name, attr )
  31.  
  32. def _gpio_get_attribute( name, attr ):
  33.     return _gpio_attribute_path( name, attr ).read_text().rstrip()
  34.  
  35. def _gpio_set_attribute( name, attr, value ):
  36.     return _gpio_attribute_path( name, attr ).write_text( value )
  37.  
  38.  
  39. # get/set output value (0 or 1) for gpio configured as output.
  40. # read input value (0 or 1) for gpio configured as input.
  41. # trying to set the value of an input will fail, it will not change to output.
  42.  
  43. def gpio_get_value( name ):
  44.     return int( _gpio_get_attribute( name, 'value' ) )
  45.  
  46. def gpio_set_value( name, value ):
  47.     assert type(value) is int and value in (0, 1)
  48.     _gpio_set_attribute( name, 'value', str(value) )
  49.  
  50.  
  51. # get/set direction ('in' or 'out') of gpio.
  52. #
  53. # NOTE: changing the direction of a gpio may not always be allowed, in which
  54. # case attempting to set it will fail even if you're trying to set it to the
  55. # state it is already in.  If you merely want to ensure the gpio direction
  56. # during initialization, check it before trying to set it.
  57.  
  58. def gpio_get_direction( name ):
  59.     return _gpio_get_attribute( name, 'direction' )
  60.  
  61. def gpio_set_direction_in( name ):
  62.     _gpio_set_attribute( name, 'direction', 'in' )
  63.  
  64. # when changing direction to output, the initial output value must be specified
  65. # with a keyword argument, e.g.  gpio_set_direction_out( "foo", value=0 )
  66. def gpio_set_direction_out( name, *, value ):
  67.     level = gpio_get_level_for_value( name, value )
  68.     _gpio_set_attribute( name, 'direction', level )
  69.  
  70.  
  71. # The state of a gpio can be described in two ways:
  72. # - logical value: 0 or 1
  73. # - voltage level: low or high
  74. #
  75. # It is important not to confuse these since the mapping between logical value
  76. # and voltage level is configurable (both in DT and at runtime).
  77. #
  78. # The level corresponding to value=1 is also known as the "active" level, hence
  79. # a gpio configured such that 1=low and 0=high is known as "active-low", while
  80. # one configured such that 0=low and 1=high is known as "active-high".
  81. #
  82. # Below are therefore three ways to get/set this mapping:
  83. # - the value (0 or 1) corresponding to low level
  84. # - the active level ('low' or 'high'), i.e. corresponding to value=1
  85. # - whether gpio is active-low (bool)
  86. #
  87. # Generally speaking you should configure this mapping once and then leave it
  88. # alone.  Ideally you should configure in DT and your software won't need to
  89. # care about any of this and can just use the value-based functions above.
  90.  
  91. def gpio_get_low_value( name ):
  92.     return int( _gpio_get_attribute( name, 'active_low' ) )
  93.  
  94. def gpio_set_low_value( name, value ):
  95.     assert type(value) is int and value in (0,1)
  96.     _gpio_set_attribute( name, 'active_low', str(value) )
  97.  
  98. def gpio_is_active_low( name ):
  99.     return bool( gpio_get_low_value( name ) )
  100.  
  101. def gpio_set_active_low( name, is_active_low ):
  102.     assert type(is_active_low) is bool
  103.     gpio_set_low_value( name, int( is_active_low ) )
  104.  
  105. def gpio_get_active_level( name ):
  106.     return ('low', 'high')[ gpio_get_low_value( name ) ]
  107.  
  108. def gpio_set_active_level( name, level ):
  109.     gpio_set_low_value( name, ('low', 'high').index( level ) )
  110.  
  111. # map between logical value (0 or 1) and voltage level ('low' or 'high')
  112.  
  113. def gpio_get_level_for_value( name, value ):
  114.     return ('low', 'high')[ gpio_get_low_value( name ) ^ value ]
  115.  
  116. def gpio_get_value_for_level( name, level ):
  117.     return ('low', 'high').index( level ) ^ gpio_get_low_value( name )
Add Comment
Please, Sign In to add comment