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