1 /*
2 * Copyright (c) 2022 Vestas Wind Systems A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/eeprom.h>
8 #include <zephyr/drivers/eeprom/eeprom_fake.h>
9 #include <zephyr/fff.h>
10 #include <zephyr/shell/shell.h>
11 #include <zephyr/shell/shell_dummy.h>
12 #include <zephyr/sys/util.h>
13 #include <zephyr/ztest.h>
14
15 #define FAKE_EEPROM_NAME DEVICE_DT_NAME(DT_NODELABEL(fake_eeprom))
16
17 /* Global variables */
18 static const struct device *const fake_eeprom_dev = DEVICE_DT_GET(DT_NODELABEL(fake_eeprom));
19 static uint8_t data_capture[CONFIG_EEPROM_SHELL_BUFFER_SIZE];
20 DEFINE_FFF_GLOBALS;
21
eeprom_shell_test_write_capture_data(const struct device * dev,off_t offset,const void * data,size_t len)22 static int eeprom_shell_test_write_capture_data(const struct device *dev, off_t offset,
23 const void *data, size_t len)
24 {
25 ARG_UNUSED(dev);
26 ARG_UNUSED(offset);
27
28 zassert_true(len <= sizeof(data_capture));
29 memcpy(&data_capture, data, MIN(sizeof(data_capture), len));
30
31 return 0;
32 }
33
eeprom_shell_test_read_captured_data(const struct device * dev,off_t offset,void * data,size_t len)34 static int eeprom_shell_test_read_captured_data(const struct device *dev, off_t offset,
35 void *data, size_t len)
36 {
37 ARG_UNUSED(dev);
38 ARG_UNUSED(offset);
39
40 zassert_true(len <= sizeof(data_capture));
41 memcpy(data, &data_capture, MIN(sizeof(data_capture), len));
42
43 return 0;
44 }
45
ZTEST(eeprom_shell,test_eeprom_write)46 ZTEST(eeprom_shell, test_eeprom_write)
47 {
48 const struct shell *sh = shell_backend_dummy_get_ptr();
49 const uint8_t expected[] = { 0x11, 0x22, 0x33, 0x44, 0xaa, 0xbb, 0xcc, 0xdd };
50 int err;
51
52 /* This test relies on the EEPROM shell using a buffer size of at least 8 bytes */
53 BUILD_ASSERT(CONFIG_EEPROM_SHELL_BUFFER_SIZE >= 8);
54
55 /* Setup data capture to satisfy EEPROM shell verification read-back */
56 fake_eeprom_write_fake.custom_fake = eeprom_shell_test_write_capture_data;
57 fake_eeprom_read_fake.custom_fake = eeprom_shell_test_read_captured_data;
58
59 err = shell_execute_cmd(sh, "eeprom write " FAKE_EEPROM_NAME
60 " 8 0x11 0x22 0x33 0x44 0xaa 0xbb 0xcc 0xdd");
61 zassert_ok(err, "failed to execute shell command (err %d)", err);
62
63 /* The EEPROM shell will write the bytes ... */
64 zassert_equal(fake_eeprom_write_fake.call_count, 1);
65 zassert_equal(fake_eeprom_write_fake.arg0_val, fake_eeprom_dev);
66 zassert_equal(fake_eeprom_write_fake.arg1_val, 8);
67 zassert_not_null(fake_eeprom_write_fake.arg2_val);
68 zassert_equal(fake_eeprom_write_fake.arg3_val, 8);
69
70 /* ... and verify the written bytes by reading them back */
71 zassert_equal(fake_eeprom_read_fake.call_count, 1);
72 zassert_equal(fake_eeprom_read_fake.arg0_val, fake_eeprom_dev);
73 zassert_equal(fake_eeprom_read_fake.arg1_val, 8);
74 zassert_not_null(fake_eeprom_read_fake.arg2_val);
75 zassert_equal(fake_eeprom_write_fake.arg3_val, 8);
76
77 /* Verify data values parsed and written correctly */
78 zassert_mem_equal(&data_capture, &expected, sizeof(expected));
79 }
80
ZTEST(eeprom_shell,test_eeprom_write_failed_verification)81 ZTEST(eeprom_shell, test_eeprom_write_failed_verification)
82 {
83 const struct shell *sh = shell_backend_dummy_get_ptr();
84 int err;
85
86 err = shell_execute_cmd(sh, "eeprom write " FAKE_EEPROM_NAME " 0 0xaa 0x55");
87 zassert_true(err < 0, "shell command should have failed (err %d)", err);
88
89 /* The EEPROM shell will write the bytes ... */
90 zassert_equal(fake_eeprom_write_fake.call_count, 1);
91 zassert_equal(fake_eeprom_write_fake.arg0_val, fake_eeprom_dev);
92 zassert_equal(fake_eeprom_write_fake.arg1_val, 0);
93 zassert_not_null(fake_eeprom_write_fake.arg2_val);
94 zassert_equal(fake_eeprom_write_fake.arg3_val, 2);
95
96 /* ... and attempt to verify the written bytes by reading them back */
97 zassert_equal(fake_eeprom_read_fake.call_count, 1);
98 zassert_equal(fake_eeprom_read_fake.arg0_val, fake_eeprom_dev);
99 zassert_equal(fake_eeprom_read_fake.arg1_val, 0);
100 zassert_not_null(fake_eeprom_read_fake.arg2_val);
101 zassert_equal(fake_eeprom_write_fake.arg3_val, 2);
102 }
103
ZTEST(eeprom_shell,test_eeprom_read)104 ZTEST(eeprom_shell, test_eeprom_read)
105 {
106 const struct shell *sh = shell_backend_dummy_get_ptr();
107 int err;
108
109 /* This test relies on the shell hexdumping 16 bytes per line */
110 BUILD_ASSERT(SHELL_HEXDUMP_BYTES_IN_LINE == 16);
111
112 /* The EEPROM shell will split this read into two calls to eeprom_read() */
113 err = shell_execute_cmd(sh, "eeprom read " FAKE_EEPROM_NAME " 8 32");
114 zassert_ok(err, "failed to execute shell command (err %d)", err);
115 zassert_equal(fake_eeprom_read_fake.call_count, 2);
116
117 /* 1st read */
118 zassert_equal(fake_eeprom_read_fake.arg0_history[0], fake_eeprom_dev);
119 zassert_equal(fake_eeprom_read_fake.arg1_history[0], 8);
120 zassert_not_null(fake_eeprom_read_fake.arg2_history[0]);
121 zassert_equal(fake_eeprom_read_fake.arg3_history[0], SHELL_HEXDUMP_BYTES_IN_LINE);
122
123 /* 2nd read */
124 zassert_equal(fake_eeprom_read_fake.arg0_history[1], fake_eeprom_dev);
125 zassert_equal(fake_eeprom_read_fake.arg1_history[1], 8 + SHELL_HEXDUMP_BYTES_IN_LINE);
126 zassert_not_null(fake_eeprom_read_fake.arg2_history[1]);
127 zassert_equal(fake_eeprom_read_fake.arg3_history[1], SHELL_HEXDUMP_BYTES_IN_LINE);
128 }
129
ZTEST(eeprom_shell,test_eeprom_size)130 ZTEST(eeprom_shell, test_eeprom_size)
131 {
132 const struct shell *sh = shell_backend_dummy_get_ptr();
133 int err;
134
135 err = shell_execute_cmd(sh, "eeprom size " FAKE_EEPROM_NAME);
136 zassert_ok(err, "failed to execute shell command (err %d)", err);
137 zassert_equal(fake_eeprom_size_fake.call_count, 1);
138 zassert_equal(fake_eeprom_size_fake.arg0_val, fake_eeprom_dev);
139 }
140
ZTEST(eeprom_shell,test_eeprom_fill)141 ZTEST(eeprom_shell, test_eeprom_fill)
142 {
143 const struct shell *sh = shell_backend_dummy_get_ptr();
144 const uint8_t expected[] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
145 int err;
146
147 /* This test relies on the EEPROM shell using a buffer size of at least 8 bytes */
148 BUILD_ASSERT(CONFIG_EEPROM_SHELL_BUFFER_SIZE >= 8);
149
150 /* Setup data capture to satisfy EEPROM shell verification read-back */
151 fake_eeprom_write_fake.custom_fake = eeprom_shell_test_write_capture_data;
152 fake_eeprom_read_fake.custom_fake = eeprom_shell_test_read_captured_data;
153
154 err = shell_execute_cmd(sh, "eeprom fill " FAKE_EEPROM_NAME
155 " 16 8 0xaa");
156 zassert_ok(err, "failed to execute shell command (err %d)", err);
157
158 /* The EEPROM shell will write the bytes ... */
159 zassert_equal(fake_eeprom_write_fake.call_count, 1);
160 zassert_equal(fake_eeprom_write_fake.arg0_val, fake_eeprom_dev);
161 zassert_equal(fake_eeprom_write_fake.arg1_val, 16);
162 zassert_not_null(fake_eeprom_write_fake.arg2_val);
163 zassert_equal(fake_eeprom_write_fake.arg3_val, 8);
164
165 /* ... and verify the written bytes by reading them back */
166 zassert_equal(fake_eeprom_read_fake.call_count, 1);
167 zassert_equal(fake_eeprom_read_fake.arg0_val, fake_eeprom_dev);
168 zassert_equal(fake_eeprom_read_fake.arg1_val, 16);
169 zassert_not_null(fake_eeprom_read_fake.arg2_val);
170 zassert_equal(fake_eeprom_write_fake.arg3_val, 8);
171
172 /* Verify data values parsed and written correctly */
173 zassert_mem_equal(&data_capture, &expected, sizeof(expected));
174 }
175
eeprom_shell_before(void * fixture)176 static void eeprom_shell_before(void *fixture)
177 {
178 ARG_UNUSED(fixture);
179
180 memset(&data_capture, 0, sizeof(data_capture));
181 }
182
eeprom_shell_setup(void)183 static void *eeprom_shell_setup(void)
184 {
185 const struct shell *sh = shell_backend_dummy_get_ptr();
186
187 zassert_true(device_is_ready(fake_eeprom_dev));
188
189 /* Verify that the EEPROM size is as expected by the tests */
190 zassert_equal(KB(8), eeprom_get_size(fake_eeprom_dev));
191
192 /* Wait for the initialization of the shell dummy backend. */
193 WAIT_FOR(shell_ready(sh), 20000, k_msleep(1));
194 zassert_true(shell_ready(sh), "timed out waiting for dummy shell backend");
195
196 return NULL;
197 }
198
199 ZTEST_SUITE(eeprom_shell, NULL, eeprom_shell_setup, eeprom_shell_before, NULL, NULL);
200