__init__.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import enum
  2. import spidev
  3. class CC1101:
  4. # > All transfers on the SPI interface are done
  5. # > most significant bit first.
  6. # > All transactions on the SPI interface start with
  7. # > a header byte containing a R/W bit, a access bit (B),
  8. # > and a 6-bit address (A5 - A0).
  9. # > [...]
  10. # > Table 45: SPI Address Space
  11. _WRITE_SINGLE_BYTE = 0x00
  12. # > Registers with consecutive addresses can be
  13. # > accessed in an efficient way by setting the
  14. # > burst bit (B) in the header byte. The address
  15. # > bits (A5 - A0) set the start address in an
  16. # > internal address counter. This counter is
  17. # > incremented by one each new byte [...]
  18. _WRITE_BURST = 0x40
  19. _READ_SINGLE_BYTE = 0x80
  20. _READ_BURST = 0xC0
  21. class _SPIAddress(enum.IntEnum):
  22. # Table 45: SPI Address Space
  23. # > For register addresses in the range 0x30-0x3D,
  24. # > the burst bit is used to select between
  25. # > status registers when burst bit is one, and
  26. # > between command strobes when burst bit is
  27. # > zero. [...]
  28. # > Because of this, burst access is not available
  29. # > for status registers and they must be accessed
  30. # > one at a time. The status registers can only be
  31. # > read.
  32. SRES = 0x30
  33. PARTNUM = 0x30
  34. VERSION = 0x31
  35. MARCSTATE = 0x35
  36. class MainRadioControlStateMachineState(enum.IntEnum):
  37. """
  38. MARCSTATE - Main Radio Control State Machine State
  39. """
  40. IDLE = 0x01
  41. # 29.3 Status Register Details
  42. _SUPPORTED_PARTNUM = 0
  43. _SUPPORTED_VERSION = 0x14
  44. def __init__(self) -> None:
  45. self._spi = spidev.SpiDev()
  46. def _reset(self) -> None:
  47. assert self._spi.xfer([self._SPIAddress.SRES, 0]) == [0x0F, 0x0F]
  48. def _read_burst(self, register: _SPIAddress) -> int:
  49. response = self._spi.xfer([register | self._READ_BURST, 0])
  50. assert len(response) == 2, response
  51. assert response[0] == 0
  52. return response[1]
  53. def __enter__(self) -> "CC1101":
  54. # https://docs.python.org/3/reference/datamodel.html#object.__enter__
  55. self._spi.open(0, 0)
  56. self._spi.max_speed_hz = 55700 # empirical
  57. self._reset()
  58. partnum = self._read_burst(self._SPIAddress.PARTNUM)
  59. if partnum != self._SUPPORTED_PARTNUM:
  60. raise ValueError(
  61. "unexpected chip part number {} (expected: {})".format(
  62. partnum, self._SUPPORTED_PARTNUM
  63. )
  64. )
  65. version = self._read_burst(self._SPIAddress.VERSION)
  66. if version != self._SUPPORTED_VERSION:
  67. raise ValueError(
  68. "unexpected chip version number {} (expected: {})".format(
  69. version, self._SUPPORTED_VERSION
  70. )
  71. )
  72. marcstate = self.getMainRadioControlStateMachineState()
  73. if marcstate != self.MainRadioControlStateMachineState.IDLE:
  74. raise ValueError("expected marcstate idle (actual: {})".format(marcstate))
  75. return self
  76. def __exit__(self, exc_type, exc_value, traceback) -> bool:
  77. # https://docs.python.org/3/reference/datamodel.html#object.__exit__
  78. self._spi.close()
  79. return False
  80. def getMainRadioControlStateMachineState(self) -> MainRadioControlStateMachineState:
  81. return self.MainRadioControlStateMachineState(
  82. self._read_burst(self._SPIAddress.MARCSTATE)
  83. )
  84. def getMARCState(self) -> MainRadioControlStateMachineState:
  85. """
  86. alias for getMainRadioControlStateMachineState()
  87. """
  88. return self.getMainRadioControlStateMachineState()