mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
common/omv_crc: Update CRC support.
- Add support for CRC32 with software fallback. - Update polynomials and lookup tables. Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
This commit is contained in:
parent
26aa191ad7
commit
e075aefca4
140
common/omv_crc.c
140
common/omv_crc.c
@ -23,50 +23,83 @@
|
||||
*/
|
||||
#include "omv_crc.h"
|
||||
|
||||
// CRC16 lookup table for polynomial 0xF94F (HD=6, len=135)
|
||||
static const uint16_t crc16_table[256] = {
|
||||
0x0000, 0xBAAD, 0xCFF7, 0x755A, 0x2543, 0x9FEE, 0xEAB4, 0x5019,
|
||||
0x4A86, 0xF02B, 0x8571, 0x3FDC, 0x6FC5, 0xD568, 0xA032, 0x1A9F,
|
||||
0x950C, 0x2FA1, 0x5AFB, 0xE056, 0xB04F, 0x0AE2, 0x7FB8, 0xC515,
|
||||
0xDF8A, 0x6527, 0x107D, 0xAAD0, 0xFAC9, 0x4064, 0x353E, 0x8F93,
|
||||
0x90B5, 0x2A18, 0x5F42, 0xE5EF, 0xB5F6, 0x0F5B, 0x7A01, 0xC0AC,
|
||||
0xDA33, 0x609E, 0x15C4, 0xAF69, 0xFF70, 0x45DD, 0x3087, 0x8A2A,
|
||||
0x05B9, 0xBF14, 0xCA4E, 0x70E3, 0x20FA, 0x9A57, 0xEF0D, 0x55A0,
|
||||
0x4F3F, 0xF592, 0x80C8, 0x3A65, 0x6A7C, 0xD0D1, 0xA58B, 0x1F26,
|
||||
0x9BC7, 0x216A, 0x5430, 0xEE9D, 0xBE84, 0x0429, 0x7173, 0xCBDE,
|
||||
0xD141, 0x6BEC, 0x1EB6, 0xA41B, 0xF402, 0x4EAF, 0x3BF5, 0x8158,
|
||||
0x0ECB, 0xB466, 0xC13C, 0x7B91, 0x2B88, 0x9125, 0xE47F, 0x5ED2,
|
||||
0x444D, 0xFEE0, 0x8BBA, 0x3117, 0x610E, 0xDBA3, 0xAEF9, 0x1454,
|
||||
0x0B72, 0xB1DF, 0xC485, 0x7E28, 0x2E31, 0x949C, 0xE1C6, 0x5B6B,
|
||||
0x41F4, 0xFB59, 0x8E03, 0x34AE, 0x64B7, 0xDE1A, 0xAB40, 0x11ED,
|
||||
0x9E7E, 0x24D3, 0x5189, 0xEB24, 0xBB3D, 0x0190, 0x74CA, 0xCE67,
|
||||
0xD4F8, 0x6E55, 0x1B0F, 0xA1A2, 0xF1BB, 0x4B16, 0x3E4C, 0x84E1,
|
||||
0x8D23, 0x378E, 0x42D4, 0xF879, 0xA860, 0x12CD, 0x6797, 0xDD3A,
|
||||
0xC7A5, 0x7D08, 0x0852, 0xB2FF, 0xE2E6, 0x584B, 0x2D11, 0x97BC,
|
||||
0x182F, 0xA282, 0xD7D8, 0x6D75, 0x3D6C, 0x87C1, 0xF29B, 0x4836,
|
||||
0x52A9, 0xE804, 0x9D5E, 0x27F3, 0x77EA, 0xCD47, 0xB81D, 0x02B0,
|
||||
0x1D96, 0xA73B, 0xD261, 0x68CC, 0x38D5, 0x8278, 0xF722, 0x4D8F,
|
||||
0x5710, 0xEDBD, 0x98E7, 0x224A, 0x7253, 0xC8FE, 0xBDA4, 0x0709,
|
||||
0x889A, 0x3237, 0x476D, 0xFDC0, 0xADD9, 0x1774, 0x622E, 0xD883,
|
||||
0xC21C, 0x78B1, 0x0DEB, 0xB746, 0xE75F, 0x5DF2, 0x28A8, 0x9205,
|
||||
0x16E4, 0xAC49, 0xD913, 0x63BE, 0x33A7, 0x890A, 0xFC50, 0x46FD,
|
||||
0x5C62, 0xE6CF, 0x9395, 0x2938, 0x7921, 0xC38C, 0xB6D6, 0x0C7B,
|
||||
0x83E8, 0x3945, 0x4C1F, 0xF6B2, 0xA6AB, 0x1C06, 0x695C, 0xD3F1,
|
||||
0xC96E, 0x73C3, 0x0699, 0xBC34, 0xEC2D, 0x5680, 0x23DA, 0x9977,
|
||||
0x8651, 0x3CFC, 0x49A6, 0xF30B, 0xA312, 0x19BF, 0x6CE5, 0xD648,
|
||||
0xCCD7, 0x767A, 0x0320, 0xB98D, 0xE994, 0x5339, 0x2663, 0x9CCE,
|
||||
0x135D, 0xA9F0, 0xDCAA, 0x6607, 0x361E, 0x8CB3, 0xF9E9, 0x4344,
|
||||
0x59DB, 0xE376, 0x962C, 0x2C81, 0x7C98, 0xC635, 0xB36F, 0x09C2
|
||||
0x0000, 0xF94F, 0x0BD1, 0xF29E, 0x17A2, 0xEEED, 0x1C73, 0xE53C,
|
||||
0x2F44, 0xD60B, 0x2495, 0xDDDA, 0x38E6, 0xC1A9, 0x3337, 0xCA78,
|
||||
0x5E88, 0xA7C7, 0x5559, 0xAC16, 0x492A, 0xB065, 0x42FB, 0xBBB4,
|
||||
0x71CC, 0x8883, 0x7A1D, 0x8352, 0x666E, 0x9F21, 0x6DBF, 0x94F0,
|
||||
0xBD10, 0x445F, 0xB6C1, 0x4F8E, 0xAAB2, 0x53FD, 0xA163, 0x582C,
|
||||
0x9254, 0x6B1B, 0x9985, 0x60CA, 0x85F6, 0x7CB9, 0x8E27, 0x7768,
|
||||
0xE398, 0x1AD7, 0xE849, 0x1106, 0xF43A, 0x0D75, 0xFFEB, 0x06A4,
|
||||
0xCCDC, 0x3593, 0xC70D, 0x3E42, 0xDB7E, 0x2231, 0xD0AF, 0x29E0,
|
||||
0x836F, 0x7A20, 0x88BE, 0x71F1, 0x94CD, 0x6D82, 0x9F1C, 0x6653,
|
||||
0xAC2B, 0x5564, 0xA7FA, 0x5EB5, 0xBB89, 0x42C6, 0xB058, 0x4917,
|
||||
0xDDE7, 0x24A8, 0xD636, 0x2F79, 0xCA45, 0x330A, 0xC194, 0x38DB,
|
||||
0xF2A3, 0x0BEC, 0xF972, 0x003D, 0xE501, 0x1C4E, 0xEED0, 0x179F,
|
||||
0x3E7F, 0xC730, 0x35AE, 0xCCE1, 0x29DD, 0xD092, 0x220C, 0xDB43,
|
||||
0x113B, 0xE874, 0x1AEA, 0xE3A5, 0x0699, 0xFFD6, 0x0D48, 0xF407,
|
||||
0x60F7, 0x99B8, 0x6B26, 0x9269, 0x7755, 0x8E1A, 0x7C84, 0x85CB,
|
||||
0x4FB3, 0xB6FC, 0x4462, 0xBD2D, 0x5811, 0xA15E, 0x53C0, 0xAA8F,
|
||||
0xFF91, 0x06DE, 0xF440, 0x0D0F, 0xE833, 0x117C, 0xE3E2, 0x1AAD,
|
||||
0xD0D5, 0x299A, 0xDB04, 0x224B, 0xC777, 0x3E38, 0xCCA6, 0x35E9,
|
||||
0xA119, 0x5856, 0xAAC8, 0x5387, 0xB6BB, 0x4FF4, 0xBD6A, 0x4425,
|
||||
0x8E5D, 0x7712, 0x858C, 0x7CC3, 0x99FF, 0x60B0, 0x922E, 0x6B61,
|
||||
0x4281, 0xBBCE, 0x4950, 0xB01F, 0x5523, 0xAC6C, 0x5EF2, 0xA7BD,
|
||||
0x6DC5, 0x948A, 0x6614, 0x9F5B, 0x7A67, 0x8328, 0x71B6, 0x88F9,
|
||||
0x1C09, 0xE546, 0x17D8, 0xEE97, 0x0BAB, 0xF2E4, 0x007A, 0xF935,
|
||||
0x334D, 0xCA02, 0x389C, 0xC1D3, 0x24EF, 0xDDA0, 0x2F3E, 0xD671,
|
||||
0x7CFE, 0x85B1, 0x772F, 0x8E60, 0x6B5C, 0x9213, 0x608D, 0x99C2,
|
||||
0x53BA, 0xAAF5, 0x586B, 0xA124, 0x4418, 0xBD57, 0x4FC9, 0xB686,
|
||||
0x2276, 0xDB39, 0x29A7, 0xD0E8, 0x35D4, 0xCC9B, 0x3E05, 0xC74A,
|
||||
0x0D32, 0xF47D, 0x06E3, 0xFFAC, 0x1A90, 0xE3DF, 0x1141, 0xE80E,
|
||||
0xC1EE, 0x38A1, 0xCA3F, 0x3370, 0xD64C, 0x2F03, 0xDD9D, 0x24D2,
|
||||
0xEEAA, 0x17E5, 0xE57B, 0x1C34, 0xF908, 0x0047, 0xF2D9, 0x0B96,
|
||||
0x9F66, 0x6629, 0x94B7, 0x6DF8, 0x88C4, 0x718B, 0x8315, 0x7A5A,
|
||||
0xB022, 0x496D, 0xBBF3, 0x42BC, 0xA780, 0x5ECF, 0xAC51, 0x551E,
|
||||
};
|
||||
|
||||
__attribute__((weak)) void omv_crc_init(void) {
|
||||
// CRC32 lookup table for polynomial 0xFA567D89
|
||||
const uint32_t crc32_table[256] = {
|
||||
0x00000000, 0xFA567D89, 0x0EFA869B, 0xF4ACFB12, 0x1DF50D36, 0xE7A370BF, 0x130F8BAD, 0xE959F624,
|
||||
0x3BEA1A6C, 0xC1BC67E5, 0x35109CF7, 0xCF46E17E, 0x261F175A, 0xDC496AD3, 0x28E591C1, 0xD2B3EC48,
|
||||
0x77D434D8, 0x8D824951, 0x792EB243, 0x8378CFCA, 0x6A2139EE, 0x90774467, 0x64DBBF75, 0x9E8DC2FC,
|
||||
0x4C3E2EB4, 0xB668533D, 0x42C4A82F, 0xB892D5A6, 0x51CB2382, 0xAB9D5E0B, 0x5F31A519, 0xA567D890,
|
||||
0xEFA869B0, 0x15FE1439, 0xE152EF2B, 0x1B0492A2, 0xF25D6486, 0x080B190F, 0xFCA7E21D, 0x06F19F94,
|
||||
0xD44273DC, 0x2E140E55, 0xDAB8F547, 0x20EE88CE, 0xC9B77EEA, 0x33E10363, 0xC74DF871, 0x3D1B85F8,
|
||||
0x987C5D68, 0x622A20E1, 0x9686DBF3, 0x6CD0A67A, 0x8589505E, 0x7FDF2DD7, 0x8B73D6C5, 0x7125AB4C,
|
||||
0xA3964704, 0x59C03A8D, 0xAD6CC19F, 0x573ABC16, 0xBE634A32, 0x443537BB, 0xB099CCA9, 0x4ACFB120,
|
||||
0x2506AEE9, 0xDF50D360, 0x2BFC2872, 0xD1AA55FB, 0x38F3A3DF, 0xC2A5DE56, 0x36092544, 0xCC5F58CD,
|
||||
0x1EECB485, 0xE4BAC90C, 0x1016321E, 0xEA404F97, 0x0319B9B3, 0xF94FC43A, 0x0DE33F28, 0xF7B542A1,
|
||||
0x52D29A31, 0xA884E7B8, 0x5C281CAA, 0xA67E6123, 0x4F279707, 0xB571EA8E, 0x41DD119C, 0xBB8B6C15,
|
||||
0x6938805D, 0x936EFDD4, 0x67C206C6, 0x9D947B4F, 0x74CD8D6B, 0x8E9BF0E2, 0x7A370BF0, 0x80617679,
|
||||
0xCAAEC759, 0x30F8BAD0, 0xC45441C2, 0x3E023C4B, 0xD75BCA6F, 0x2D0DB7E6, 0xD9A14CF4, 0x23F7317D,
|
||||
0xF144DD35, 0x0B12A0BC, 0xFFBE5BAE, 0x05E82627, 0xECB1D003, 0x16E7AD8A, 0xE24B5698, 0x181D2B11,
|
||||
0xBD7AF381, 0x472C8E08, 0xB380751A, 0x49D60893, 0xA08FFEB7, 0x5AD9833E, 0xAE75782C, 0x542305A5,
|
||||
0x8690E9ED, 0x7CC69464, 0x886A6F76, 0x723C12FF, 0x9B65E4DB, 0x61339952, 0x959F6240, 0x6FC91FC9,
|
||||
0x4A0D5DD2, 0xB05B205B, 0x44F7DB49, 0xBEA1A6C0, 0x57F850E4, 0xADAE2D6D, 0x5902D67F, 0xA354ABF6,
|
||||
0x71E747BE, 0x8BB13A37, 0x7F1DC125, 0x854BBCAC, 0x6C124A88, 0x96443701, 0x62E8CC13, 0x98BEB19A,
|
||||
0x3DD9690A, 0xC78F1483, 0x3323EF91, 0xC9759218, 0x202C643C, 0xDA7A19B5, 0x2ED6E2A7, 0xD4809F2E,
|
||||
0x06337366, 0xFC650EEF, 0x08C9F5FD, 0xF29F8874, 0x1BC67E50, 0xE19003D9, 0x153CF8CB, 0xEF6A8542,
|
||||
0xA5A53462, 0x5FF349EB, 0xAB5FB2F9, 0x5109CF70, 0xB8503954, 0x420644DD, 0xB6AABFCF, 0x4CFCC246,
|
||||
0x9E4F2E0E, 0x64195387, 0x90B5A895, 0x6AE3D51C, 0x83BA2338, 0x79EC5EB1, 0x8D40A5A3, 0x7716D82A,
|
||||
0xD27100BA, 0x28277D33, 0xDC8B8621, 0x26DDFBA8, 0xCF840D8C, 0x35D27005, 0xC17E8B17, 0x3B28F69E,
|
||||
0xE99B1AD6, 0x13CD675F, 0xE7619C4D, 0x1D37E1C4, 0xF46E17E0, 0x0E386A69, 0xFA94917B, 0x00C2ECF2,
|
||||
0x6F0BF33B, 0x955D8EB2, 0x61F175A0, 0x9BA70829, 0x72FEFE0D, 0x88A88384, 0x7C047896, 0x8652051F,
|
||||
0x54E1E957, 0xAEB794DE, 0x5A1B6FCC, 0xA04D1245, 0x4914E461, 0xB34299E8, 0x47EE62FA, 0xBDB81F73,
|
||||
0x18DFC7E3, 0xE289BA6A, 0x16254178, 0xEC733CF1, 0x052ACAD5, 0xFF7CB75C, 0x0BD04C4E, 0xF18631C7,
|
||||
0x2335DD8F, 0xD963A006, 0x2DCF5B14, 0xD799269D, 0x3EC0D0B9, 0xC496AD30, 0x303A5622, 0xCA6C2BAB,
|
||||
0x80A39A8B, 0x7AF5E702, 0x8E591C10, 0x740F6199, 0x9D5697BD, 0x6700EA34, 0x93AC1126, 0x69FA6CAF,
|
||||
0xBB4980E7, 0x411FFD6E, 0xB5B3067C, 0x4FE57BF5, 0xA6BC8DD1, 0x5CEAF058, 0xA8460B4A, 0x521076C3,
|
||||
0xF777AE53, 0x0D21D3DA, 0xF98D28C8, 0x03DB5541, 0xEA82A365, 0x10D4DEEC, 0xE47825FE, 0x1E2E5877,
|
||||
0xCC9DB43F, 0x36CBC9B6, 0xC26732A4, 0x38314F2D, 0xD168B909, 0x2B3EC480, 0xDF923F92, 0x25C4421B,
|
||||
};
|
||||
|
||||
}
|
||||
__attribute__((weak)) uint16_t omv_crc16_start(const void *buf, size_t len) {
|
||||
const uint8_t *data = (const uint8_t *) buf;
|
||||
uint16_t crc = OMV_CRC16_INIT;
|
||||
|
||||
__attribute__((weak)) omv_crc_t omv_crc_start(const void *buf, size_t size) {
|
||||
const uint8_t *data = (const uint8_t *)buf;
|
||||
omv_crc_t crc = OMV_CRC_INIT;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t index = (crc >> 8) ^ data[i];
|
||||
crc = (crc << 8) ^ crc16_table[index];
|
||||
}
|
||||
@ -74,13 +107,36 @@ __attribute__((weak)) omv_crc_t omv_crc_start(const void *buf, size_t size) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
__attribute__((weak)) omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size) {
|
||||
const uint8_t *data = (const uint8_t *)buf;
|
||||
__attribute__((weak)) uint16_t omv_crc16_update(uint16_t crc, const void *buf, size_t len) {
|
||||
const uint8_t *data = (const uint8_t *) buf;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t index = (crc >> 8) ^ data[i];
|
||||
crc = (crc << 8) ^ crc16_table[index];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t omv_crc32_start(const void *buf, size_t len) {
|
||||
const uint8_t *data = (const uint8_t *) buf;
|
||||
uint32_t crc = OMV_CRC32_INIT;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t index = (crc >> 24) ^ data[i];
|
||||
crc = (crc << 8) ^ crc32_table[index];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
__attribute__((weak)) uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len) {
|
||||
const uint8_t *data = (const uint8_t *) buf;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t index = (crc >> 24) ^ data[i];
|
||||
crc = (crc << 8) ^ crc32_table[index];
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
@ -27,37 +27,74 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// 0xBAAD is ironically good - HD=5 up to 108 bits, HD=4 up to 7985 bits
|
||||
#define OMV_CRC_POLY (0xBAAD)
|
||||
#define OMV_CRC_INIT (0xFFFF)
|
||||
#define OMV_CRC_SIZE (16)
|
||||
typedef uint16_t omv_crc_t;
|
||||
// CRC size enumeration
|
||||
typedef enum {
|
||||
OMV_CRC16 = 16,
|
||||
OMV_CRC32 = 32
|
||||
} omv_crc_size_t;
|
||||
|
||||
// Initialize CRC hardware (if available)
|
||||
void omv_crc_init(void);
|
||||
// HD=6 up to 114 bits
|
||||
#define OMV_CRC16_POLY (0xF94F)
|
||||
#define OMV_CRC16_INIT (0xFFFF)
|
||||
|
||||
// Start CRC calculation for buffer data
|
||||
omv_crc_t omv_crc_start(const void *buf, size_t size);
|
||||
// HD=6 up to 32738 bits (~4K)
|
||||
#define OMV_CRC32_POLY (0xFA567D89)
|
||||
#define OMV_CRC32_INIT (0xFFFFFFFF)
|
||||
|
||||
// Update CRC with additional buffer data
|
||||
omv_crc_t omv_crc_update(omv_crc_t crc, const void *buf, size_t size);
|
||||
// Default software implementations
|
||||
uint16_t omv_crc16_start(const void *buf, size_t len);
|
||||
uint16_t omv_crc16_update(uint16_t crc, const void *buf, size_t len);
|
||||
|
||||
// Read CRC value from the last 2 bytes of buffer
|
||||
static inline omv_crc_t omv_crc_read(const void *buf, size_t size) {
|
||||
const uint8_t *crc_buf = (const uint8_t *)buf + size - 2;
|
||||
return *((omv_crc_t*) crc_buf);
|
||||
uint32_t omv_crc32_start(const void *buf, size_t len);
|
||||
uint32_t omv_crc32_update(uint32_t crc, const void *buf, size_t len);
|
||||
|
||||
// Public API functions
|
||||
static inline uint32_t omv_crc_start(omv_crc_size_t size, const void *buf, size_t len) {
|
||||
if (size == OMV_CRC16) {
|
||||
return omv_crc16_start(buf, len);
|
||||
} else if (size == OMV_CRC32) {
|
||||
return omv_crc32_start(buf, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Calculate CRC and write it to the last 2 bytes of buffer
|
||||
static inline void omv_crc_write(void *buf, size_t size) {
|
||||
omv_crc_t crc = omv_crc_start(buf, size - 2);
|
||||
uint8_t *crc_buf = (uint8_t *)buf + size - 2;
|
||||
static inline uint32_t omv_crc_update(omv_crc_size_t size, uint32_t crc, const void *buf, size_t len) {
|
||||
if (size == OMV_CRC16) {
|
||||
return omv_crc16_update((uint16_t) crc, buf, len);
|
||||
} else if (size == OMV_CRC32) {
|
||||
return omv_crc32_update(crc, buf, len);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Read CRC value from the last bytes of buffer
|
||||
static inline uint32_t omv_crc_read(omv_crc_size_t crc_size, const void *buf, size_t size) {
|
||||
const uint8_t *crc_buf = (const uint8_t *) buf + size - (crc_size == OMV_CRC16 ? 2 : 4);
|
||||
if (crc_size == OMV_CRC16) {
|
||||
return *((uint16_t *) crc_buf);
|
||||
} else {
|
||||
return *((uint32_t *) crc_buf);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate CRC and write it to the last bytes of buffer
|
||||
static inline void omv_crc_write(omv_crc_size_t crc_size, void *buf, size_t size) {
|
||||
uint32_t crc = omv_crc_start(crc_size, buf, size - (crc_size == OMV_CRC16 ? 2 : 4));
|
||||
uint8_t *crc_buf = (uint8_t *) buf + size - (crc_size == OMV_CRC16 ? 2 : 4);
|
||||
|
||||
if (crc_size == OMV_CRC16) {
|
||||
crc_buf[0] = crc & 0xFF;
|
||||
crc_buf[1] = (crc >> 8) & 0xFF;
|
||||
} else {
|
||||
crc_buf[0] = crc & 0xFF;
|
||||
crc_buf[1] = (crc >> 8) & 0xFF;
|
||||
crc_buf[2] = (crc >> 16) & 0xFF;
|
||||
crc_buf[3] = (crc >> 24) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate and check if CRC matches the one stored in buffer
|
||||
static inline bool omv_crc_check(const void *buf, size_t size) {
|
||||
return omv_crc_read(buf, size) == omv_crc_start(buf, size - 2);
|
||||
static inline bool omv_crc_check(omv_crc_size_t crc_size, const void *buf, size_t size) {
|
||||
return omv_crc_read(crc_size, buf, size) == omv_crc_start(crc_size, buf, size - (crc_size == OMV_CRC16 ? 2 : 4));
|
||||
}
|
||||
#endif // __OMV_CRC_H__
|
||||
|
Loading…
Reference in New Issue
Block a user