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