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