1 /*
2  * Copyright (c) 2020 Seagate Technology LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/drivers/led.h>
10 
11 #define BRIGHTNESS_MAX	100
12 #define TEST_MAX_COLORS	8
13 #define COLOR_FULL	0xff
14 
15 #define _COLOR_MAPPING(led_node_id)				\
16 const uint8_t test_color_mapping_##led_node_id[] =		\
17 	DT_PROP(led_node_id, color_mapping)
18 
19 #define COLOR_MAPPING(led_node_id)					\
20 	IF_ENABLED(DT_NODE_HAS_PROP(led_node_id, color_mapping),	\
21 		   (_COLOR_MAPPING(led_node_id);))
22 
23 #define LED_INFO_COLOR(led_node_id)				\
24 {								\
25 	.label		= DT_PROP(led_node_id, label),		\
26 	.index		= DT_PROP_OR(led_node_id, index, 0),	\
27 	.num_colors	=					\
28 		DT_PROP_LEN(led_node_id, color_mapping),	\
29 	.color_mapping	= test_color_mapping_##led_node_id,	\
30 },
31 
32 #define LED_INFO_NO_COLOR(led_node_id)				\
33 {								\
34 	.label		= DT_PROP(led_node_id, label),		\
35 	.index		= DT_PROP_OR(led_node_id, index, 0),	\
36 	.num_colors	= 0,					\
37 	.color_mapping	= NULL,					\
38 },
39 
40 #define LED_INFO(led_node_id)	\
41 	COND_CODE_1(DT_NODE_HAS_PROP(led_node_id, color_mapping),	\
42 		    (LED_INFO_COLOR(led_node_id)),			\
43 		    (LED_INFO_NO_COLOR(led_node_id)))
44 
45 #define LED_CONTROLLER_INFO(node_id)				\
46 								\
47 DT_FOREACH_CHILD(node_id, COLOR_MAPPING)			\
48 								\
49 const struct led_info test_led_info[] = {			\
50 	DT_FOREACH_CHILD(node_id, LED_INFO)			\
51 };								\
52 								\
53 static ZTEST_DMEM int num_leds = ARRAY_SIZE(test_led_info)
54 
55 LED_CONTROLLER_INFO(DT_ALIAS(led_controller_0));
56 
57 static ZTEST_BMEM const struct device *const led_ctrl = DEVICE_DT_GET(DT_ALIAS(led_controller_0));
58 
test_led_setup(void)59 static void test_led_setup(void)
60 {
61 	zassert_true(device_is_ready(led_ctrl), "LED controller is not ready");
62 
63 	zassert_not_equal(num_leds, 0, "No LEDs subnodes found in DT for controller");
64 
65 	k_object_access_grant(led_ctrl, k_current_get());
66 }
67 
ZTEST_USER(led_user,test_led_get_info)68 ZTEST_USER(led_user, test_led_get_info)
69 {
70 	uint8_t led;
71 	int ret;
72 
73 	if (!led_ctrl || !num_leds) {
74 		ztest_test_skip();
75 	}
76 
77 	for (led = 0; led < num_leds; led++) {
78 		const struct led_info *info;
79 		uint8_t col;
80 
81 		ret = led_get_info(led_ctrl, led, &info);
82 		if (ret == -ENOTSUP) {
83 			TC_PRINT("led_get_info() syscall is not supported.\n");
84 			ztest_test_skip();
85 			return;
86 		}
87 
88 		zassert_equal(ret, 0, "LED %d - led_get_info() error (ret=%d)",
89 			      led, ret);
90 
91 		zassert_true(!strcmp(info->label, test_led_info[led].label),
92 			     "LED %d - label: %s instead of %s",
93 			     led, info->label, test_led_info[led].label);
94 
95 		zassert_equal(info->index, test_led_info[led].index,
96 			      "LED %d - index: %d instead of %d", led,
97 			      info->index, test_led_info[led].index);
98 
99 		zassert_equal(info->num_colors, test_led_info[led].num_colors,
100 			      "LED %d - num_colors: %d instead of %d", led,
101 			      info->num_colors, test_led_info[led].num_colors);
102 
103 		TC_PRINT("LED %d - label: %s, index: %d, num_colors: %d",
104 			 led, info->label, info->index, info->num_colors);
105 
106 		if (!info->num_colors) {
107 			continue;
108 		}
109 
110 		TC_PRINT(" color_mapping: ");
111 
112 		for (col = 0; col < info->num_colors; col++) {
113 			zassert_equal(info->color_mapping[col],
114 				test_led_info[led].color_mapping[col],
115 				"LED %d - color_mapping[%d]=%d instead of %d",
116 				led, col, info->color_mapping[col],
117 				test_led_info[led].color_mapping[col]);
118 			TC_PRINT("%d", info->color_mapping[col]);
119 		}
120 		TC_PRINT("\n");
121 	}
122 }
123 
ZTEST_USER(led_user,test_led_on)124 ZTEST_USER(led_user, test_led_on)
125 {
126 	uint8_t led;
127 	int ret;
128 
129 	if (!led_ctrl || !num_leds) {
130 		ztest_test_skip();
131 	}
132 
133 	for (led = 0; led < num_leds; led++) {
134 		ret = led_on(led_ctrl, led);
135 		zassert_equal(ret, 0, "LED %d - failed to turn on", led);
136 	}
137 }
138 
ZTEST_USER(led_user,test_led_off)139 ZTEST_USER(led_user, test_led_off)
140 {
141 	uint8_t led;
142 	int ret;
143 
144 	if (!led_ctrl || !num_leds) {
145 		ztest_test_skip();
146 	}
147 
148 	for (led = 0; led < num_leds; led++) {
149 		ret = led_off(led_ctrl, led);
150 		zassert_equal(ret, 0, "LED %d - failed to turn off", led);
151 	}
152 }
153 
ZTEST_USER(led_user,test_led_set_color)154 ZTEST_USER(led_user, test_led_set_color)
155 {
156 	uint8_t led;
157 	uint8_t colors[TEST_MAX_COLORS + 1];
158 	int ret;
159 
160 	if (!led_ctrl || !num_leds) {
161 		ztest_test_skip();
162 	}
163 
164 	for (led = 0; led < num_leds; led++) {
165 		uint8_t num_colors = test_led_info[led].num_colors;
166 		uint8_t col;
167 
168 		if (num_colors > TEST_MAX_COLORS) {
169 			TC_PRINT("LED %d - skip set_color test, num_colors: %d"
170 				 " (test limit is %d)",
171 				 led, num_colors, TEST_MAX_COLORS);
172 			continue;
173 		}
174 
175 		memset(colors, 0, sizeof(colors));
176 
177 		/* Try to set more colors than supported. */
178 		ret = led_set_color(led_ctrl, led, num_colors + 1, colors);
179 		zassert_not_equal(ret, 0, "LED %d - setting %d"
180 				  " colors should fail (%d supported)",
181 				  led, num_colors + 1, num_colors);
182 
183 		if (!num_colors) {
184 			continue;
185 		}
186 
187 		/* Try to set less colors than supported. */
188 		ret = led_set_color(led_ctrl, led, num_colors - 1, colors);
189 		zassert_not_equal(ret, 0, "LED %d - setting %d"
190 				  " colors should fail (%d supported)",
191 				  led, num_colors - 1, num_colors);
192 
193 		/* Ensure the LED is on to get a visual feedback. */
194 		led_set_brightness(led_ctrl, led, BRIGHTNESS_MAX / 2);
195 
196 		/* Set each color gradually to its maximum level. */
197 		for (col = 0; col < num_colors; col++) {
198 			uint16_t level;
199 
200 			memset(colors, 0, sizeof(colors));
201 
202 			for (level = 0; level <= COLOR_FULL; level++) {
203 				colors[col] = level;
204 
205 				ret = led_set_color(led_ctrl, led,
206 						    num_colors, colors);
207 				zassert_equal(ret, 0,
208 					"LED %d - failed to set color[%d] to %d",
209 					led, level);
210 			}
211 		}
212 	}
213 }
214 
ZTEST_USER(led_user,test_led_set_brightness)215 ZTEST_USER(led_user, test_led_set_brightness)
216 {
217 	uint8_t led;
218 	int ret;
219 
220 	if (!led_ctrl || !num_leds) {
221 		ztest_test_skip();
222 	}
223 
224 	for (led = 0; led < num_leds; led++) {
225 		uint16_t level;
226 
227 		for (level = 0; level <= BRIGHTNESS_MAX; level++) {
228 			ret = led_set_brightness(led_ctrl, led, level);
229 			zassert_equal(ret, 0,
230 				      "LED %d - failed to set brightness to %d",
231 				      led, level);
232 		}
233 		for (level = BRIGHTNESS_MAX + 1; level <= 255; level++) {
234 			ret = led_set_brightness(led_ctrl, led, level);
235 			zassert_not_equal(ret, 0,
236 					  "LED %d - setting brightness to %d"
237 					  " should fail (maximum: %d)",
238 					  led, level, BRIGHTNESS_MAX);
239 		}
240 	}
241 }
242 
led_setup(void)243 void *led_setup(void)
244 {
245 	test_led_setup();
246 
247 	return NULL;
248 }
249 
250 ZTEST_SUITE(led_user, NULL, led_setup, NULL, NULL, NULL);
251