Coverage for /usr/lib/python3/dist-packages/gpiozero/pins/spi.py: 14%

67 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2024-02-10 12:38 +0000

1# vim: set fileencoding=utf-8: 

2# 

3# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins 

4# 

5# Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk> 

6# 

7# SPDX-License-Identifier: BSD-3-Clause 

8 

9from __future__ import ( 

10 unicode_literals, 

11 print_function, 

12 absolute_import, 

13 division, 

14 ) 

15str = type('') 

16 

17 

18import operator 

19from threading import RLock 

20 

21from ..devices import Device, SharedMixin 

22from ..input_devices import InputDevice 

23from ..output_devices import OutputDevice 

24 

25 

26class SPISoftwareBus(SharedMixin, Device): 

27 def __init__(self, clock_pin, mosi_pin, miso_pin): 

28 self.lock = None 

29 self.clock = None 

30 self.mosi = None 

31 self.miso = None 

32 super(SPISoftwareBus, self).__init__() 

33 self.lock = RLock() 

34 try: 

35 self.clock = OutputDevice(clock_pin, active_high=True) 

36 if mosi_pin is not None: 

37 self.mosi = OutputDevice(mosi_pin) 

38 if miso_pin is not None: 

39 self.miso = InputDevice(miso_pin) 

40 except: 

41 self.close() 

42 raise 

43 

44 def close(self): 

45 super(SPISoftwareBus, self).close() 

46 if getattr(self, 'lock', None): 

47 with self.lock: 

48 if self.miso is not None: 

49 self.miso.close() 

50 self.miso = None 

51 if self.mosi is not None: 

52 self.mosi.close() 

53 self.mosi = None 

54 if self.clock is not None: 

55 self.clock.close() 

56 self.clock = None 

57 self.lock = None 

58 

59 @property 

60 def closed(self): 

61 return self.lock is None 

62 

63 @classmethod 

64 def _shared_key(cls, clock_pin, mosi_pin, miso_pin): 

65 return (clock_pin, mosi_pin, miso_pin) 

66 

67 def transfer(self, data, clock_phase=False, lsb_first=False, bits_per_word=8): 

68 """ 

69 Writes data (a list of integer words where each word is assumed to have 

70 :attr:`bits_per_word` bits or less) to the SPI interface, and reads an 

71 equivalent number of words, returning them as a list of integers. 

72 """ 

73 result = [] 

74 with self.lock: 

75 # See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 

76 # (specifically the section "Example of bit-banging the master 

77 # protocol") for a simpler C implementation of this which ignores 

78 # clock polarity, phase, variable word-size, and multiple input 

79 # words 

80 if lsb_first: 

81 shift = operator.lshift 

82 init_mask = 1 

83 else: 

84 shift = operator.rshift 

85 init_mask = 1 << (bits_per_word - 1) 

86 for write_word in data: 

87 mask = init_mask 

88 read_word = 0 

89 for _ in range(bits_per_word): 

90 if self.mosi is not None: 

91 self.mosi.value = bool(write_word & mask) 

92 # read bit on clock activation 

93 self.clock.on() 

94 if not clock_phase: 

95 if self.miso is not None and self.miso.value: 

96 read_word |= mask 

97 # read bit on clock deactivation 

98 self.clock.off() 

99 if clock_phase: 

100 if self.miso is not None and self.miso.value: 

101 read_word |= mask 

102 mask = shift(mask, 1) 

103 result.append(read_word) 

104 return result