|  | /* | 
|  | * Copyright (c) 2022 Meta | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <errno.h> | 
|  | #include <stdbool.h> | 
|  | #include <stdint.h> | 
|  | #include <stdlib.h> | 
|  | #ifdef CONFIG_ARCH_POSIX | 
|  | #include <unistd.h> | 
|  | #else | 
|  | #include <zephyr/posix/unistd.h> | 
|  | #endif | 
|  |  | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/shell/shell.h> | 
|  | #include <zephyr/sys/crc.h> | 
|  |  | 
|  | static const char *const crc_types[] = { | 
|  | [CRC7_BE] = "7_be", | 
|  | [CRC8] = "8", | 
|  | [CRC8_CCITT] "8_ccitt", | 
|  | [CRC16] = "16", | 
|  | [CRC16_ANSI] = "16_ansi", | 
|  | [CRC16_CCITT] = "16_ccitt", | 
|  | [CRC16_ITU_T] = "16_itu_t", | 
|  | [CRC32_C] = "32_c", | 
|  | [CRC32_IEEE] = "32_ieee", | 
|  | }; | 
|  |  | 
|  | static int string_to_crc_type(const char *s) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(crc_types); ++i) { | 
|  | if (strcmp(s, crc_types[i]) == 0) { | 
|  | return i; | 
|  | } | 
|  | } | 
|  |  | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | static void usage(const struct shell *sh) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | shell_print(sh, "crc [options..] <address> <size>"); | 
|  | shell_print(sh, "options:"); | 
|  | shell_print(sh, "-f         This is the first packet"); | 
|  | shell_print(sh, "-l         This is the last packet"); | 
|  | shell_print(sh, "-p <poly>  Use polynomial 'poly'"); | 
|  | shell_print(sh, "-r         Reflect"); | 
|  | shell_print(sh, "-s <seed>  Use 'seed' as the initial value"); | 
|  | shell_print(sh, "-t <type>  Compute the CRC described by 'type'"); | 
|  | shell_print(sh, "Note: some options are only useful for certain CRCs"); | 
|  | shell_print(sh, "CRC Types:"); | 
|  | for (i = 0; i < ARRAY_SIZE(crc_types); ++i) { | 
|  | shell_print(sh, "%s", crc_types[i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | static int cmd_crc(const struct shell *sh, size_t argc, char **argv) | 
|  | { | 
|  | int rv; | 
|  | size_t size = -1; | 
|  | bool last = false; | 
|  | uint32_t poly = 0; | 
|  | bool first = false; | 
|  | uint32_t seed = 0; | 
|  | bool reflect = false; | 
|  | void *addr = (void *)-1; | 
|  | enum crc_type type = CRC32_IEEE; | 
|  |  | 
|  | optind = 1; | 
|  |  | 
|  | while ((rv = getopt(argc, argv, "fhlp:rs:t:")) != -1) { | 
|  | switch (rv) { | 
|  | case 'f': | 
|  | first = true; | 
|  | break; | 
|  | case 'h': | 
|  | usage(sh); | 
|  | return 0; | 
|  | case 'l': | 
|  | last = true; | 
|  | break; | 
|  | case 'p': | 
|  | poly = (size_t)strtoul(optarg, NULL, 16); | 
|  | if (poly == 0 && errno == EINVAL) { | 
|  | shell_error(sh, "invalid seed '%s'", optarg); | 
|  | return -EINVAL; | 
|  | } | 
|  | break; | 
|  | case 'r': | 
|  | reflect = true; | 
|  | break; | 
|  | case 's': | 
|  | seed = (size_t)strtoul(optarg, NULL, 16); | 
|  | if (seed == 0 && errno == EINVAL) { | 
|  | shell_error(sh, "invalid seed '%s'", optarg); | 
|  | return -EINVAL; | 
|  | } | 
|  | break; | 
|  | case 't': | 
|  | type = string_to_crc_type(optarg); | 
|  | if (type == -1) { | 
|  | shell_error(sh, "invalid type '%s'", optarg); | 
|  | return -EINVAL; | 
|  | } | 
|  | break; | 
|  | case '?': | 
|  | default: | 
|  | usage(sh); | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (optind + 2 > argc) { | 
|  | shell_error(sh, "'address' and 'size' arguments are mandatory"); | 
|  | usage(sh); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | addr = (void *)strtoul(argv[optind], NULL, 16); | 
|  | if (addr == 0 && errno == EINVAL) { | 
|  | shell_error(sh, "invalid address '%s'", argv[optind]); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | size = (size_t)strtoul(argv[optind + 1], NULL, 0); | 
|  | if (size == 0 && errno == EINVAL) { | 
|  | shell_error(sh, "invalid size '%s'", argv[optind + 1]); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | shell_print(sh, "0x%x", crc_by_type(type, addr, size, seed, poly, reflect, first, last)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | SHELL_CMD_ARG_REGISTER(crc, NULL, NULL, cmd_crc, 0, 12); |