/* * SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD * * SPDX-License-Identifier: MIT */ /* UnitTest for M5Utility */ #include #include #include namespace { struct CRCType { const char* name; const uint32_t result; const uint32_t poly; const uint32_t init; const bool refIn; const bool refOut; const uint32_t xorout; }; // See also // https://crccalc.com/?crc=0123456789abcdef&method=crc8&datatype=hex&outtype=0 CRCType crc8_table[] = { // name, result, poly, init, refIn, refOut, xorout {"CRC-8", 0x1E, 0x07, 0x00, false, false, 0x00}, {"CRC-8/CDMA2000", 0xF0, 0x9B, 0xFF, false, false, 0x00}, {"CRC-8/DARC", 0x4E, 0x39, 0x00, true, true, 0x00}, {"CRC-8/DVB-S2", 0x7D, 0xD5, 0x00, false, false, 0x00}, {"CRC-8/EBU", 0x17, 0x1D, 0xFF, true, true, 0x00}, {"CRC-8/I-CODE", 0x6C, 0x1D, 0xFD, false, false, 0x00}, {"CRC-8/ITU", 0x4B, 0x07, 0x00, false, false, 0x55}, {"CRC-8/MAXIM", 0xDD, 0x31, 0x00, true, true, 0x00}, {"CRC-8/ROHC", 0xFC, 0x07, 0xFF, true, true, 0x00}, {"CRC-8/WCDMA", 0x22, 0x9B, 0x00, true, true, 0x00}, }; CRCType crc16_table[] = { // name, result, poly, init, refIn, refOut, xorout {"CRC-16/ARC", 0xF3A6, 0x8005, 0x0000, true, true, 0x0000}, {"CRC-16/AUG-CCITT", 0x486C, 0x1021, 0x1D0F, false, false, 0x0000}, {"CRC-16/BUYPASS", 0x2951, 0x8005, 0x0000, false, false, 0x0000}, {"CRC-16/CCITT-FALSE", 0x986B, 0x1021, 0xFFFF, false, false, 0x0000}, {"CRC-16/CDMA2000", 0x593C, 0xC867, 0xFFFF, false, false, 0x0000}, {"CRC-16/DDS-110", 0x27B1, 0x8005, 0x800D, false, false, 0x0000}, {"CRC-16/DECT-R", 0xE83B, 0x0589, 0x0000, false, false, 0x0001}, {"CRC-16/DECT-X", 0xE83A, 0x0589, 0x0000, false, false, 0x0000}, {"CRC-16/DNP", 0xDFCE, 0x3D65, 0x0000, true, true, 0xFFFF}, {"CRC-16/EN-13757", 0x984F, 0x3D65, 0x0000, false, false, 0xFFFF}, {"CRC-16/GENIBUS", 0x6794, 0x1021, 0xFFFF, false, false, 0xFFFF}, {"CRC-16/KERMIT", 0x5A3C, 0x1021, 0x0000, true, true, 0x0000}, {"CRC-16/MAXIM", 0x0C59, 0x8005, 0x0000, true, true, 0xFFFF}, {"CRC-16/MCRF4XX", 0x26B0, 0x1021, 0xFFFF, true, true, 0x0000}, {"CRC-16/MODBUS", 0xF8E6, 0x8005, 0xFFFF, true, true, 0x0000}, {"CRC-16/RIELLO", 0x077C, 0x1021, 0xB2AA, true, true, 0x0000}, // 0x554D {"CRC-16/T10-DIF", 0x4FF0, 0x8BB7, 0x0000, false, false, 0x0000}, {"CRC-16/TELEDISK", 0x3267, 0xA097, 0x0000, false, false, 0x0000}, {"CRC-16/TMS37157", 0x5A4B, 0x1021, 0x89EC, true, true, 0x0000}, // 0x3791 {"CRC-16/USB", 0x0719, 0x8005, 0xFFFF, true, true, 0xFFFF}, {"CRC-16/X-25", 0xD94F, 0x1021, 0xFFFF, true, true, 0xFFFF}, {"CRC-16/XMODEM", 0xA955, 0x1021, 0x0000, false, false, 0x0000}, {"CRC-A", 0x0F06, 0x1021, 0xC6C6, true, true, 0x0000}, // 0x6363 }; const std::vector tdata = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; }; // namespace using namespace m5::utility; TEST(Utility, CRC8) { for (auto&& e : crc8_table) { SCOPED_TRACE(e.name); CRC8 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout); auto v = crc.range(tdata.data(), tdata.size()); auto u = crc.update(tdata.data(), tdata.size()); EXPECT_EQ(v, e.result); EXPECT_EQ(crc.value(), e.result); EXPECT_EQ(u, crc.value()); v = crc.range(tdata.data(), tdata.size()); u = crc.update(tdata.data(), tdata.size()); EXPECT_EQ(v, e.result); EXPECT_NE(v, u); } } TEST(Utility, CRC16) { for (auto&& e : crc16_table) { SCOPED_TRACE(e.name); CRC16 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout); auto v = crc.update(tdata.data(), tdata.size()); EXPECT_EQ(crc.value(), e.result); EXPECT_EQ(v, crc.value()); } } // Test whether calculation from the whole and calculation from split chunks are // equivalent TEST(Utility, Chunk) { constexpr uint8_t d8[32] = {0x04, 0x67, 0xfc, 0x4d, 0xf4, 0xe7, 0x9c, 0x3b, 0x05, 0xb8, 0xad, 0x31, 0x97, 0xb1, 0x21, 0x72, 0x59, 0x5d, 0x80, 0x26, 0x66, 0x0c, 0x12, 0xa9, 0x53, 0xa6, 0x70, 0x87, 0x91, 0x5d, 0xa4, 0x9a}; ; // CRC8 for (auto&& e : crc8_table) { SCOPED_TRACE(e.name); uint8_t crc_all = CRC8::calculate(d8, m5::stl::size(d8), e.init, e.poly, e.refIn, e.refOut, e.xorout); CRC8 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout); uint8_t crc_chunk{}; for (int i = 0; i < 4; ++i) { crc_chunk = crc.update(d8 + (i * 8), 8); // M5_LOGW("%s:i:%d:[%x/%x]", e.name, i, crc_chunk, // crc.range(d8 + (i * 8), 8)); if (i == 0) { EXPECT_EQ(crc_chunk, crc.range(d8 + (i * 8), 8)); } else { EXPECT_NE(crc_chunk, crc.range(d8 + (i * 8), 8)); } } EXPECT_EQ(crc_all, crc_chunk); EXPECT_EQ(crc_all, crc.value()); } // CRC16 for (auto&& e : crc16_table) { SCOPED_TRACE(e.name); uint16_t crc_all = CRC16::calculate(d8, m5::stl::size(d8), e.init, e.poly, e.refIn, e.refOut, e.xorout); CRC16 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout); uint16_t crc_chunk{}; for (int i = 0; i < 4; ++i) { crc_chunk = crc.update(d8 + (i * 8), 8); if (i == 0) { EXPECT_EQ(crc_chunk, crc.range(d8 + (i * 8), 8)); } else { EXPECT_NE(crc_chunk, crc.range(d8 + (i * 8), 8)); } } EXPECT_EQ(crc_all, crc_chunk); EXPECT_EQ(crc_all, crc_chunk); } }