1 /*
2  * Copyright (c) 2019 Vestas Wind Systems A/S
3  * Copyright (c) 2021 Lemonbeat GmbH
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @file
10  * @brief EEPROM shell commands.
11  */
12 
13 #include <zephyr/shell/shell.h>
14 #include <zephyr/drivers/eeprom.h>
15 #include <stdlib.h>
16 
17 struct args_index {
18 	uint8_t device;
19 	uint8_t offset;
20 	uint8_t length;
21 	uint8_t data;
22 	uint8_t pattern;
23 };
24 
25 static const struct args_index args_indx = {
26 	.device = 1,
27 	.offset = 2,
28 	.length = 3,
29 	.data = 3,
30 	.pattern = 4,
31 };
32 
cmd_read(const struct shell * sh,size_t argc,char ** argv)33 static int cmd_read(const struct shell *sh, size_t argc, char **argv)
34 {
35 	const struct device *eeprom;
36 	size_t addr;
37 	size_t len;
38 	size_t pending;
39 	size_t upto;
40 	int err;
41 
42 	addr = strtoul(argv[args_indx.offset], NULL, 0);
43 	len = strtoul(argv[args_indx.length], NULL, 0);
44 
45 	eeprom = device_get_binding(argv[args_indx.device]);
46 	if (!eeprom) {
47 		shell_error(sh, "EEPROM device not found");
48 		return -EINVAL;
49 	}
50 
51 	shell_print(sh, "Reading %zu bytes from EEPROM, offset %zu...", len,
52 		    addr);
53 
54 	for (upto = 0; upto < len; upto += pending) {
55 		uint8_t data[SHELL_HEXDUMP_BYTES_IN_LINE];
56 
57 		pending = MIN(len - upto, SHELL_HEXDUMP_BYTES_IN_LINE);
58 		err = eeprom_read(eeprom, addr, data, pending);
59 		if (err) {
60 			shell_error(sh, "EEPROM read failed (err %d)", err);
61 			return err;
62 		}
63 
64 		shell_hexdump_line(sh, addr, data, pending);
65 		addr += pending;
66 	}
67 
68 	shell_print(sh, "");
69 	return 0;
70 }
71 
cmd_write(const struct shell * sh,size_t argc,char ** argv)72 static int cmd_write(const struct shell *sh, size_t argc, char **argv)
73 {
74 	uint8_t wr_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE];
75 	uint8_t rd_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE];
76 	const struct device *eeprom;
77 	unsigned long byte;
78 	off_t offset;
79 	size_t len;
80 	int err;
81 	int i;
82 
83 	offset = strtoul(argv[args_indx.offset], NULL, 0);
84 	len = argc - args_indx.data;
85 
86 	if (len > sizeof(wr_buf)) {
87 		shell_error(sh, "Write buffer size (%zu bytes) exceeded",
88 			    sizeof(wr_buf));
89 		return -EINVAL;
90 	}
91 
92 	for (i = 0; i < len; i++) {
93 		byte = strtoul(argv[args_indx.data + i], NULL, 0);
94 		if (byte > UINT8_MAX) {
95 			shell_error(sh, "Error parsing data byte %d", i);
96 			return -EINVAL;
97 		}
98 		wr_buf[i] = byte;
99 	}
100 
101 	eeprom = device_get_binding(argv[args_indx.device]);
102 	if (!eeprom) {
103 		shell_error(sh, "EEPROM device not found");
104 		return -EINVAL;
105 	}
106 
107 	shell_print(sh, "Writing %zu bytes to EEPROM...", len);
108 
109 	err = eeprom_write(eeprom, offset, wr_buf, len);
110 	if (err) {
111 		shell_error(sh, "EEPROM write failed (err %d)", err);
112 		return err;
113 	}
114 
115 	shell_print(sh, "Verifying...");
116 
117 	err = eeprom_read(eeprom, offset, rd_buf, len);
118 	if (err) {
119 		shell_error(sh, "EEPROM read failed (err %d)", err);
120 		return err;
121 	}
122 
123 	if (memcmp(wr_buf, rd_buf, len) != 0) {
124 		shell_error(sh, "Verify failed");
125 		return -EIO;
126 	}
127 
128 	shell_print(sh, "Verify OK");
129 
130 	return 0;
131 }
132 
cmd_size(const struct shell * sh,size_t argc,char ** argv)133 static int cmd_size(const struct shell *sh, size_t argc, char **argv)
134 {
135 	const struct device *eeprom;
136 
137 	eeprom = device_get_binding(argv[args_indx.device]);
138 	if (!eeprom) {
139 		shell_error(sh, "EEPROM device not found");
140 		return -EINVAL;
141 	}
142 
143 	shell_print(sh, "%zu bytes", eeprom_get_size(eeprom));
144 	return 0;
145 }
146 
cmd_fill(const struct shell * sh,size_t argc,char ** argv)147 static int cmd_fill(const struct shell *sh, size_t argc, char **argv)
148 {
149 	uint8_t wr_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE];
150 	uint8_t rd_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE];
151 	const struct device *eeprom;
152 	unsigned long pattern;
153 	size_t addr;
154 	size_t initial_offset;
155 	size_t len;
156 	size_t pending;
157 	size_t upto;
158 	int err;
159 
160 	initial_offset = strtoul(argv[args_indx.offset], NULL, 0);
161 	len = strtoul(argv[args_indx.length], NULL, 0);
162 
163 	pattern = strtoul(argv[args_indx.pattern], NULL, 0);
164 	if (pattern > UINT8_MAX) {
165 		shell_error(sh, "Error parsing pattern byte");
166 		return -EINVAL;
167 	}
168 	memset(wr_buf, pattern, MIN(len, CONFIG_EEPROM_SHELL_BUFFER_SIZE));
169 
170 	eeprom = device_get_binding(argv[args_indx.device]);
171 	if (!eeprom) {
172 		shell_error(sh, "EEPROM device not found");
173 		return -EINVAL;
174 	}
175 
176 	shell_print(sh, "Writing %zu bytes of 0x%02lx to EEPROM...", len,
177 		    pattern);
178 
179 	addr = initial_offset;
180 
181 	for (upto = 0; upto < len; upto += pending) {
182 		pending = MIN(len - upto, CONFIG_EEPROM_SHELL_BUFFER_SIZE);
183 		err = eeprom_write(eeprom, addr, wr_buf, pending);
184 		if (err) {
185 			shell_error(sh, "EEPROM write failed (err %d)", err);
186 			return err;
187 		}
188 		addr += pending;
189 	}
190 
191 	addr = initial_offset;
192 
193 	shell_print(sh, "Verifying...");
194 
195 	for (upto = 0; upto < len; upto += pending) {
196 		pending = MIN(len - upto, CONFIG_EEPROM_SHELL_BUFFER_SIZE);
197 		err = eeprom_read(eeprom, addr, rd_buf, pending);
198 		if (err) {
199 			shell_error(sh, "EEPROM read failed (err %d)", err);
200 			return err;
201 		}
202 
203 		if (memcmp(wr_buf, rd_buf, pending) != 0) {
204 			shell_error(sh, "Verify failed");
205 			return -EIO;
206 		}
207 
208 		addr += pending;
209 	}
210 
211 	shell_print(sh, "Verify OK");
212 
213 	return 0;
214 }
215 
216 /* Device name autocompletion support */
device_name_get(size_t idx,struct shell_static_entry * entry)217 static void device_name_get(size_t idx, struct shell_static_entry *entry)
218 {
219 	const struct device *dev = shell_device_lookup(idx, NULL);
220 
221 	entry->syntax = (dev != NULL) ? dev->name : NULL;
222 	entry->handler = NULL;
223 	entry->help = NULL;
224 	entry->subcmd = NULL;
225 }
226 
227 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
228 
229 SHELL_STATIC_SUBCMD_SET_CREATE(eeprom_cmds,
230 	SHELL_CMD_ARG(read, &dsub_device_name,
231 		      "<device> <offset> <length>", cmd_read, 4, 0),
232 	SHELL_CMD_ARG(write, &dsub_device_name,
233 		      "<device> <offset> [byte0] <byte1> .. <byteN>", cmd_write,
234 		      4, CONFIG_EEPROM_SHELL_BUFFER_SIZE - 1),
235 	SHELL_CMD_ARG(size, &dsub_device_name, "<device>", cmd_size, 2, 0),
236 	SHELL_CMD_ARG(fill, &dsub_device_name,
237 		      "<device> <offset> <length> <pattern>", cmd_fill, 5, 0),
238 	SHELL_SUBCMD_SET_END
239 );
240 
241 SHELL_CMD_REGISTER(eeprom, &eeprom_cmds, "EEPROM shell commands", NULL);
242