145 lines
3.1 KiB
C
145 lines
3.1 KiB
C
/*
|
|
* 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);
|