| /* |
| * Copyright (c) 2019 Vestas Wind Systems A/S |
| * Copyright (c) 2021 Lemonbeat GmbH |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * @brief EEPROM shell commands. |
| */ |
| |
| #include <zephyr/shell/shell.h> |
| #include <zephyr/drivers/eeprom.h> |
| #include <stdlib.h> |
| |
| struct args_index { |
| uint8_t device; |
| uint8_t offset; |
| uint8_t length; |
| uint8_t data; |
| uint8_t pattern; |
| }; |
| |
| static const struct args_index args_indx = { |
| .device = 1, |
| .offset = 2, |
| .length = 3, |
| .data = 3, |
| .pattern = 4, |
| }; |
| |
| static int cmd_read(const struct shell *shell, size_t argc, char **argv) |
| { |
| const struct device *eeprom; |
| size_t addr; |
| size_t len; |
| size_t pending; |
| size_t upto; |
| int err; |
| |
| addr = strtoul(argv[args_indx.offset], NULL, 0); |
| len = strtoul(argv[args_indx.length], NULL, 0); |
| |
| eeprom = device_get_binding(argv[args_indx.device]); |
| if (!eeprom) { |
| shell_error(shell, "EEPROM device not found"); |
| return -EINVAL; |
| } |
| |
| shell_print(shell, "Reading %zu bytes from EEPROM, offset %zu...", len, |
| addr); |
| |
| for (upto = 0; upto < len; upto += pending) { |
| uint8_t data[SHELL_HEXDUMP_BYTES_IN_LINE]; |
| |
| pending = MIN(len - upto, SHELL_HEXDUMP_BYTES_IN_LINE); |
| err = eeprom_read(eeprom, addr, data, pending); |
| if (err) { |
| shell_error(shell, "EEPROM read failed (err %d)", err); |
| return err; |
| } |
| |
| shell_hexdump_line(shell, addr, data, pending); |
| addr += pending; |
| } |
| |
| shell_print(shell, ""); |
| return 0; |
| } |
| |
| static int cmd_write(const struct shell *shell, size_t argc, char **argv) |
| { |
| uint8_t wr_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE]; |
| uint8_t rd_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE]; |
| const struct device *eeprom; |
| unsigned long byte; |
| off_t offset; |
| size_t len; |
| int err; |
| int i; |
| |
| offset = strtoul(argv[args_indx.offset], NULL, 0); |
| len = argc - args_indx.data; |
| |
| if (len > sizeof(wr_buf)) { |
| shell_error(shell, "Write buffer size (%zu bytes) exceeded", |
| sizeof(wr_buf)); |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < len; i++) { |
| byte = strtoul(argv[args_indx.data + i], NULL, 0); |
| if (byte > UINT8_MAX) { |
| shell_error(shell, "Error parsing data byte %d", i); |
| return -EINVAL; |
| } |
| wr_buf[i] = byte; |
| } |
| |
| eeprom = device_get_binding(argv[args_indx.device]); |
| if (!eeprom) { |
| shell_error(shell, "EEPROM device not found"); |
| return -EINVAL; |
| } |
| |
| shell_print(shell, "Writing %zu bytes to EEPROM...", len); |
| |
| err = eeprom_write(eeprom, offset, wr_buf, len); |
| if (err) { |
| shell_error(shell, "EEPROM write failed (err %d)", err); |
| return err; |
| } |
| |
| shell_print(shell, "Verifying..."); |
| |
| err = eeprom_read(eeprom, offset, rd_buf, len); |
| if (err) { |
| shell_error(shell, "EEPROM read failed (err %d)", err); |
| return err; |
| } |
| |
| if (memcmp(wr_buf, rd_buf, len) != 0) { |
| shell_error(shell, "Verify failed"); |
| return -EIO; |
| } |
| |
| shell_print(shell, "Verify OK"); |
| |
| return 0; |
| } |
| |
| static int cmd_size(const struct shell *shell, size_t argc, char **argv) |
| { |
| const struct device *eeprom; |
| |
| eeprom = device_get_binding(argv[args_indx.device]); |
| if (!eeprom) { |
| shell_error(shell, "EEPROM device not found"); |
| return -EINVAL; |
| } |
| |
| shell_print(shell, "%zu bytes", eeprom_get_size(eeprom)); |
| return 0; |
| } |
| |
| static int cmd_fill(const struct shell *shell, size_t argc, char **argv) |
| { |
| uint8_t wr_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE]; |
| uint8_t rd_buf[CONFIG_EEPROM_SHELL_BUFFER_SIZE]; |
| const struct device *eeprom; |
| unsigned long pattern; |
| size_t addr; |
| size_t initial_offset; |
| size_t len; |
| size_t pending; |
| size_t upto; |
| int err; |
| |
| initial_offset = strtoul(argv[args_indx.offset], NULL, 0); |
| len = strtoul(argv[args_indx.length], NULL, 0); |
| |
| pattern = strtoul(argv[args_indx.pattern], NULL, 0); |
| if (pattern > UINT8_MAX) { |
| shell_error(shell, "Error parsing pattern byte"); |
| return -EINVAL; |
| } |
| memset(wr_buf, pattern, MIN(len, CONFIG_EEPROM_SHELL_BUFFER_SIZE)); |
| |
| eeprom = device_get_binding(argv[args_indx.device]); |
| if (!eeprom) { |
| shell_error(shell, "EEPROM device not found"); |
| return -EINVAL; |
| } |
| |
| shell_print(shell, "Writing %zu bytes of 0x%02lx to EEPROM...", len, |
| pattern); |
| |
| addr = initial_offset; |
| |
| for (upto = 0; upto < len; upto += pending) { |
| pending = MIN(len - upto, CONFIG_EEPROM_SHELL_BUFFER_SIZE); |
| err = eeprom_write(eeprom, addr, wr_buf, pending); |
| if (err) { |
| shell_error(shell, "EEPROM write failed (err %d)", err); |
| return err; |
| } |
| addr += pending; |
| } |
| |
| addr = initial_offset; |
| |
| shell_print(shell, "Verifying..."); |
| |
| for (upto = 0; upto < len; upto += pending) { |
| pending = MIN(len - upto, CONFIG_EEPROM_SHELL_BUFFER_SIZE); |
| err = eeprom_read(eeprom, addr, rd_buf, pending); |
| if (err) { |
| shell_error(shell, "EEPROM read failed (err %d)", err); |
| return err; |
| } |
| |
| if (memcmp(wr_buf, rd_buf, pending) != 0) { |
| shell_error(shell, "Verify failed"); |
| return -EIO; |
| } |
| |
| addr += pending; |
| } |
| |
| shell_print(shell, "Verify OK"); |
| |
| return 0; |
| } |
| |
| /* Device name autocompletion support */ |
| static void device_name_get(size_t idx, struct shell_static_entry *entry) |
| { |
| const struct device *dev = shell_device_lookup(idx, NULL); |
| |
| entry->syntax = (dev != NULL) ? dev->name : NULL; |
| entry->handler = NULL; |
| entry->help = NULL; |
| entry->subcmd = NULL; |
| } |
| |
| SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get); |
| |
| SHELL_STATIC_SUBCMD_SET_CREATE(eeprom_cmds, |
| SHELL_CMD_ARG(read, &dsub_device_name, |
| "<device> <offset> <length>", cmd_read, 4, 0), |
| SHELL_CMD_ARG(write, &dsub_device_name, |
| "<device> <offset> [byte0] <byte1> .. <byteN>", cmd_write, |
| 4, CONFIG_EEPROM_SHELL_BUFFER_SIZE - 1), |
| SHELL_CMD_ARG(size, &dsub_device_name, "<device>", cmd_size, 2, 0), |
| SHELL_CMD_ARG(fill, &dsub_device_name, |
| "<device> <offset> <length> <pattern>", cmd_fill, 5, 0), |
| SHELL_SUBCMD_SET_END |
| ); |
| |
| SHELL_CMD_REGISTER(eeprom, &eeprom_cmds, "EEPROM shell commands", NULL); |