blob: 3d08a59aa17bfc8e6337c124994feb2140cb877c [file] [log] [blame]
/*
* 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[] = {
[CRC4] = "4",
[CRC4_TI] = "4_ti",
[CRC7_BE] = "7_be",
[CRC8] = "8",
[CRC8_CCITT] = "8_ccitt",
[CRC8_ROHC] = "8_rohc",
[CRC16] = "16",
[CRC16_ANSI] = "16_ansi",
[CRC16_CCITT] = "16_ccitt",
[CRC16_ITU_T] = "16_itu_t",
[CRC24_PGP] = "24_pgp",
[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);