test_ws2812.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # Copyright (c) 2014-18 Richard Hull and contributors
  4. # See LICENSE.rst for details.
  5. import pytest
  6. from luma.led_matrix.device import neopixel
  7. from luma.core.render import canvas
  8. from unittest.mock import Mock, call
  9. ws = Mock(unsafe=True)
  10. chan = "channel"
  11. leds = "leds"
  12. def setup_function(function):
  13. ws.reset_mock()
  14. ws.command.side_effect = None
  15. ws.ws2811_init = Mock(return_value=0)
  16. ws.ws2811_render = Mock(return_value=0)
  17. ws.ws2811_channel_get = Mock(return_value=chan)
  18. ws.ws2811_new_ws2811_t = Mock(return_value=leds)
  19. def test_init_cascaded():
  20. device = neopixel(ws, cascaded=7)
  21. assert device.width == 7
  22. assert device.height == 1
  23. assert ws.ws2811_channel_t_count_set.called
  24. assert ws.ws2811_channel_t_gpionum_set.called
  25. assert ws.ws2811_channel_t_invert_set.called
  26. assert ws.ws2811_channel_t_brightness_set.called
  27. assert ws.ws2811_channel_t_strip_type_set.called
  28. assert ws.ws2811_t_freq_set.called
  29. assert ws.ws2811_t_dmanum_set.called
  30. assert ws.ws2811_init.called
  31. ws.ws2811_led_set.assert_has_calls([
  32. call(chan, i, 0x000000) for i in range(7)])
  33. assert ws.ws2811_render.called
  34. def test_init_4x8():
  35. device = neopixel(ws)
  36. assert device.cascaded == 32
  37. assert ws.ws2811_channel_t_count_set.called
  38. assert ws.ws2811_channel_t_gpionum_set.called
  39. assert ws.ws2811_channel_t_invert_set.called
  40. assert ws.ws2811_channel_t_brightness_set.called
  41. assert ws.ws2811_channel_t_strip_type_set.called
  42. assert ws.ws2811_t_freq_set.called
  43. assert ws.ws2811_t_dmanum_set.called
  44. assert ws.ws2811_init.called
  45. ws.ws2811_led_set.assert_has_calls([
  46. call(chan, i, 0x000000) for i in range(32)])
  47. assert ws.ws2811_render.called
  48. def test_init_fail():
  49. ws.reset_mock()
  50. ws.ws2811_init = Mock(return_value=-1)
  51. with pytest.raises(RuntimeError) as ex:
  52. neopixel(ws, cascaded=7)
  53. assert "ws2811_init failed with code -1" in str(ex.value)
  54. def test_clear():
  55. device = neopixel(ws)
  56. ws.reset_mock()
  57. device.clear()
  58. ws.ws2811_led_set.assert_has_calls([
  59. call(chan, i, 0x000000) for i in range(32)])
  60. assert ws.ws2811_render.called
  61. def test_cleanup():
  62. device = neopixel(ws)
  63. device.cleanup()
  64. ws.ws2811_led_set.assert_has_calls([
  65. call(chan, i, 0x000000) for i in range(32)])
  66. assert ws.ws2811_render.called
  67. assert ws.ws2811_fini.called
  68. assert ws.delete_ws2811_t.called
  69. assert device._leds is None
  70. assert device._channel is None
  71. def test_hide():
  72. device = neopixel(ws, cascaded=5)
  73. ws.reset_mock()
  74. device.hide()
  75. ws.ws2811_led_set.assert_not_called()
  76. assert ws.ws2811_render.called
  77. def test_show():
  78. device = neopixel(ws, cascaded=5)
  79. ws.reset_mock()
  80. device.hide()
  81. device.show()
  82. ws.ws2811_led_set.assert_not_called()
  83. assert ws.ws2811_render.called
  84. def test_contrast():
  85. device = neopixel(ws, cascaded=6)
  86. ws.reset_mock()
  87. device.contrast(0x6B)
  88. ws.ws2811_channel_t_brightness_set.assert_called_once_with(chan, 0x6B)
  89. def test_display():
  90. device = neopixel(ws, width=4, height=4)
  91. ws.reset_mock()
  92. with canvas(device) as draw:
  93. draw.rectangle(device.bounding_box, outline="red")
  94. ws.ws2811_led_set.assert_has_calls([
  95. call(chan, 0, 0xFF0000),
  96. call(chan, 1, 0xFF0000),
  97. call(chan, 2, 0xFF0000),
  98. call(chan, 3, 0xFF0000),
  99. call(chan, 4, 0xFF0000),
  100. call(chan, 5, 0x000000),
  101. call(chan, 6, 0x000000),
  102. call(chan, 7, 0xFF0000),
  103. call(chan, 8, 0xFF0000),
  104. call(chan, 9, 0x000000),
  105. call(chan, 10, 0x000000),
  106. call(chan, 11, 0xFF0000),
  107. call(chan, 12, 0xFF0000),
  108. call(chan, 13, 0xFF0000),
  109. call(chan, 14, 0xFF0000),
  110. call(chan, 15, 0xFF0000),
  111. ])
  112. assert ws.ws2811_render.called
  113. def test_display_fail():
  114. device = neopixel(ws, cascaded=7)
  115. ws.reset_mock()
  116. ws.ws2811_render = Mock(return_value=-1)
  117. with pytest.raises(RuntimeError) as ex:
  118. with canvas(device) as draw:
  119. draw.rectangle(device.bounding_box, outline="red")
  120. assert "ws2811_render failed with code -1" in str(ex.value)
  121. def test_mapping():
  122. num_pixels = 16
  123. device = neopixel(ws, cascaded=num_pixels, mapping=reversed(list(range(num_pixels))))
  124. ws.reset_mock()
  125. with canvas(device) as draw:
  126. for i in range(device.cascaded):
  127. draw.point((i, 0), (i, 0, 0))
  128. expected = [call(chan, num_pixels - i - 1, i << 16) for i in range(num_pixels)]
  129. ws.ws2811_led_set.assert_has_calls(expected)
  130. assert ws.ws2811_render.called