test_transmit.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. import logging
  2. import unittest.mock
  3. import pytest
  4. import cc1101.addresses
  5. import cc1101.options
  6. # pylint: disable=protected-access
  7. def test_transmit_empty_payload(transceiver):
  8. with unittest.mock.patch.object(
  9. transceiver,
  10. "get_packet_length_mode",
  11. return_value=cc1101.options.PacketLengthMode.VARIABLE,
  12. ), unittest.mock.patch.object(
  13. transceiver, "get_packet_length_bytes", return_value=21
  14. ):
  15. with pytest.raises(ValueError, match=r"\bempty\b"):
  16. transceiver.transmit([])
  17. @pytest.mark.parametrize(
  18. ("max_packet_length", "payload"),
  19. ((3, "\x04\x01\x02\x03"), (4, [7, 21, 42, 0, 0, 1, 2, 3])),
  20. )
  21. def test_transmit_exceeding_max_length(transceiver, max_packet_length, payload):
  22. with unittest.mock.patch.object(
  23. transceiver,
  24. "get_packet_length_mode",
  25. return_value=cc1101.options.PacketLengthMode.VARIABLE,
  26. ), unittest.mock.patch.object(
  27. transceiver, "get_packet_length_bytes", return_value=max_packet_length
  28. ):
  29. with pytest.raises(
  30. ValueError, match=r"\bpayload exceeds maximum payload length\b"
  31. ):
  32. transceiver.transmit(payload)
  33. @pytest.mark.parametrize(
  34. ("packet_length", "payload"),
  35. ((3, "\x04\x01\x02\x03"), (4, [7, 21, 42, 0, 0, 1, 2, 3])),
  36. )
  37. def test_transmit_unexpected_payload_len(transceiver, packet_length, payload):
  38. with unittest.mock.patch.object(
  39. transceiver,
  40. "get_packet_length_mode",
  41. return_value=cc1101.options.PacketLengthMode.FIXED,
  42. ), unittest.mock.patch.object(
  43. transceiver, "get_packet_length_bytes", return_value=packet_length
  44. ):
  45. with pytest.raises(ValueError, match=r"\bpayload length\b"):
  46. transceiver.transmit(payload)
  47. def test_transmit_not_idle(transceiver: cc1101.CC1101) -> None:
  48. with unittest.mock.patch.object(
  49. transceiver,
  50. "get_packet_length_mode",
  51. return_value=cc1101.options.PacketLengthMode.VARIABLE,
  52. ), unittest.mock.patch.object(
  53. transceiver, "get_packet_length_bytes", return_value=42 // 2
  54. ), unittest.mock.patch.object(
  55. transceiver,
  56. "get_main_radio_control_state_machine_state",
  57. return_value=cc1101.MainRadioControlStateMachineState.RX,
  58. ), pytest.raises(
  59. RuntimeError,
  60. match=r"^device must be idle before transmission \(current marcstate: RX\)$",
  61. ):
  62. transceiver.transmit(b"\x01\x02\x03")
  63. transceiver._spi.xfer.assert_not_called()
  64. @pytest.mark.parametrize("payload", (b"\0", b"\xaa\xbb\xcc", bytes(range(42))))
  65. def test_transmit_fixed(caplog, transceiver, payload):
  66. transceiver._spi.xfer.side_effect = lambda v: [15] * len(v)
  67. with unittest.mock.patch.object(
  68. transceiver,
  69. "get_packet_length_mode",
  70. return_value=cc1101.options.PacketLengthMode.FIXED,
  71. ), unittest.mock.patch.object(
  72. transceiver, "get_packet_length_bytes", return_value=len(payload)
  73. ), unittest.mock.patch.object(
  74. transceiver,
  75. "get_main_radio_control_state_machine_state",
  76. return_value=cc1101.MainRadioControlStateMachineState.IDLE,
  77. ), caplog.at_level(
  78. logging.INFO
  79. ):
  80. transceiver.transmit(payload)
  81. assert transceiver._spi.xfer.call_args_list == [
  82. unittest.mock.call([0x3B]), # flush
  83. unittest.mock.call([0x3F | 0x40] + list(payload)),
  84. unittest.mock.call([0x35]), # start transmission
  85. ]
  86. assert caplog.record_tuples == [
  87. (
  88. "cc1101",
  89. 20,
  90. "transmitting 0x{} ({!r})".format( # pylint: disable=consider-using-f-string
  91. "".join(f"{b:02x}" for b in payload), payload
  92. ),
  93. )
  94. ]
  95. @pytest.mark.parametrize(
  96. "payload", (b"\x01\0", b"\x03\xaa\xbb\xcc", b"\x10" + bytes(range(16)))
  97. )
  98. def test_transmit_variable(transceiver, payload):
  99. transceiver._spi.xfer.side_effect = lambda v: [15] * len(v)
  100. with unittest.mock.patch.object(
  101. transceiver,
  102. "get_packet_length_mode",
  103. return_value=cc1101.options.PacketLengthMode.VARIABLE,
  104. ), unittest.mock.patch.object(
  105. transceiver, "get_packet_length_bytes", return_value=255
  106. ), unittest.mock.patch.object(
  107. transceiver,
  108. "get_main_radio_control_state_machine_state",
  109. return_value=cc1101.MainRadioControlStateMachineState.IDLE,
  110. ):
  111. transceiver.transmit(payload)
  112. assert transceiver._spi.xfer.call_args_list == [
  113. unittest.mock.call([0x3B]), # flush
  114. unittest.mock.call([0x3F | 0x40] + [len(payload)] + list(payload)),
  115. unittest.mock.call([0x35]), # start transmission
  116. ]
  117. def test_asynchronous_transmission(transceiver: cc1101.CC1101) -> None:
  118. with unittest.mock.patch.object(
  119. transceiver, "_set_transceive_mode"
  120. ) as set_mode_mock, unittest.mock.patch.object(
  121. transceiver, "_command_strobe"
  122. ) as command_mock:
  123. with transceiver.asynchronous_transmission() as input_pin:
  124. set_mode_mock.assert_called_once_with(
  125. cc1101.options._TransceiveMode.ASYNCHRONOUS_SERIAL
  126. )
  127. set_mode_mock.reset_mock()
  128. command_mock.assert_called_once_with(cc1101.addresses.StrobeAddress.STX)
  129. command_mock.reset_mock()
  130. transceiver._spi.xfer.assert_not_called()
  131. assert input_pin == cc1101.Pin.GDO0
  132. set_mode_mock.assert_called_once_with(cc1101.options._TransceiveMode.FIFO)
  133. command_mock.assert_called_once_with(cc1101.addresses.StrobeAddress.SIDLE)
  134. transceiver._spi.xfer.assert_not_called()