1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdint.h>
9 #include <stddef.h>
10
11 /**
12 * Bitwise reverse 1 byte,
13 * Based on code in the public domain as claimed by the author in this page:
14 * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits
15 */
rev_byte(uint8_t input)16 static uint8_t rev_byte(uint8_t input){
17 return ((input * 0x80200802ULL) & 0x0884422110ULL)
18 * 0x0101010101ULL >> 32;
19 }
20
21 /**
22 * Reverse the bits order in a 24 bit word
23 */
rev_24(uint32_t input)24 static uint32_t rev_24(uint32_t input){
25 uint32_t ret;
26 ret = rev_byte((input >> 0) & 0xff) << 16
27 | rev_byte((input >> 8) & 0xff) << 8
28 | rev_byte((input >> 16) & 0xff);
29 return ret;
30 }
31
32 /**
33 * Reverse the bits order in a 16 bit word
34 */
rev_16(uint16_t input)35 static uint32_t rev_16(uint16_t input){
36 uint16_t ret;
37 ret = rev_byte((input >> 0) & 0xff) << 8
38 | rev_byte((input >> 8) & 0xff) << 0;
39 return ret;
40 }
41
42 /*
43 Table implementation of the CRCs autogenerated with these scripts (with very minor modifications)
44 https://pycrc.org (These python scripts are MIT licensed)
45 Options="--std=C99 --width=24 --poly=0x100065B --algorithm=table-driven --xor-out=0x0 --xor-in=0x555555 --reflect-in=true --reflect-out=true --crc-type=uint32_t"
46 python pycrc.py $Options --generate=h > pycrc_stdout.h
47 python pycrc.py $Options --generate=c-main > pycrc_stdout.c
48 gcc pycrc_stdout.c -o testexe && ./testexe -s "@"
49 */
50 static const uint32_t crc_table_24_ble[256] = {
51 0x000000, 0x01b4c0, 0x036980, 0x02dd40, 0x06d300, 0x0767c0, 0x05ba80, 0x040e40,
52 0x0da600, 0x0c12c0, 0x0ecf80, 0x0f7b40, 0x0b7500, 0x0ac1c0, 0x081c80, 0x09a840,
53 0x1b4c00, 0x1af8c0, 0x182580, 0x199140, 0x1d9f00, 0x1c2bc0, 0x1ef680, 0x1f4240,
54 0x16ea00, 0x175ec0, 0x158380, 0x143740, 0x103900, 0x118dc0, 0x135080, 0x12e440,
55 0x369800, 0x372cc0, 0x35f180, 0x344540, 0x304b00, 0x31ffc0, 0x332280, 0x329640,
56 0x3b3e00, 0x3a8ac0, 0x385780, 0x39e340, 0x3ded00, 0x3c59c0, 0x3e8480, 0x3f3040,
57 0x2dd400, 0x2c60c0, 0x2ebd80, 0x2f0940, 0x2b0700, 0x2ab3c0, 0x286e80, 0x29da40,
58 0x207200, 0x21c6c0, 0x231b80, 0x22af40, 0x26a100, 0x2715c0, 0x25c880, 0x247c40,
59 0x6d3000, 0x6c84c0, 0x6e5980, 0x6fed40, 0x6be300, 0x6a57c0, 0x688a80, 0x693e40,
60 0x609600, 0x6122c0, 0x63ff80, 0x624b40, 0x664500, 0x67f1c0, 0x652c80, 0x649840,
61 0x767c00, 0x77c8c0, 0x751580, 0x74a140, 0x70af00, 0x711bc0, 0x73c680, 0x727240,
62 0x7bda00, 0x7a6ec0, 0x78b380, 0x790740, 0x7d0900, 0x7cbdc0, 0x7e6080, 0x7fd440,
63 0x5ba800, 0x5a1cc0, 0x58c180, 0x597540, 0x5d7b00, 0x5ccfc0, 0x5e1280, 0x5fa640,
64 0x560e00, 0x57bac0, 0x556780, 0x54d340, 0x50dd00, 0x5169c0, 0x53b480, 0x520040,
65 0x40e400, 0x4150c0, 0x438d80, 0x423940, 0x463700, 0x4783c0, 0x455e80, 0x44ea40,
66 0x4d4200, 0x4cf6c0, 0x4e2b80, 0x4f9f40, 0x4b9100, 0x4a25c0, 0x48f880, 0x494c40,
67 0xda6000, 0xdbd4c0, 0xd90980, 0xd8bd40, 0xdcb300, 0xdd07c0, 0xdfda80, 0xde6e40,
68 0xd7c600, 0xd672c0, 0xd4af80, 0xd51b40, 0xd11500, 0xd0a1c0, 0xd27c80, 0xd3c840,
69 0xc12c00, 0xc098c0, 0xc24580, 0xc3f140, 0xc7ff00, 0xc64bc0, 0xc49680, 0xc52240,
70 0xcc8a00, 0xcd3ec0, 0xcfe380, 0xce5740, 0xca5900, 0xcbedc0, 0xc93080, 0xc88440,
71 0xecf800, 0xed4cc0, 0xef9180, 0xee2540, 0xea2b00, 0xeb9fc0, 0xe94280, 0xe8f640,
72 0xe15e00, 0xe0eac0, 0xe23780, 0xe38340, 0xe78d00, 0xe639c0, 0xe4e480, 0xe55040,
73 0xf7b400, 0xf600c0, 0xf4dd80, 0xf56940, 0xf16700, 0xf0d3c0, 0xf20e80, 0xf3ba40,
74 0xfa1200, 0xfba6c0, 0xf97b80, 0xf8cf40, 0xfcc100, 0xfd75c0, 0xffa880, 0xfe1c40,
75 0xb75000, 0xb6e4c0, 0xb43980, 0xb58d40, 0xb18300, 0xb037c0, 0xb2ea80, 0xb35e40,
76 0xbaf600, 0xbb42c0, 0xb99f80, 0xb82b40, 0xbc2500, 0xbd91c0, 0xbf4c80, 0xbef840,
77 0xac1c00, 0xada8c0, 0xaf7580, 0xaec140, 0xaacf00, 0xab7bc0, 0xa9a680, 0xa81240,
78 0xa1ba00, 0xa00ec0, 0xa2d380, 0xa36740, 0xa76900, 0xa6ddc0, 0xa40080, 0xa5b440,
79 0x81c800, 0x807cc0, 0x82a180, 0x831540, 0x871b00, 0x86afc0, 0x847280, 0x85c640,
80 0x8c6e00, 0x8ddac0, 0x8f0780, 0x8eb340, 0x8abd00, 0x8b09c0, 0x89d480, 0x886040,
81 0x9a8400, 0x9b30c0, 0x99ed80, 0x985940, 0x9c5700, 0x9de3c0, 0x9f3e80, 0x9e8a40,
82 0x972200, 0x9696c0, 0x944b80, 0x95ff40, 0x91f100, 0x9045c0, 0x929880, 0x932c40
83 };
84
crc_update_ble(uint32_t crc,const void * data,size_t data_len)85 static uint32_t crc_update_ble(uint32_t crc, const void *data, size_t data_len)
86 {
87 const unsigned char *d = (const unsigned char *)data;
88 unsigned int tbl_idx;
89
90 while (data_len--) {
91 tbl_idx = (crc ^ *d) & 0xff;
92 crc = (crc_table_24_ble[tbl_idx] ^ (crc >> 8)) & 0xffffff;
93
94 d++;
95 }
96 return crc & 0xffffff;
97 }
98
99
100 /**
101 * Append the BLE CRC to a buffer buf of len bytes at the end of the buffer
102 * itself
103 */
append_crc_ble(uint8_t * buf,unsigned int len,uint32_t crc_init)104 void append_crc_ble(uint8_t* buf, unsigned int len, uint32_t crc_init)
105 {
106 uint32_t crc;
107 crc = crc_update_ble( rev_24(crc_init), buf, len );
108
109 /*Copy CRC itself at the end of the input buffer*/
110 for (int i = 0; i < 3; i++) {
111 buf[len + i] = (crc >> (i*8)) & 0xff;
112 }
113 return;
114 }
115
116
117 /*
118 Table implementation of the CRCs autogenerated with these scripts (with very minor changes)
119 https://pycrc.org (These python scripts are MIT licensed)
120 mkdir pycrc && cd pycrc
121 git clone git@github.com:tpircher/pycrc.git .
122
123 Options="--std=C99 --width=16 --poly=0x1021 --algorithm=table-driven --reflect-in=true --reflect-out=true --crc-type=uint16_t"
124 python3 src/pycrc.py $Options --generate=h > pycrc_stdout.h
125 python3 src/pycrc.py $Options --generate=c-main > pycrc_stdout.c
126 */
127 static const uint16_t crc_table_154[256] = {
128 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
129 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
130 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
131 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
132 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
133 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
134 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
135 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
136 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
137 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
138 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
139 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
140 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
141 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
142 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
143 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
144 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
145 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
146 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
147 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
148 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
149 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
150 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
151 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
152 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
153 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
154 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
155 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
156 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
157 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
158 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
159 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
160 };
161
crc_update_154(uint16_t crc,const void * data,size_t data_len)162 uint16_t crc_update_154(uint16_t crc, const void *data, size_t data_len)
163 {
164 const unsigned char *d = (const unsigned char *)data;
165 unsigned int tbl_idx;
166
167 while (data_len--) {
168 tbl_idx = (crc ^ *d) & 0xff;
169 crc = (crc_table_154[tbl_idx] ^ (crc >> 8)) & 0xffff;
170 d++;
171 }
172 return crc & 0xffff;
173 }
174
175 /**
176 * Append the 154 CRC to a buffer buf of len bytes at the end of the buffer
177 * itself
178 */
append_crc_154(uint8_t * buf,unsigned int len,uint16_t crc_init)179 void append_crc_154(uint8_t* buf, unsigned int len, uint16_t crc_init)
180 {
181 uint16_t crc;
182 crc = crc_update_154( rev_16(crc_init), buf, len );
183
184 /*Copy CRC itself at the end of the input buffer*/
185 for (int i = 0; i < 2; i++) {
186 buf[len + i] = (crc >> (i*8)) & 0xff;
187 }
188 return;
189 }
190
191 #if defined(__TEST_CRC_154)
192 //Quick unit test of the 154 CRC
193 // gcc -D__TEST_CRC_154 crc.c -o crc_154test && ./crc_154test
194 #include <string.h>
195 #include <stdlib.h>
196 #include <stdio.h>
197
198 //An acknowledgment frame with no payload and the following 3 byte MHR (spec example)
199 // 0100 0000 0000 0000 0101 0110 (b0..b23)
200 uint8_t test_data[] = {0x2, 0x0, 0x6A};
201 //Expected CRC: 0010 0111 1001 1110 r0..r15
202 uint8_t test_crc[] = {0xE4, 0x79};
203
main()204 int main(){
205 uint8_t buffer[10] = {0};
206 memcpy(buffer, test_data, 3);
207
208 append_crc_154(buffer, 3, 0x0);
209 for (int i=0 ; i < 5; i++){
210 printf("0x%02X ", buffer[i]);
211 }
212 printf("\n");
213
214 if ((buffer[3] == test_crc[0]) && (buffer[4] == test_crc[1])){
215 printf("CRC was correct -> PASSED\n");
216 return 0;
217 } else {
218 printf("CRC NOT was correct -> FAILED \n");
219 return 1;
220 }
221 }
222 #endif //defined(__TEST_CRC_154)
223