diff --git a/example/balise_1023_830/main.go b/example/balise_1023_830/main.go new file mode 100644 index 0000000..90477d5 --- /dev/null +++ b/example/balise_1023_830/main.go @@ -0,0 +1,406 @@ +package main + +import ( + "fmt" + "log/slog" + "strconv" + + "joylink.club/bj-rtsts-server/third_party/balise" +) + +type Transponder struct { + // 应答器编号 + Code int + // 应答器名称 + Name string + // 应答器类型 + Type string + // 校验码 + CheckSum string + // 830报文 + Msg830 string + // 1023报文 + Msg1023 string +} + +func main() { + transponderMap := ReadTransponders() + // v := transponderMap["FB121_BGZ"] + // b1023 := convertToBalise1023(v.Msg1023) + // replaced830 := replaceFirst10Bits(convertTo830(v.Msg830)) + // scrambled830 := scrambling(replaced830, b1023.S) + // compare830(scrambled830, b1023.data830) + + // count := 0 + for _, v := range transponderMap { + // slog.Info("transponder", "name", v.Name, "code", v.Code, "checksum", v.CheckSum, "msg830", v.Msg830, "msg1023", v.Msg1023) + byte104, err := balise.DecodeByteString(v.Msg1023) + if err != nil { + slog.Error("解码应答器数据失败", "name", v.Name, "code", v.Code, "err", err) + continue + } + compare104Bytes(byte104, balise.ConvertByteStringToBytes(v.Msg830)) + // b1023 := convertToBalise1023(v.Msg1023) + // source830 := convertTo830(v.Msg830) + // // replaced830 := replaceFirst10Bits(source830) + // // compare830(reverted830, source830) + // descrambled830 := descrambling(b1023.data830, b1023.S) + // reverted830 := revertFirst10Bits(descrambled830) + // // // scrambled830 := scrambling(replaced830, b1023.S) + // compare830(source830, reverted830) + // count++ + // if count >= 10 { + // break + // } + } + +} + +// 比较830位数据 +func compare104Bytes(bytes104 []byte, compare104 []byte) { + if len(bytes104) != 104 { + panic("invalid length") + } + for i := 0; i < 104; i++ { + fmt.Printf("%02x\n", bytes104[i]) + fmt.Printf("%02x\n\n", compare104[i]) + if bytes104[i] != compare104[i] { + slog.Info("error", "index", i, "bytes104", fmt.Sprintf("%02x", bytes104[i]), "compare", fmt.Sprintf("%02x", compare104[i])) + panic("104 bytes compare error") + } + } +} + +type Balise1023 struct { + bits []byte // 1023报文,1023bit + data []byte // 数据位,913bit + data830 []byte // 830位数据 + cb []byte // 控制位,3bit + sb []byte // 加扰位,12bit + S uint32 // 由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 + esb []byte // 额外修正位,10bit + checkSum []byte // 校验位,85bit +} + +func newBalise1023(bits []byte) *Balise1023 { + if len(bits) != 1023 { + panic("invalid length") + } + // for i := 0; i < 1023; i++ { + // if i%10 == 0 { + // println() + // } + // print(1022-i, ":", bits[i], ",") + // } + // println() + balise1023 := &Balise1023{ + bits: bits, + } + balise1023.data = balise1023.getRange(1022, 110) + if len(balise1023.data) != 913 { + panic("invalid data length") + } + balise1023.data830 = convert913To830(balise1023.data) + balise1023.check11To10() + balise1023.cb = balise1023.getRange(109, 107) + for i, v := range balise1023.cb { + n := 109 - i + name := "b" + strconv.Itoa(109-i) + slog.Info("cb", name, v) + if n == 109 && v == 1 { + slog.Error("控制位cb错误:cb109应该为0,实际为1") + } else if n == 108 && v == 1 { + slog.Error("控制位cb错误:cb108应该为0,实际为1") + } else if n == 107 && v == 0 { + slog.Error("控制位cb错误:cb107应该为1,实际为0") + } + } + balise1023.sb = balise1023.getRange(106, 95) + balise1023.S = calculateS(balise1023.sb) + balise1023.esb = balise1023.getRange(94, 85) + balise1023.checkSum = balise1023.getRange(84, 0) + slog.Info("msg length", "datalen", len(balise1023.data), "cblen", len(balise1023.cb), "sblen", len(balise1023.sb), "esblen", len(balise1023.esb), "checkSumlen", len(balise1023.checkSum)) + return balise1023 +} + +func (b *Balise1023) getRange(start, end int) []byte { + if start < 0 || end < 0 || start < end || start > 1022 { + panic("invalid range") + } + return b.bits[1022-start : 1022-(end-1)] +} + +func (b *Balise1023) check11To10() { + b913 := b.data + compare := convert830To913(b.data830) + for i := 0; i < 913; i++ { + if b913[i] != compare[i] { + slog.Info("error", "idx", i, "b913", b913[i], "compare", compare[i]) + panic("10 to 11 bit error") + } + } +} + +// 转换字节字符串到bit数组,左边为最高有效位(MSB) +func convertStringBytesToBits(msg string) []byte { + length := len(msg) + println("msg:", msg) + bytes := make([]byte, length/2) + for i := 0; i < length; i += 2 { + v, err := strconv.ParseUint(msg[i:i+2], 16, 8) + if err != nil { + panic(err) + } + bytes[i/2] = byte(v) + // slog.Info("i", "byteidx", i/2, "byte", fmt.Sprintf("%02x", v)) + } + // 字节转换为bit数组 + bits := make([]byte, length/2*8) + for i, bt := range bytes { + for j := 0; j < 8; j++ { + move := 7 - j + idx := i*8 + j + bits[idx] = (bt >> move) & 1 + } + } + return bits +} + +func convertTo830(msg string) []byte { + length := len(msg) + if length != 208 { + panic("invalid length") + } + // 字节转换为bit数组 + bits := convertStringBytesToBits(msg) + bits830 := bits[0:830] + return bits830 +} + +func convertToBalise1023(msg string) *Balise1023 { + length := len(msg) + if length != 256 { + panic("invalid length") + } + // 字节转换为bit数组 + bits := convertStringBytesToBits(msg) + bits1023 := bits[0:1023] + slog.Info("bits length", "len", len(bits1023)) + return newBalise1023(bits1023) +} + +// 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组,除了第一个10位值,其余值求和,然后循环2的10次方次与其他值求和结果相加后模2的10次方,若结果和第一个10位值相同,则结束,此值即为原始的第一个10位值,将此值替换为第一个10位二进制数组,依然是左边为MSB +func revertFirst10Bits(b []byte) []byte { + if len(b) != 830 { + panic("invalid length") + } + // 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组 + bits := make([]uint16, 83) + for i := 0; i < 83; i++ { + bits[i] = uint16(balise.ToValLeftMsb(b[i*10 : i*10+10])) + // 打印输出 + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b[i*10+j]) + } + print(" ") + if i != 0 && i%10 == 9 { + println() + } + } + println() + // 将除了第一个10位字整数求和 + sum := uint64(0) + for i := 1; i < 83; i++ { + sum += uint64(bits[i]) + } + // 循环2的10次方次与其他值求和结果相加后模2的10次方 + for i := 0; i < 1024; i++ { + test := sum + uint64(i) + if test%1024 == uint64(bits[0]) { + bits[0] = uint16(i) + break + } + } + slog.Info("还原第一个10位值", "sum", sum, "bits[0]", bits[0], "bits[0]b", fmt.Sprintf("%010b", bits[0])) + rbits := make([]byte, 830) + // 将整个10位数组转换为二进制数组,依然是MSB + u0bits := balise.ToBitsLeftMsb(int(bits[0]), 10) + for i := 0; i < 10; i++ { + rbits[i] = u0bits[i] + } + for i := 10; i < 830; i++ { + rbits[i] = b[i] + } + // compare830(b, rbits) + return rbits +} + +// 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组,然后求和后模2的10次方,得到的结果覆盖第一个10位值,然后将整个10位数组转换为二进制数组,依然是左边为MSB +func replaceFirst10Bits(b []byte) []byte { + if len(b) != 830 { + panic("invalid length") + } + // 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组 + bits := make([]uint16, 83) + for i := 0; i < 83; i++ { + bits[i] = uint16(balise.ToValLeftMsb(b[i*10 : i*10+10])) + // 打印输出 + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b[i*10+j]) + } + print(" ") + if i != 0 && i%10 == 9 { + println() + } + } + println() + // 将每一个10位字整数求和后模2的10次方,得到的结果覆盖第一个10位值 + sum := uint64(0) + for i := 0; i < 83; i++ { + sum += uint64(bits[i]) + // fmt.Printf("i=%d, v10=%d, v10b=%010b\n", i, bits[i], bits[i]) + } + bits[0] = uint16(sum % 1024) + slog.Info("替换第一个10位值", "sum", sum, "bits[0]", bits[0], "bits[0]b", fmt.Sprintf("%010b", bits[0])) + rbits := make([]byte, 830) + // 将整个10位数组转换为二进制数组,依然是MSB + u0bits := balise.ToBitsLeftMsb(int(bits[0]), 10) + for i := 0; i < 10; i++ { + rbits[i] = u0bits[i] + } + for i := 10; i < 830; i++ { + rbits[i] = b[i] + } + // compare830(b, rbits) + return rbits +} + +// 由加扰位计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 +func calculateS(sb []byte) uint32 { + // 由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 + if len(sb) != 12 { + panic("invalid length") + } + B := balise.ToValLeftMsb(sb) + const A uint64 = 2801775573 + S := uint32((A * uint64(B)) % (1 << 32)) + slog.Info("由12位加扰位计算得到整数S", "B", B, "S", S, "Sb", fmt.Sprintf("%032b", S)) + return S +} + +// 由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 +// 1. 生成一个32位的线性反馈移位寄存器,其初始状态为S(左边为MSB) +// 2. 系数h31,h30,h29,h27,h25和h0等于1(表示连接),所有其他系数都为0(表示不连接) +// 3. 然后电路被时钟驱动m-1次,其中m是数据位的数量,同时输入dn的每一位dn(m-1),dn(m-2),...,dn(0),便生成加扰后的码位(在第一个时钟之前读取第一个输出out(m-1)) +// 4. 生成的加扰码位是dn的每一位与S的最高位的异或值 +// 5. 生成的加扰码位会根据系数进行异或反馈回S的最低位 +// 几种可能性: +func scrambling(dn []byte, S uint32) []byte { + if len(dn) != 830 { + panic("invalid length") + } + // const Polynomial = 0x000000AF + out := make([]byte, len(dn)) + t := S // 寄存器初始值 + for i := 0; i < len(dn); i++ { + msb := (t >> 31) & 1 + out[i] = (dn[i] ^ byte(msb)) & 1 + // fmt.Printf("i=%d, t=%032b, msb=%d, dn=%d, out=%d\n", i, t, msb, dn[i], out[i]) + xor := uint32(out[i]) + t = (xor << 30) ^ (xor << 29) ^ (xor << 28) ^ (xor << 26) ^ (xor << 24) ^ t + t = (t << 1) | xor + } + return out +} + +func descrambling(dn []byte, S uint32) []byte { + if len(dn) != 830 { + panic("invalid length") + } + // const Polynomial = 0x000000AF + out := make([]byte, len(dn)) + t := S // 寄存器初始值 + for i := 0; i < len(dn); i++ { + msb := (t >> 31) & 1 + out[i] = (dn[i] ^ byte(msb)) & 1 + // fmt.Printf("i=%d, t=%032b, msb=%d, dn=%d, out=%d\n", i, t, msb, dn[i], out[i]) + xor := uint32(dn[i]) + t = (xor << 30) ^ (xor << 29) ^ (xor << 28) ^ (xor << 26) ^ (xor << 24) ^ t + t = (t << 1) | xor + } + return out +} + +// 将830位的二进制数组先以10位为一组分别转换为11位并组合 +func convert830To913(b830 []byte) []byte { + if len(b830) != 830 { + panic("invalid length") + } + b913 := make([]byte, 913) + for i := 0; i < 83; i++ { + b11 := balise.To11(b830[i*10 : i*10+10]) + for j := 0; j < 11; j++ { + b913[i*11+j] = b11[j] + } + } + return b913 +} + +func convert913To830(b913 []byte) []byte { + if len(b913) != 913 { + panic("invalid length") + } + b830 := make([]byte, 830) + for i := 0; i < 83; i++ { + b10, err := balise.From11(b913[i*11 : i*11+11]) + if err != nil { + panic(err) + } + for j := 0; j < 10; j++ { + b830[i*10+j] = b10[j] + } + } + return b830 +} + +func compare830(b830 []byte, compare830 []byte) { + if len(b830) != 830 { + panic("invalid length") + } + for i := 0; i < 83; i++ { + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b830[i*10+j]) + } + println() + for j := 0; j < 10; j++ { + fmt.Printf("%01b", compare830[i*10+j]) + } + println() + println() + } + for i := 0; i < 830; i++ { + if b830[i] != compare830[i] { + slog.Info("error", "index", i, "b830", b830[i], "compare", compare830[i]) + panic("830 bit compare error") + } + } +} + +// 以11位为一组比较两个913位的报文 +func compare913(b913 []byte, b1023 *Balise1023) { + if len(b913) != 913 { + panic("invalid length") + } + compare := b1023.data + for i := 0; i < 913; i += 11 { + for j := 0; j < 11; j++ { + print(b913[i+j]) + } + println() + for j := 0; j < 11; j++ { + print(compare[i+j]) + } + println() + println() + } +} diff --git a/example/balise_1023_830/read_excel.go b/example/balise_1023_830/read_excel.go new file mode 100644 index 0000000..4ef46f1 --- /dev/null +++ b/example/balise_1023_830/read_excel.go @@ -0,0 +1,156 @@ +package main + +import ( + "log/slog" + "runtime/debug" + "strconv" + "strings" + + "github.com/xuri/excelize/v2" +) + +const ( + fileName = "北岗子-应答器报文清单.xlsx" + sheetName = "应答器报文清单" + codeColumn = "应答器编号" + nameColumn = "应答器名称" + typeColumn = "类型" + checkSumColumn = "校验码" + msg830strColumn = "用户报文(830bits)" + msg1023strColumn = "报文(1023bits)" +) + +var heads []string + +func init() { + initHeads() +} + +func initHeads() { + heads = append(heads, codeColumn) + heads = append(heads, nameColumn) + heads = append(heads, typeColumn) + heads = append(heads, checkSumColumn) + heads = append(heads, msg830strColumn) + heads = append(heads, msg1023strColumn) +} + +func buildHeadIndex(row []string) map[string]int { + headIdx := make(map[string]int) + for i, column := range row { + column = HandleStringSpace(column) + if column == codeColumn { + headIdx[column] = i + } else if column == nameColumn { + headIdx[column] = i + } else if column == typeColumn { + headIdx[column] = i + } else if column == checkSumColumn { + headIdx[column] = i + } else if column == msg830strColumn { + headIdx[column] = i + } else if column == msg1023strColumn { + headIdx[column] = i + } + } + // 检查headIndex是否完整 + if len(headIdx) <= 0 { + return nil + } + checkHeadsIndex(headIdx, fileName, sheetName, heads) + return headIdx +} + +func checkHeadsIndex(headIdx map[string]int, fileName, sheetName string, heads []string) { + // 检查headIndex是否完整 + for _, v := range heads { + if _, ok := headIdx[v]; !ok { + slog.Error("表头缺失", "文件名", fileName, "SheetName", sheetName, "表头", v) + panic("课时表头缺失") + } + } +} + +func ReadTransponders() map[string]Transponder { + return readExcel(fileName, sheetName, readRows) +} + +func readExcel[T any](fileName, sheetName string, handle func(rows [][]string) map[string]T) map[string]T { + f, err := excelize.OpenFile(fileName) + if err != nil { + slog.Error("打开表文件异常", "表名", fileName, "error", err) + debug.PrintStack() + panic("打开表文件异常") + } + defer func() { + if err := f.Close(); err != nil { + slog.Error("文件关闭异常", "error", err) + } + }() + + rows, err := f.GetRows(sheetName) + if err != nil { + slog.Error("读取Sheet异常", "SheetName", sheetName, "error", err) + panic(err) + } + // fmt.Println(rows) + return handle(rows) +} + +func readRows(rows [][]string) map[string]Transponder { + dataMap := make(map[string]Transponder) + var headIdx map[string]int + for _, row := range rows { + if headIdx == nil { + headIdx = buildHeadIndex(row) + // if headIdx != nil { + // slog.Info("读取到表头索引", "文件名", fileName, "表名", sheetName, "索引", headIdx) + // } + } else { + rowSize := len(row) + if rowSize <= 0 { + continue + } + if rowSize <= headIdx[msg1023strColumn] { + // slog.Info("非数据行", "row", row, "rowIndex", i) + continue + } + codeStr := row[headIdx[codeColumn]] + if codeStr == "" { + continue + } + codeStr = HandleStringSpace(codeStr) + code, err := strconv.ParseInt(codeStr, 10, 32) + if err != nil { + slog.Error("应答器编号错误", "编号", codeStr, "error", err) + panic("应答器编号错误") + } + name := row[headIdx[nameColumn]] + if name == "" { + continue + } + name = HandleStringSpace(name) + tp := row[headIdx[typeColumn]] + checkSum := row[headIdx[checkSumColumn]] + msg830 := row[headIdx[msg830strColumn]] + msg1023 := row[headIdx[msg1023strColumn]] + dataMap[name] = Transponder{ + Code: int(code), + Name: name, + Type: tp, + CheckSum: checkSum, + Msg830: msg830, + Msg1023: msg1023, + } + } + } + slog.Info("读取结果", "文件名", fileName, "SheetName", sheetName, "总数", len(dataMap)) + // fmt.Println(dataMap) + return dataMap +} + +func HandleStringSpace(s string) string { + s = strings.ReplaceAll(s, " ", "") + s = strings.ReplaceAll(s, "\n", "") + return s +} diff --git a/example/ex1/main.go b/example/ex1/main.go new file mode 100644 index 0000000..1b9564f --- /dev/null +++ b/example/ex1/main.go @@ -0,0 +1,32 @@ +package main + +import "log/slog" + +func main() { + a1 := calculateAvgAcc(136960.88, 24.41978) + a2 := calculateAvgAcc(34874, 14.97515) + slog.Info("根据位移和时间计算平均加速度", "通号平均加速度", a1, "动力学平均加速度", a2) + avt1 := calculateAvgAccByV(6.94444, 24.41978) + avt2 := calculateAvgAccByV(6.94444, 14.97515) + slog.Info("根据速度和时间计算平均加速度", "通号平均加速度", avt1, "动力学平均加速度", avt2) + s1 := calculateS(0.28437766432762146, 24.41978) + s2 := calculateS(0.46373090147972107, 14.97515) + slog.Info("根据加速度和时间计算位移", "通号最小位移", s1, "动力学最小位移", s2) + slog.Info("实际位移", "通号实际位移差", 136960.88-s1, "动力学实际位移差", 34874-s2) +} + +// 根据位移和时间计算平均加速度(初始速度为0) +// s单位为mm,t单位为s +func calculateAvgAcc(s float32, t float32) float32 { + return 2 * s / (t * t) / 1000 +} + +// 根据速度和时间计算平均加速度(初始速度为0) +func calculateAvgAccByV(v float32, t float32) float32 { + return v / t +} + +// 根据加速度和时间计算位移(初始速度为0) +func calculateS(a float32, t float32) float32 { + return 0.5 * a * t * t * 1000 +} diff --git a/example/lfsr/main.go b/example/lfsr/main.go new file mode 100644 index 0000000..1d72efe --- /dev/null +++ b/example/lfsr/main.go @@ -0,0 +1,56 @@ +package main + +import ( + "fmt" + "log/slog" +) + +func main() { + // fib_lfsr() + galois_lfsr() +} + +/* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */ +func fib_lfsr() { + startState := uint16(0xACE1) + lfsr := startState + var bit uint16 + period := uint64(0) + for { + slog.Info("fib_lfsr", "bit", fmt.Sprintf("%01b", lfsr&1), "lfsr", fmt.Sprintf("%016b", lfsr)) + bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5)) & 1 + lfsr = (lfsr >> 1) | (bit << 15) + period++ + if period == 15 { + break + } + if lfsr == startState { + break + } + } + println(period) +} + +/* taps: 16 14 13 11; feedback polynomial: x^16 + x^14 + x^13 + x^11 + 1 */ +func galois_lfsr() { + startState := uint16(0xACE1) + lfsr := startState + var bit uint16 + period := uint64(0) + for { + slog.Info("galois_lfsr", "bit", fmt.Sprintf("%01b", lfsr&1), "lfsr", fmt.Sprintf("%016b", lfsr)) + bit = lfsr & 1 + lfsr >>= 1 + if bit == 1 { + lfsr ^= 0xB400 + } + period++ + // if period == 15 { + // break + // } + if lfsr == startState { + break + } + } + println(period) +} diff --git a/example/test/main.go b/example/test/main.go new file mode 100644 index 0000000..65e04e2 --- /dev/null +++ b/example/test/main.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "math" +) + +func main() { + d2, d1, d0 := encodeAcc(6.742071875) + a := decode2Acc(d2, d1, d0) + fmt.Println(a) +} + +const G = 9.80665 + +func encodeAcc(a float32) (d2, d1, d0 byte) { + d2 = 0 + d1 = 0 + d0 = 0 + x := a / G + v := uint32(0) + for i := 17; i >= 0; i-- { + t := float32(1.0 / math.Pow(2, float64(17-i))) + if t > x { + continue + } else { + v |= 1 << i + x -= t + } + } + fmt.Printf("%b, %b\n", v, v<<6) + v <<= 6 + d0 = byte(v) + d1 = byte(v >> 8) + d2 = byte(v >> 16) + fmt.Printf("%b, %b, %b\n", d2, d1, d0) + return +} + +func decode2Acc(d2, d1, d0 byte) float32 { + v := uint32(d2)<<10 | uint32(d1)<<2 | uint32(d0>>6) + fmt.Printf("%b\n", v) + x := float32(0) + for i := 17; i >= 0; i-- { + if v&(1< 1022 { + panic("invalid range") + } + return bits[1022-start : 1022-(end-1)] +} + +// 转换128字节数据为1023位数据 +func convertTo1023Bits(byte128 []byte) []byte { + if len(byte128) != 128 { + panic("invalid length") + } + // 字节转换为bit数组 + bits := make([]byte, 1024) + for i, bt := range byte128 { + for j := 0; j < 8; j++ { + move := 7 - j + idx := i*8 + j + bits[idx] = (bt >> move) & 1 + } + } + bits1023 := bits[0:1023] + return bits1023 +} + +// 由加扰位计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 +func calculateS(sb []byte) uint32 { + // 由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 + if len(sb) != 12 { + panic("invalid length") + } + B := ToValLeftMsb(sb) + const A uint64 = 2801775573 + S := uint32((A * uint64(B)) % (1 << 32)) + slog.Info("由12位加扰位计算得到整数S", "B", B, "S", S, "Sb", fmt.Sprintf("%032b", S)) + return S +} + +// 以11位为一组比较两个913位的报文 +func compare913(b913 []byte, compare []byte) { + if len(b913) != 913 { + panic("invalid length") + } + for i := 0; i < 913; i += 11 { + for j := 0; j < 11; j++ { + print(b913[i+j]) + } + println() + for j := 0; j < 11; j++ { + print(compare[i+j]) + } + println() + println() + } +} + +// 比较830位数据 +func compare830(b830 []byte, compare830 []byte) { + if len(b830) != 830 { + panic("invalid length") + } + for i := 0; i < 83; i++ { + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b830[i*10+j]) + } + println() + for j := 0; j < 10; j++ { + fmt.Printf("%01b", compare830[i*10+j]) + } + println() + println() + } + for i := 0; i < 830; i++ { + if b830[i] != compare830[i] { + slog.Info("error", "index", i, "b830", b830[i], "compare", compare830[i]) + panic("830 bit compare error") + } } } diff --git a/third_party/balise/conv.go b/third_party/balise/conv.go index 16adbbd..a6c67c1 100644 --- a/third_party/balise/conv.go +++ b/third_party/balise/conv.go @@ -113,14 +113,83 @@ var ConvWords = []uint16{ var convWordMap = make(map[uint16]int, 1024) func init() { + if len(ConvWords) != 1024 { + panic(fmt.Errorf("ConvWords长度不是1024, len=%d", len(ConvWords))) + } + // 检查,前512个字的累加和为267528,所有1024个字的累加和为1048064 + sum1 := 0 + sum2 := 0 + for i := 0; i < 1024; i++ { + if i < 512 { + sum1 += int(ConvWords[i]) + } + sum2 += int(ConvWords[i]) + } + if sum1 != 267528 { + panic(fmt.Errorf("前512个字的累加和不是267528, sum1=%d", sum1)) + } + if sum2 != 1048064 { + panic(fmt.Errorf("所有1024个字的累加和不是1048064, sum2=%d", sum2)) + } + // 检查,后一个字比前一个字大 + for i := 1; i < 1024; i++ { + if ConvWords[i] <= ConvWords[i-1] { + panic(fmt.Errorf("第%d个字比第%d个字小, %04o <= %04o", i, i-1, ConvWords[i], ConvWords[i-1])) + } + } for i, v := range ConvWords { convWordMap[v] = i + fmt.Printf("%04o: %d\n", v, i) + // slog.Info("构建10位到11位转换置换字", "i", i, "v", v) } + // 检查:翻转有效字的所有位能形成另一个有效字 + for _, v := range ConvWords { + rv := revertBits(v) + _, ok := convWordMap[rv] + if !ok { + panic(fmt.Errorf("构建10位到11位转换置换字失败, v=%04o, rv=%04o", v, rv)) + } + } +} + +// 翻转11位bit数组 +func revertBits(word uint16) uint16 { + bits11 := ToBitsLeftMsb(int(word), 11) + revert := make([]byte, 11) + for i := 0; i < 11; i++ { + if bits11[i] == 1 { + revert[i] = 0 + } else { + revert[i] = 1 + } + } + rw := ToValLeftMsb(revert) + // slog.Info("反转11位bit数组", "word", fmt.Sprintf("%04o", word), "bits11", bits11, "revert", revert, "revertWord", fmt.Sprintf("%04o", rw)) + return rw } // bit数组转换为数字,左边为最高有效位 // v - 0/1数组,数组的每个值都只能是0或1 -func ToVal(v []int) uint16 { +func ToValLeftMsb(v []byte) uint16 { + if len(v) > 15 { + panic(fmt.Errorf("不支持15位以上")) + } + val := uint16(0) + l := len(v) + elems := make([]string, l) + for i := 0; i < l; i++ { + elems[i] = fmt.Sprintf("%d", v[i]) + if v[i] == 1 { + val += (1 << (l - i - 1)) + } + } + // slog.Info("ToValLeftMsb", "len", l, "v", strings.Join(elems, ""), "val", fmt.Sprintf("%04o", val)) + return val +} + +// bit数组转换为数字,右边为最高有效位 +// v - 0/1数组,数组的每个值都只能是0或1 +func ToValRightMsb(v []byte) uint16 { if len(v) > 15 { panic(fmt.Errorf("不支持15位以上")) } @@ -128,15 +197,15 @@ func ToVal(v []int) uint16 { l := len(v) for i := 0; i < l; i++ { if v[i] == 1 { - val += (1 << (l - i - 1)) + val += (1 << i) } } return val } // 数字转换为bit数组,左边为最高有效位 -func ToBits(val int, count int) []int { - bs := make([]int, count) +func ToBitsLeftMsb(val int, count int) []byte { + bs := make([]byte, count) for i := 0; i < count; i++ { tmp := 1 << (count - 1 - i) if (val & (tmp)) == (tmp) { @@ -148,26 +217,42 @@ func ToBits(val int, count int) []int { return bs } +// 数字转换为bit数组,右边为最高有效位 +func ToBitsRightMsb(val int, count int) []byte { + bs := make([]byte, count) + for i := 0; i < count; i++ { + tmp := 1 << i + if (val & (tmp)) == (tmp) { + bs[i] = 1 + } else { + bs[i] = 0 + } + } + return bs +} + // 11位字转换回10位字 -func From11(b11 []int) ([]int, error) { - v11 := ToVal(b11) - v10, ok := convWordMap[uint16(v11)] +func From11(b11 []byte) ([]byte, error) { + v11 := ToValLeftMsb(b11) + v10, ok := convWordMap[v11] + // slog.Info("11位字转换回10位字", "v11", fmt.Sprintf("%04o", v11), "v11b", fmt.Sprintf("%011b", v11), "v10", v10, "ok", ok, "v10bits", fmt.Sprintf("%010b", v10), "to10Bits", ToBitsLeftMsb(v10, 10)) if ok { - return ToBits(v10, 10), nil + return ToBitsLeftMsb(v10, 10), nil } else { - return nil, fmt.Errorf("错误的11位字") + return nil, fmt.Errorf("错误的11位字,word11=%04o", v11) } } // 10位字转换为11位字 -func To11(b10 []int) []int { +func To11(b10 []byte) []byte { if len(b10) != 10 { panic(fmt.Errorf("应答器编码10位字转换为11位字参数异常: 位数不是10, len=%d", len(b10))) } - v10 := ToVal(b10) + v10 := ToValLeftMsb(b10) if v10 > 1023 { panic(fmt.Errorf("应答器编码10位字转换为11位字参数异常: 10位字转为整数不能大于1023, v10=%d", v10)) } v11 := ConvWords[v10] - return ToBits(int(v11), 11) + // slog.Info("10位字转换为11位字", "v10", v10, "v10b", fmt.Sprintf("%010b", v10), "v11", fmt.Sprintf("%04o", v11), "v11bits", fmt.Sprintf("%011b", v11), "to11Bits", ToBitsLeftMsb(int(v11), 11)) + return ToBitsLeftMsb(int(v11), 11) } diff --git a/third_party/balise/conv_test.go b/third_party/balise/conv_test.go index 30d363a..ff2a7c4 100644 --- a/third_party/balise/conv_test.go +++ b/third_party/balise/conv_test.go @@ -39,6 +39,6 @@ func TestConvList(t *testing.T) { } func TestTo11(t *testing.T) { - b10 := []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + b10 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 1} balise.To11(b10) } diff --git a/third_party/balise/decode.go b/third_party/balise/decode.go new file mode 100644 index 0000000..4e58d1d --- /dev/null +++ b/third_party/balise/decode.go @@ -0,0 +1,88 @@ +package balise + +import ( + "fmt" + "log/slog" +) + +// 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组,除了第一个10位值,其余值求和,然后循环2的10次方次与其他值求和结果相加后模2的10次方,若结果和第一个10位值相同,则结束,此值即为原始的第一个10位值,将此值替换为第一个10位二进制数组,依然是左边为MSB +func revertFirst10Bits(b []byte) []byte { + if len(b) != 830 { + panic("invalid length") + } + // 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组 + w10s := make([]uint16, 83) + for i := 0; i < 83; i++ { + w10s[i] = uint16(ToValLeftMsb(b[i*10 : i*10+10])) + // 打印输出 + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b[i*10+j]) + } + print(" ") + if i != 0 && i%10 == 9 { + println() + } + } + println() + // 将除了第一个10位字整数求和 + sum := uint64(0) + for i := 1; i < 83; i++ { + sum += uint64(w10s[i]) + } + // 循环2的10次方次与其他值求和结果相加后模2的10次方 + for i := 0; i < 1024; i++ { + test := sum + uint64(i) + if test%1024 == uint64(w10s[0]) { + w10s[0] = uint16(i) + break + } + } + slog.Info("还原第一个10位值", "sum", sum, "bits[0]", w10s[0], "bits[0]b", fmt.Sprintf("%010b", w10s[0])) + bits := make([]byte, 830) + // 将整个10位数组转换为二进制数组,依然是MSB + u0bits := ToBitsLeftMsb(int(w10s[0]), 10) + for i := 0; i < 10; i++ { + bits[i] = u0bits[i] + } + for i := 10; i < 830; i++ { + bits[i] = b[i] + } + return bits +} + +// 解扰,由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行解扰 +func descrambling(dn []byte, S uint32) []byte { + if len(dn) != 830 { + panic("invalid length") + } + // const Polynomial = 0x000000AF + out := make([]byte, len(dn)) + t := S // 寄存器初始值 + for i := 0; i < len(dn); i++ { + msb := (t >> 31) & 1 + out[i] = (dn[i] ^ byte(msb)) & 1 + // fmt.Printf("i=%d, t=%032b, msb=%d, dn=%d, out=%d\n", i, t, msb, dn[i], out[i]) + xor := uint32(dn[i]) + t = (xor << 30) ^ (xor << 29) ^ (xor << 28) ^ (xor << 26) ^ (xor << 24) ^ t + t = (t << 1) | xor + } + return out +} + +// 转换913位数据为830位数据 +func convert913To830(b913 []byte) ([]byte, error) { + if len(b913) != 913 { + panic("invalid length") + } + b830 := make([]byte, 830) + for i := 0; i < 83; i++ { + b10, err := From11(b913[i*11 : i*11+11]) + if err != nil { + return nil, buildError(err.Error()) + } + for j := 0; j < 10; j++ { + b830[i*10+j] = b10[j] + } + } + return b830, nil +} diff --git a/third_party/balise/encode.go b/third_party/balise/encode.go new file mode 100644 index 0000000..2b0dd19 --- /dev/null +++ b/third_party/balise/encode.go @@ -0,0 +1,86 @@ +package balise + +import ( + "fmt" + "log/slog" +) + +// 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组,然后求和后模2的10次方,得到的结果覆盖第一个10位值,然后将整个10位数组转换为二进制数组,依然是左边为MSB +func replaceFirst10Bits(b []byte) []byte { + if len(b) != 830 { + panic("invalid length") + } + // 将830位的二进制数组以10位为单位组成一个左边为最高有效位(MSB)的无符号整数数组 + bits := make([]uint16, 83) + for i := 0; i < 83; i++ { + bits[i] = uint16(ToValLeftMsb(b[i*10 : i*10+10])) + // 打印输出 + for j := 0; j < 10; j++ { + fmt.Printf("%01b", b[i*10+j]) + } + print(" ") + if i != 0 && i%10 == 9 { + println() + } + } + println() + // 将每一个10位字整数求和后模2的10次方,得到的结果覆盖第一个10位值 + sum := uint64(0) + for i := 0; i < 83; i++ { + sum += uint64(bits[i]) + // fmt.Printf("i=%d, v10=%d, v10b=%010b\n", i, bits[i], bits[i]) + } + bits[0] = uint16(sum % 1024) + slog.Info("替换第一个10位值", "sum", sum, "bits[0]", bits[0], "bits[0]b", fmt.Sprintf("%010b", bits[0])) + rbits := make([]byte, 830) + // 将整个10位数组转换为二进制数组,依然是MSB + u0bits := ToBitsLeftMsb(int(bits[0]), 10) + for i := 0; i < 10; i++ { + rbits[i] = u0bits[i] + } + for i := 10; i < 830; i++ { + rbits[i] = b[i] + } + // compare830(b, rbits) + return rbits +} + +// 由加扰计算得到的S,作为初始状态为S的32位线性反馈移位寄存器对数据进行加扰 +// 1. 生成一个32位的线性反馈移位寄存器,其初始状态为S(左边为MSB) +// 2. 系数h31,h30,h29,h27,h25和h0等于1(表示连接),所有其他系数都为0(表示不连接) +// 3. 然后电路被时钟驱动m-1次,其中m是数据位的数量,同时输入dn的每一位dn(m-1),dn(m-2),...,dn(0),便生成加扰后的码位(在第一个时钟之前读取第一个输出out(m-1)) +// 4. 生成的加扰码位是dn的每一位与S的最高位的异或值 +// 5. 生成的加扰码位会根据系数进行异或反馈回S的最低位 +// 几种可能性: +func scrambling(dn []byte, S uint32) []byte { + if len(dn) != 830 { + panic("invalid length") + } + // const Polynomial = 0x000000AF + out := make([]byte, len(dn)) + t := S // 寄存器初始值 + for i := 0; i < len(dn); i++ { + msb := (t >> 31) & 1 + out[i] = (dn[i] ^ byte(msb)) & 1 + // fmt.Printf("i=%d, t=%032b, msb=%d, dn=%d, out=%d\n", i, t, msb, dn[i], out[i]) + xor := uint32(out[i]) + t = (xor << 30) ^ (xor << 29) ^ (xor << 28) ^ (xor << 26) ^ (xor << 24) ^ t + t = (t << 1) | xor + } + return out +} + +// 将830位的二进制数组先以10位为一组分别转换为11位并组合 +func convert830To913(b830 []byte) []byte { + if len(b830) != 830 { + panic("invalid length") + } + b913 := make([]byte, 913) + for i := 0; i < 83; i++ { + b11 := To11(b830[i*10 : i*10+10]) + for j := 0; j < 11; j++ { + b913[i*11+j] = b11[j] + } + } + return b913 +} diff --git a/third_party/example/main.go b/third_party/example/main.go index 8480313..04e0059 100644 --- a/third_party/example/main.go +++ b/third_party/example/main.go @@ -46,13 +46,13 @@ func main() { // fmt.Println() // } // } - v10 := balise.ToVal([]int{ + v10 := balise.ToValLeftMsb([]byte{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) fmt.Println(v10) - bs := balise.ToBits(1982, 11) + bs := balise.ToBitsLeftMsb(1982, 11) fmt.Println(bs) // fmt.Printf("%o\n", balise.ConvWords[511]) } diff --git a/北岗子-应答器报文清单.xlsx b/北岗子-应答器报文清单.xlsx new file mode 100644 index 0000000..a9c08f0 Binary files /dev/null and b/北岗子-应答器报文清单.xlsx differ