1 /*
2  * Copyright 2024 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "emulated_target.hpp"
6 
7 #include <zephyr/devicetree.h>
8 #include <zephyr/drivers/i2c.h>
9 #include <zephyr/fff.h>
10 #include <zephyr/ztest.h>
11 
12 namespace
13 {
14 
15 #define GET_TARGET_DEVICE(node_id, prop, n) DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, n)),
16 
17 /* Get the devicetree constants */
18 constexpr const struct device *controller = DEVICE_DT_GET(CONTROLLER_LABEL);
19 constexpr const struct device *targets[FORWARD_COUNT] = {
20 	DT_FOREACH_PROP_ELEM(CONTROLLER_LABEL, forwards, GET_TARGET_DEVICE)};
21 
ZTEST(i2c_emul_forwarding,test_write_is_forwarded)22 ZTEST(i2c_emul_forwarding, test_write_is_forwarded)
23 {
24 	// Try writing some values
25 	for (uint8_t data = 0; data < 10; ++data) {
26 		const unsigned int expected_call_count = 1 + data;
27 
28 		zassert_ok(i2c_write(controller, &data, sizeof(data),
29 				     emulated_target_config[0].address));
30 
31 		// Expected no reads to be made
32 		zexpect_equal(0, target_read_requested_0_fake.call_count);
33 		zexpect_equal(0, target_read_processed_0_fake.call_count);
34 
35 		// Expected N write requests to be made
36 		zexpect_equal(expected_call_count, target_write_requested_0_fake.call_count,
37 			      "Expected to be called %d times, got %d", expected_call_count,
38 			      target_write_requested_0_fake.call_count);
39 		zexpect_equal(expected_call_count, target_write_received_0_fake.call_count,
40 			      "Expected to be called %d times, got %d", expected_call_count,
41 			      target_write_received_0_fake.call_count);
42 
43 		// Check that the data written was correct
44 		zexpect_equal(data, target_write_received_0_fake.arg1_val,
45 			      "Expected data value %u. got %u", data,
46 			      target_write_received_0_fake.arg1_val);
47 
48 		// Expect 1 stop call per write request
49 		zexpect_equal(expected_call_count, target_stop_0_fake.call_count,
50 			      "Expected to be called %d times, got %d", expected_call_count,
51 			      target_stop_0_fake.call_count);
52 	}
53 }
54 
ZTEST(i2c_emul_forwarding,test_read_is_forwarded)55 ZTEST(i2c_emul_forwarding, test_read_is_forwarded)
56 {
57 	// Try reading some values
58 	for (uint8_t i = 0; i < 10; ++i) {
59 		const uint8_t expected_data[2] = {
60 			static_cast<uint8_t>(0x1 * i),
61 			static_cast<uint8_t>(0x2 * i),
62 		};
63 		const unsigned int expected_call_count = 1 + i;
64 		uint8_t data[2];
65 
66 		// Setup some lambdas to do the actual reads using 'expected_data'
67 		target_read_requested_0_fake.custom_fake =
68 			[expected_data](struct i2c_target_config *, uint8_t *out) -> int {
69 			*out = expected_data[0];
70 			return 0;
71 		};
72 		target_read_processed_0_fake.custom_fake =
73 			[expected_data](struct i2c_target_config *, uint8_t *out) -> int {
74 			*out = expected_data[1];
75 			return 0;
76 		};
77 		zassert_ok(i2c_read(controller, data, sizeof(data),
78 				    emulated_target_config[0].address));
79 
80 		// Expect the read functions to be called N times
81 		zexpect_equal(expected_call_count, target_read_requested_0_fake.call_count,
82 			      "Expected to be called %d times, got %d", expected_call_count,
83 			      target_read_requested_0_fake.call_count);
84 		zexpect_equal(expected_call_count, target_read_processed_0_fake.call_count,
85 			      "Expected to be called %d times, got %d", expected_call_count,
86 			      target_read_processed_0_fake.call_count);
87 
88 		// Expect the data read to match
89 		zexpect_equal(expected_data[0], data[0], "Expected 0x%02x, got 0x%02x",
90 			      expected_data[0], data[0]);
91 		zexpect_equal(expected_data[1], data[1], "Expected 0x%02x, got 0x%02x",
92 			      expected_data[1], data[1]);
93 
94 		// Expect 0 write calls
95 		zexpect_equal(0, target_write_requested_0_fake.call_count);
96 		zexpect_equal(0, target_write_received_0_fake.call_count);
97 
98 		// Expect 1 stop call per read
99 		zexpect_equal(expected_call_count, target_stop_0_fake.call_count,
100 			      "Expected to be called %d times, got %d", expected_call_count,
101 			      target_stop_0_fake.call_count);
102 	}
103 }
104 
ZTEST(i2c_emul_forwarding,test_recover_failed_write)105 ZTEST(i2c_emul_forwarding, test_recover_failed_write)
106 {
107 	uint8_t write_data[2];
108 
109 	// Fail on the write request (should never call the write_received function)
110 	target_write_requested_0_fake.return_val = -EINVAL;
111 	zassert_equal(-EINVAL, i2c_write(controller, write_data, sizeof(write_data),
112 					 emulated_target_config[0].address));
113 	zexpect_equal(1, target_write_requested_0_fake.call_count, "Was called %d times",
114 		      target_write_requested_0_fake.call_count);
115 	zexpect_equal(0, target_write_received_0_fake.call_count, "Was called %d times",
116 		      target_write_requested_0_fake.call_count);
117 
118 	// Next instruction should succeed
119 	target_write_requested_0_fake.return_val = 0;
120 	zassert_ok(i2c_write(controller, write_data, sizeof(write_data),
121 			     emulated_target_config[0].address));
122 	zexpect_equal(2, target_write_requested_0_fake.call_count, "Was called %d times",
123 		      target_write_requested_0_fake.call_count);
124 	zexpect_equal(2, target_write_received_0_fake.call_count, "Was called %d times",
125 		      target_write_requested_0_fake.call_count);
126 }
127 
ZTEST(i2c_emul_forwarding,test_recover_failed_read)128 ZTEST(i2c_emul_forwarding, test_recover_failed_read)
129 {
130 	uint8_t read_data[2];
131 
132 	// Fail the read_requested (should never call the read_processed function)
133 	target_read_requested_0_fake.return_val = -EINVAL;
134 	zassert_equal(-EINVAL, i2c_read(controller, read_data, sizeof(read_data),
135 					emulated_target_config[0].address));
136 	zexpect_equal(1, target_read_requested_0_fake.call_count, "Was called %d times",
137 		      target_read_requested_0_fake.call_count);
138 	zexpect_equal(0, target_read_processed_0_fake.call_count, "Was called %d times",
139 		      target_read_processed_0_fake.call_count);
140 
141 	// Next instruction should pass
142 	target_read_requested_0_fake.return_val = 0;
143 	zassert_ok(i2c_read(controller, read_data, sizeof(read_data),
144 			    emulated_target_config[0].address));
145 	zexpect_equal(2, target_read_requested_0_fake.call_count, "Was called %d times",
146 		      target_read_requested_0_fake.call_count);
147 	zexpect_equal(1, target_read_processed_0_fake.call_count, "Was called %d times",
148 		      target_read_processed_0_fake.call_count);
149 }
150 
ZTEST(i2c_emul_forwarding,test_transfer_is_forwarded)151 ZTEST(i2c_emul_forwarding, test_transfer_is_forwarded)
152 {
153 	uint8_t write_data[1] = {};
154 	uint8_t read_data[2] = {};
155 
156 	struct i2c_msg msgs[] = {
157 		{
158 			.buf = write_data,
159 			.len = sizeof(write_data),
160 			.flags = I2C_MSG_WRITE,
161 		},
162 		{
163 			.buf = read_data,
164 			.len = sizeof(read_data),
165 			.flags = I2C_MSG_READ | I2C_MSG_STOP,
166 		},
167 	};
168 
169 	int phase = 0;
170 	target_write_requested_0_fake.custom_fake = [&phase](struct i2c_target_config *) -> int {
171 		zassert_equal(0, phase, "Expected a call to write_requested before anything else");
172 		phase++;
173 		return 0;
174 	};
175 	target_write_received_0_fake.custom_fake = [&phase](struct i2c_target_config *,
176 							    uint8_t) -> int {
177 		zassert_equal(1, phase, "Expected a call to write_received as the second step");
178 		phase++;
179 		return 0;
180 	};
181 	target_read_requested_0_fake.custom_fake = [&phase](struct i2c_target_config *,
182 							    uint8_t *) -> int {
183 		zassert_equal(2, phase, "Expected a call to read_requested as the 3rd step");
184 		phase++;
185 		return 0;
186 	};
187 	target_read_processed_0_fake.custom_fake = [&phase](struct i2c_target_config *,
188 							    uint8_t *) -> int {
189 		zassert_equal(3, phase, "Expected a call to read_processed as the 4th step");
190 		phase++;
191 		return 0;
192 	};
193 	target_stop_0_fake.custom_fake = [&phase](struct i2c_target_config *) -> int {
194 		zassert_equal(4, phase, "Expected a call to stop as the 5th step");
195 		phase++;
196 		return 0;
197 	};
198 	zassert_ok(i2c_transfer(controller, msgs, ARRAY_SIZE(msgs),
199 				emulated_target_config[0].address));
200 	zexpect_equal(1, target_write_requested_0_fake.call_count,
201 		      "Expected target_write_requested to be called once, but got %d",
202 		      target_write_requested_0_fake.call_count);
203 	zexpect_equal(1, target_write_received_0_fake.call_count,
204 		      "Expected target_write_received to be called once, but got %d",
205 		      target_write_received_0_fake.call_count);
206 	zexpect_equal(1, target_read_requested_0_fake.call_count,
207 		      "Expected target_read_requested to be called once, but got %d",
208 		      target_read_requested_0_fake.call_count);
209 	zexpect_equal(1, target_read_processed_0_fake.call_count,
210 		      "Expected target_read_processed to be called once, but got %d",
211 		      target_read_processed_0_fake.call_count);
212 	zexpect_equal(1, target_stop_0_fake.call_count,
213 		      "Expected target_stop to be called once, but got %d",
214 		      target_stop_0_fake.call_count);
215 	zexpect_equal(5, phase, "Expected a total of 5 phases, but got %d", phase);
216 }
217 
ZTEST(i2c_emul_forwarding,test_forward_two_targets)218 ZTEST(i2c_emul_forwarding, test_forward_two_targets)
219 {
220 	uint8_t read_data[2];
221 
222 	// Read the second forward and ensure that we only forwarded to the correct one
223 	zassert_ok(i2c_read(controller, read_data, sizeof(read_data),
224 			    emulated_target_config[1].address));
225 
226 	// Check that we got the forward
227 	zexpect_equal(1, target_read_requested_1_fake.call_count,
228 		      "Expected to be called 1 time, got %d",
229 		      target_read_requested_1_fake.call_count);
230 	zexpect_equal(1, target_read_processed_1_fake.call_count,
231 		      "Expected to be called 1 time, got %d",
232 		      target_read_processed_1_fake.call_count);
233 
234 	// Check that we didn't forward to the first target
235 	zexpect_equal(0, target_read_requested_0_fake.call_count,
236 		      "Expected to be called 0 times, got %d",
237 		      target_read_requested_0_fake.call_count);
238 	zexpect_equal(0, target_read_processed_0_fake.call_count,
239 		      "Expected to be called 0 times, got %d",
240 		      target_read_processed_0_fake.call_count);
241 }
242 
ZTEST(i2c_emul_forwarding,test_error_in_write_received)243 ZTEST(i2c_emul_forwarding, test_error_in_write_received)
244 {
245 	uint8_t data;
246 
247 	target_write_received_0_fake.return_val = -EINTR;
248 	zassert_equal(-EINTR, i2c_write(controller, &data, 1, emulated_target_config[0].address));
249 	zexpect_equal(1, target_write_requested_0_fake.call_count);
250 	zexpect_equal(1, target_write_received_0_fake.call_count);
251 	zexpect_equal(0, target_stop_0_fake.call_count);
252 }
253 
254 } // namespace
255