1 /*
2  * Copyright 2024 Google LLC
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "emulated_target.hpp"
6 #include <cstdint>
7 
8 #include <zephyr/devicetree.h>
9 #include <zephyr/drivers/i2c.h>
10 #include <zephyr/fff.h>
11 #include <zephyr/ztest.h>
12 
13 namespace
14 {
15 
16 /* Get the devicetree constants */
17 constexpr const struct device *controller = DEVICE_DT_GET(CONTROLLER_LABEL);
18 
ZTEST(i2c_emul_forwarding,test_write_is_forwarded)19 ZTEST(i2c_emul_forwarding, test_write_is_forwarded)
20 {
21 	uint8_t data[] = {0x00, 0x01, 0x02};
22 
23 	target_buf_write_received_0_fake.custom_fake = [&data](struct i2c_target_config *,
24 							       uint8_t *buf, uint32_t len) {
25 		zassert_equal(ARRAY_SIZE(data), len);
26 		zexpect_mem_equal(data, buf, len);
27 	};
28 
29 	zassert_ok(
30 		i2c_write(controller, data, ARRAY_SIZE(data), emulated_target_config[0].address));
31 
32 	// Expect 0 reads and 1 write/stop to be made
33 	zexpect_equal(0, target_buf_read_requested_0_fake.call_count);
34 	zexpect_equal(1, target_buf_write_received_0_fake.call_count);
35 	zexpect_equal(1, target_stop_0_fake.call_count);
36 }
37 
ZTEST(i2c_emul_forwarding,test_read_is_forwarded)38 ZTEST(i2c_emul_forwarding, test_read_is_forwarded)
39 {
40 	uint8_t expected[] = {0x01, 0x02, 0x03};
41 	uint8_t data[ARRAY_SIZE(expected)] = {};
42 
43 	/* Set the custom fake function to a lambda which captures the expected value as a reference.
44 	 * This means that when the function is executed, we can access 'expected' as though it were
45 	 * within the lambda's scope.
46 	 */
47 	target_buf_read_requested_0_fake.custom_fake = [&expected](struct i2c_target_config *,
48 								   uint8_t **ptr, uint32_t *len) {
49 		*ptr = expected;
50 		*len = ARRAY_SIZE(expected);
51 		return 0;
52 	};
53 
54 	zassert_ok(i2c_read(controller, data, ARRAY_SIZE(expected),
55 			    emulated_target_config[0].address));
56 
57 	// Expect 1 read/stop and 0 write to be made
58 	zexpect_equal(1, target_buf_read_requested_0_fake.call_count);
59 	zexpect_equal(0, target_buf_write_received_0_fake.call_count);
60 	zexpect_equal(1, target_stop_0_fake.call_count);
61 	zexpect_mem_equal(expected, data, ARRAY_SIZE(expected));
62 }
63 
ZTEST(i2c_emul_forwarding,test_failed_read_request)64 ZTEST(i2c_emul_forwarding, test_failed_read_request)
65 {
66 	uint8_t data;
67 	target_buf_read_requested_0_fake.return_val = -EINTR;
68 
69 	zassert_equal(-EINTR, i2c_read(controller, &data, 1, emulated_target_config[0].address));
70 	zexpect_equal(1, target_buf_read_requested_0_fake.call_count);
71 	zexpect_equal(0, target_buf_write_received_0_fake.call_count);
72 	zexpect_equal(0, target_stop_0_fake.call_count);
73 }
74 
ZTEST(i2c_emul_forwarding,test_read_request_overflow)75 ZTEST(i2c_emul_forwarding, test_read_request_overflow)
76 {
77 	uint8_t data;
78 
79 	/* Set the custom_fake to a local lambda with no capture values. */
80 	target_buf_read_requested_0_fake.custom_fake = [](struct i2c_target_config *, uint8_t **_,
81 							  uint32_t *len) {
82 		*len = UINT32_MAX;
83 		return 0;
84 	};
85 
86 	zassert_equal(-ENOMEM, i2c_read(controller, &data, 1, emulated_target_config[0].address));
87 	zexpect_equal(1, target_buf_read_requested_0_fake.call_count);
88 	zexpect_equal(0, target_buf_write_received_0_fake.call_count);
89 	zexpect_equal(0, target_stop_0_fake.call_count);
90 }
91 
ZTEST(i2c_emul_forwarding,test_transfer_is_forwarded)92 ZTEST(i2c_emul_forwarding, test_transfer_is_forwarded)
93 {
94 	uint8_t write_data[1] = {};
95 	uint8_t read_data[2] = {};
96 
97 	struct i2c_msg msgs[] = {
98 		{
99 			.buf = write_data,
100 			.len = sizeof(write_data),
101 			.flags = I2C_MSG_WRITE,
102 		},
103 		{
104 			.buf = read_data,
105 			.len = sizeof(read_data),
106 			.flags = I2C_MSG_READ | I2C_MSG_STOP,
107 		},
108 	};
109 
110 	int phase = 0;
111 	target_buf_write_received_0_fake.custom_fake = [&phase](struct i2c_target_config *,
112 								uint8_t *, uint32_t) {
113 		zassert_equal(0, phase,
114 			      "Expected a call to buf_write_received before anything else");
115 		phase++;
116 	};
117 	target_buf_read_requested_0_fake.custom_fake = [&phase](struct i2c_target_config *,
118 								uint8_t **ptr, uint32_t *len) {
119 		zassert_equal(1, phase, "Expected a call to buf_Read_requested as the second step");
120 		phase++;
121 
122 		// Write a random byte. It doesn't make a difference.
123 		*ptr = (uint8_t *)&phase;
124 		*len = 1;
125 		return 0;
126 	};
127 	target_stop_0_fake.custom_fake = [&phase](struct i2c_target_config *) -> int {
128 		zassert_equal(2, phase, "Expected a call to stop as the 3rd step");
129 		phase++;
130 		return 0;
131 	};
132 
133 	zassert_ok(i2c_transfer(controller, msgs, ARRAY_SIZE(msgs),
134 				emulated_target_config[0].address));
135 	zexpect_equal(1, target_buf_write_received_0_fake.call_count);
136 	zexpect_equal(1, target_buf_read_requested_0_fake.call_count);
137 	zexpect_equal(1, target_stop_0_fake.call_count);
138 	zexpect_equal(3, phase, "Expected a total of 3 phases, but got %d", phase);
139 }
140 
ZTEST(i2c_emul_forwarding,test_call_pio_forwarded_bus_when_buffering_enabled)141 ZTEST(i2c_emul_forwarding, test_call_pio_forwarded_bus_when_buffering_enabled)
142 {
143 	uint8_t data[2];
144 
145 	zassert_ok(i2c_read(controller, data, ARRAY_SIZE(data), emulated_target_config[1].address));
146 	zexpect_equal(1, target_read_requested_1_fake.call_count);
147 	zexpect_equal(1, target_read_processed_1_fake.call_count);
148 	zexpect_equal(1, target_stop_1_fake.call_count);
149 }
150 
151 } // namespace
152