|
|
@@ -0,0 +1,81 @@
|
|
|
+package com.grkj.data.hardware.can
|
|
|
+
|
|
|
+/**
|
|
|
+ * NodeId 计算器:
|
|
|
+ * 以“置位个数递增 + 位索引字典序”的顺序枚举 8 位拨码的所有组合。
|
|
|
+ * 例如:
|
|
|
+ * k=1: 00000001, 00000010, ..., 10000000
|
|
|
+ * k=2: 00000011, 00000101, ..., 10000001, 00000110, ..., 11000000
|
|
|
+ * ...
|
|
|
+ * k=8: 11111111
|
|
|
+ */
|
|
|
+object NodeIdHelper {
|
|
|
+
|
|
|
+ /** 总位数(1..8 对应 bit0..bit7) */
|
|
|
+ private const val MAX_BITS = 8
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 枚举所有非零掩码,按置位个数递增(1..8),
|
|
|
+ * 同一置位个数内按“位索引组合字典序”输出。
|
|
|
+ *
|
|
|
+ * @param emit 对每个掩码调用一次(0x01..0xFF),顺序如上。
|
|
|
+ */
|
|
|
+ suspend fun scanRange(emit: suspend (Int) -> Unit) {
|
|
|
+ // 置位个数 k:1..8
|
|
|
+ for (k in 1..MAX_BITS) {
|
|
|
+ generateKBitMasks(k, MAX_BITS, emit)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成固定置位个数 k 的所有掩码(组合字典序)。
|
|
|
+ * 例如 k=2, n=8:
|
|
|
+ * 索引组合 (0,1) → 00000011, (0,2) → 00000101, ..., (6,7) → 11000000
|
|
|
+ */
|
|
|
+ private suspend fun generateKBitMasks(
|
|
|
+ k: Int,
|
|
|
+ n: Int,
|
|
|
+ emit: suspend (Int) -> Unit
|
|
|
+ ) {
|
|
|
+ // 组合索引数组,初始为 [0,1,2,...,k-1]
|
|
|
+ val idx = IntArray(k) { it }
|
|
|
+ while (true) {
|
|
|
+ // 根据当前索引组合生成掩码
|
|
|
+ var mask = 0
|
|
|
+ for (i in 0 until k) {
|
|
|
+ mask = mask or (1 shl idx[i])
|
|
|
+ }
|
|
|
+ emit(mask)
|
|
|
+
|
|
|
+ // 生成下一个组合(典型字典序组合生成算法)
|
|
|
+ var pos = k - 1
|
|
|
+ while (pos >= 0 && idx[pos] == pos + n - k) pos--
|
|
|
+ if (pos < 0) break
|
|
|
+ idx[pos]++
|
|
|
+ for (j in pos + 1 until k) {
|
|
|
+ idx[j] = idx[j - 1] + 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 如果你不需要挂起回调,也可以拿到一个 Sequence 方便 for-each。
|
|
|
+ */
|
|
|
+ fun scanRangeSeq(): Sequence<Int> = sequence {
|
|
|
+ for (k in 1..MAX_BITS) {
|
|
|
+ // 复用相同生成逻辑,但以 yield 返回
|
|
|
+ val idx = IntArray(k) { it }
|
|
|
+ while (true) {
|
|
|
+ var mask = 0
|
|
|
+ for (i in 0 until k) mask = mask or (1 shl idx[i])
|
|
|
+ yield(mask)
|
|
|
+
|
|
|
+ var pos = k - 1
|
|
|
+ while (pos >= 0 && idx[pos] == pos + MAX_BITS - k) pos--
|
|
|
+ if (pos < 0) break
|
|
|
+ idx[pos]++
|
|
|
+ for (j in pos + 1 until k) idx[j] = idx[j - 1] + 1
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|