1use super::bch::EcLevel;
8
9#[derive(Debug, Clone, Copy)]
15pub struct EcBlockInfo {
16 pub ec_per_block: u16,
17 pub group1: (u16, u16),
18 pub group2: Option<(u16, u16)>,
19}
20
21impl EcBlockInfo {
22 pub fn total_data_codewords(&self) -> u16 {
24 let g1 = self.group1.0 * self.group1.1;
25 let g2 = self.group2.map(|(n, d)| n * d).unwrap_or(0);
26 g1 + g2
27 }
28
29 pub fn total_blocks(&self) -> u16 {
31 self.group1.0 + self.group2.map(|(n, _)| n).unwrap_or(0)
32 }
33
34 pub fn total_ec_codewords(&self) -> u16 {
36 self.total_blocks() * self.ec_per_block
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
44pub struct Version(
45 pub u8,
47);
48
49impl Version {
50 pub fn new(v: u8) -> Self {
52 assert!((1..=40).contains(&v));
53 Self(v)
54 }
55 pub fn size(self) -> usize {
57 17 + 4 * self.0 as usize
58 }
59}
60
61#[allow(dead_code)]
63pub const TOTAL_CODEWORDS: [u16; 40] = [
64 26, 44, 70, 100, 134, 172, 196, 242, 292, 346, 404, 466, 532, 581, 655, 733, 815, 901, 991,
65 1085, 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185, 2323, 2465, 2611, 2761, 2876,
66 3034, 3196, 3362, 3532, 3706,
67];
68
69#[rustfmt::skip]
71const EC_BLOCKS: [[EcBlockInfo; 4]; 40] = [
72 [ b1(7,1,19), b1(10,1,16), b1(13,1,13), b1(17,1,9) ],
74 [ b1(10,1,34), b1(16,1,28), b1(22,1,22), b1(28,1,16) ],
76 [ b1(15,1,55), b1(26,1,44), b1(18,2,17), b1(22,2,13) ],
78 [ b1(20,1,80), b1(18,2,32), b1(26,2,24), b1(16,4,9) ],
80 [ b1(26,1,108), b1(24,2,43), b2(18,2,15,2,16), b2(22,2,11,2,12) ],
82 [ b1(18,2,68), b1(16,4,27), b1(24,4,19), b1(28,4,15) ],
84 [ b1(20,2,78), b1(18,4,31), b2(18,2,14,4,15), b2(26,4,13,1,14) ],
86 [ b1(24,2,97), b2(22,2,38,2,39), b2(22,4,18,2,19), b2(26,4,14,2,15) ],
88 [ b1(30,2,116), b2(22,3,36,2,37), b2(20,4,16,4,17), b2(24,4,12,4,13) ],
90 [ b2(18,2,68,2,69), b2(26,4,43,1,44), b2(24,6,19,2,20), b2(28,6,15,2,16) ],
92 [ b1(20,4,81), b2(30,1,50,4,51), b2(28,4,22,4,23), b2(24,3,12,8,13) ],
94 [ b2(24,2,92,2,93), b2(22,6,36,2,37), b2(26,4,20,6,21), b2(28,7,14,4,15) ],
96 [ b1(26,4,107), b2(22,8,37,1,38), b2(24,8,20,4,21), b2(22,12,11,4,12) ],
98 [ b2(30,3,115,1,116), b2(24,4,40,5,41), b2(20,11,16,5,17), b2(24,11,12,5,13) ],
100 [ b2(22,5,87,1,88), b2(24,5,41,5,42), b2(30,5,24,7,25), b2(24,11,12,7,13) ],
102 [ b2(24,5,98,1,99), b2(28,7,45,3,46), b2(24,15,19,2,20), b2(30,3,15,13,16) ],
104 [ b2(28,1,107,5,108), b2(28,10,46,1,47), b2(28,1,22,15,23), b2(28,2,14,17,15) ],
106 [ b2(30,5,120,1,121), b2(26,9,43,4,44), b2(28,17,22,1,23), b2(28,2,14,19,15) ],
108 [ b2(28,3,113,4,114), b2(26,3,44,11,45), b2(26,17,21,4,22), b2(26,9,13,16,14) ],
110 [ b2(28,3,107,5,108), b2(26,3,41,13,42), b2(30,15,24,5,25), b2(28,15,15,10,16) ],
112 [ b2(28,4,116,4,117), b1(26,17,42), b2(28,17,22,6,23), b2(30,19,16,6,17) ],
114 [ b2(28,2,111,7,112), b1(28,17,46), b2(30,7,24,16,25), b1(24,34,13) ],
116 [ b2(30,4,121,5,122), b2(28,4,47,14,48), b2(30,11,24,14,25), b2(30,16,15,14,16) ],
118 [ b2(30,6,117,4,118), b2(28,6,45,14,46), b2(30,11,24,16,25), b2(30,30,16,2,17) ],
120 [ b2(26,8,106,4,107), b2(28,8,47,13,48), b2(30,7,24,22,25), b2(30,22,15,13,16) ],
122 [ b2(28,10,114,2,115), b2(28,19,46,4,47), b2(28,28,22,6,23), b2(30,33,16,4,17) ],
124 [ b2(30,8,122,4,123), b2(28,22,45,3,46), b2(30,8,23,26,24), b2(30,12,15,28,16) ],
126 [ b2(30,3,117,10,118), b2(28,3,45,23,46), b2(30,4,24,31,25), b2(30,11,15,31,16) ],
128 [ b2(30,7,116,7,117), b2(28,21,45,7,46), b2(30,1,23,37,24), b2(30,19,15,26,16) ],
130 [ b2(30,5,115,10,116), b2(28,19,47,10,48), b2(30,15,24,25,25), b2(30,23,15,25,16) ],
132 [ b2(30,13,115,3,116), b2(28,2,46,29,47), b2(30,42,24,1,25), b2(30,23,15,28,16) ],
134 [ b1(30,17,115), b2(28,10,46,23,47), b2(30,10,24,35,25), b2(30,19,15,35,16) ],
136 [ b2(30,17,115,1,116), b2(28,14,46,21,47), b2(30,29,24,19,25), b2(30,11,15,46,16) ],
138 [ b2(30,13,115,6,116), b2(28,14,46,23,47), b2(30,44,24,7,25), b2(30,59,16,1,17) ],
140 [ b2(30,12,121,7,122), b2(28,12,47,26,48), b2(30,39,24,14,25), b2(30,22,15,41,16) ],
142 [ b2(30,6,121,14,122), b2(28,6,47,34,48), b2(30,46,24,10,25), b2(30,2,15,64,16) ],
144 [ b2(30,17,122,4,123), b2(28,29,46,14,47), b2(30,49,24,10,25), b2(30,24,15,46,16) ],
146 [ b2(30,4,122,18,123), b2(28,13,46,32,47), b2(30,48,24,14,25), b2(30,42,15,32,16) ],
148 [ b2(30,20,117,4,118), b2(28,40,47,7,48), b2(30,43,24,22,25), b2(30,10,15,67,16) ],
150 [ b2(30,19,118,6,119), b2(28,18,47,31,48), b2(30,34,24,34,25), b2(30,20,15,61,16) ],
152];
153
154const fn b1(ec: u16, n: u16, d: u16) -> EcBlockInfo {
155 EcBlockInfo {
156 ec_per_block: ec,
157 group1: (n, d),
158 group2: None,
159 }
160}
161const fn b2(ec: u16, n1: u16, d1: u16, n2: u16, d2: u16) -> EcBlockInfo {
162 EcBlockInfo {
163 ec_per_block: ec,
164 group1: (n1, d1),
165 group2: Some((n2, d2)),
166 }
167}
168
169pub fn ec_blocks(version: Version, level: EcLevel) -> EcBlockInfo {
171 let idx = level_index(level);
172 EC_BLOCKS[version.0 as usize - 1][idx]
173}
174
175fn level_index(level: EcLevel) -> usize {
176 match level {
177 EcLevel::L => 0,
178 EcLevel::M => 1,
179 EcLevel::Q => 2,
180 EcLevel::H => 3,
181 }
182}
183
184pub fn alignment_centers(version: Version) -> &'static [u8] {
188 ALIGNMENT_CENTERS[version.0 as usize - 1]
189}
190
191const ALIGNMENT_CENTERS: [&[u8]; 40] = [
192 &[],
193 &[6, 18],
194 &[6, 22],
195 &[6, 26],
196 &[6, 30],
197 &[6, 34],
198 &[6, 22, 38],
199 &[6, 24, 42],
200 &[6, 26, 46],
201 &[6, 28, 50],
202 &[6, 30, 54],
203 &[6, 32, 58],
204 &[6, 34, 62],
205 &[6, 26, 46, 66],
206 &[6, 26, 48, 70],
207 &[6, 26, 50, 74],
208 &[6, 30, 54, 78],
209 &[6, 30, 56, 82],
210 &[6, 30, 58, 86],
211 &[6, 34, 62, 90],
212 &[6, 28, 50, 72, 94],
213 &[6, 26, 50, 74, 98],
214 &[6, 30, 54, 78, 102],
215 &[6, 28, 54, 80, 106],
216 &[6, 32, 58, 84, 110],
217 &[6, 30, 58, 86, 114],
218 &[6, 34, 62, 90, 118],
219 &[6, 26, 50, 74, 98, 122],
220 &[6, 30, 54, 78, 102, 126],
221 &[6, 26, 52, 78, 104, 130],
222 &[6, 30, 56, 82, 108, 134],
223 &[6, 34, 60, 86, 112, 138],
224 &[6, 30, 58, 86, 114, 142],
225 &[6, 34, 62, 90, 118, 146],
226 &[6, 30, 54, 78, 102, 126, 150],
227 &[6, 24, 50, 76, 102, 128, 154],
228 &[6, 28, 54, 80, 106, 132, 158],
229 &[6, 32, 58, 84, 110, 136, 162],
230 &[6, 26, 54, 82, 110, 138, 166],
231 &[6, 30, 58, 86, 114, 142, 170],
232];
233
234pub fn byte_mode_count_bits(version: Version) -> usize {
237 if version.0 <= 9 {
238 8
239 } else {
240 16
241 }
242}
243
244pub fn byte_mode_max_capacity(version: Version, level: EcLevel) -> usize {
250 let total_data_bits = ec_blocks(version, level).total_data_codewords() as usize * 8;
251 let overhead = 4 + byte_mode_count_bits(version);
252 (total_data_bits - overhead) / 8
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258
259 #[test]
261 fn ec_blocks_match_total_codewords() {
262 for v in 1..=40u8 {
263 let version = Version::new(v);
264 let expected = TOTAL_CODEWORDS[v as usize - 1];
265 for level in [EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H] {
266 let info = ec_blocks(version, level);
267 let actual = info.total_data_codewords() + info.total_ec_codewords();
268 assert_eq!(
269 actual, expected,
270 "v{} {:?}: data={} + ec={} != total={}",
271 v,
272 level,
273 info.total_data_codewords(),
274 info.total_ec_codewords(),
275 expected
276 );
277 }
278 }
279 }
280
281 #[test]
283 fn version_sizes() {
284 assert_eq!(Version::new(1).size(), 21);
285 assert_eq!(Version::new(2).size(), 25);
286 assert_eq!(Version::new(7).size(), 45);
287 assert_eq!(Version::new(40).size(), 177);
288 }
289
290 #[test]
292 fn alignment_centers_count() {
293 for v in 1..=40u8 {
294 let n = alignment_centers(Version::new(v)).len();
295 let expected = match v {
296 1 => 0,
297 2..=6 => 2,
298 7..=13 => 3,
299 14..=20 => 4,
300 21..=27 => 5,
301 28..=34 => 6,
302 35..=40 => 7,
303 _ => unreachable!(),
304 };
305 assert_eq!(n, expected, "v{}: alignment count", v);
306 }
307 }
308
309 #[test]
310 fn byte_capacity_v1_l() {
311 assert_eq!(byte_mode_max_capacity(Version::new(1), EcLevel::L), 17);
313 }
314
315 #[test]
316 fn byte_capacity_v10_h() {
317 assert_eq!(byte_mode_max_capacity(Version::new(10), EcLevel::H), 119);
319 }
320}