// syndrome takes a bitstream and uses the parity bits from the BCH polynomial // generator to calculate if the bits are received correctly. // A 0 return means the bits are correct. // Thanks to multimon-ng (https://github.com/EliasOenal/multimon-ng) for // detailing implmentation of this. func syndrome(bits []datatypes.Bit) uint32 { bytes := utils.MSBBitsToBytes(bits, 8) // take the parity-bit out from our codeword codeword := utils.Btouint32(bytes) >> 1 // put the mask bit to the far left in the bitstream mask := uint32(1 << (BCH_N)) coeff := uint32(BHC_COEFF) // step over each data-bit (the first 21) for a := 0; a < BCH_K; a += 1 { // step the coefficient and mask right in the bitstream mask >>= 1 coeff >>= 1 // if the current bit in the codeword is 1 then XOR the codeword with the coefficient if (codeword & mask) > 0 { codeword = codeword ^ coeff } } // in the end, if the coefficient matches the codeword they // are canceled out by the XOR, returning 0 return codeword }
// NewCodeword takes 32 bits, creates a new codeword construct, sets the type and checks for parity errors. func NewCodeword(bits []datatypes.Bit) (*Codeword, error) { if len(bits) != 32 { return nil, fmt.Errorf("invalid number of bits for codeword: ", len(bits)) } bits, corrected := BitCorrection(bits) mtype := CodewordTypeAddress if bits[0] == true { mtype = CodewordTypeMessage } bytes := utils.MSBBitsToBytes(bits, 8) if isIdle(bytes) { mtype = CodewordTypeIdle } c := &Codeword{ Type: mtype, Payload: bits[1:21], ParityBits: bits[21:31], EvenParity: bits[31], ValidParity: (syndrome(bits) == 0) && utils.ParityCheck(bits[:31], bits[31]), BitCorrections: corrected, } return c, nil }
// ParseBatches takes bits decoded from the stream and parses them for // batches of codewords. func (p *POCSAG) ParseBatches(bits []datatypes.Bit) ([]*Batch, error) { batches := []*Batch{} var start = -1 var batchno = -1 // synchornize with the decoded bits for a := 0; a < len(bits)-32; a += 1 { bytes := utils.MSBBitsToBytes(bits[a:a+32], 8) if isPreamble(bytes) { batchno += 1 start = a + 32 // for file output as bin data batchbits := bits[a : a+POCSAG_BATCH_LEN+32] stream := utils.MSBBitsToBytes(batchbits, 8) if DEBUG && LEVEL > 2 { out, err := os.Create(fmt.Sprintf("batches/batch-%d.bin", batchno)) if err != nil { return nil, err } out.Write(stream) } batch, err := NewBatch(bits[start : start+POCSAG_BATCH_LEN]) if err != nil { println(err.Error()) } else { batches = append(batches, batch) } } } if start < 0 { return nil, fmt.Errorf("could not obtain message sync") } return batches, nil }
// ReciptientString returns the reciptient address as a hexadecimal representation, // with the function bits as 0 or 1. func (m *Message) ReciptientString() string { bytes := utils.MSBBitsToBytes(m.Reciptient.Payload[0:17], 8) addr := uint(bytes[1]) addr += uint(bytes[0]) << 8 return fmt.Sprintf("%X%d%d", addr, m.Reciptient.Payload[18].Int(), m.Reciptient.Payload[19].Int()) }
// Print the address for debugging func (c *Codeword) Adress() string { bytes := utils.MSBBitsToBytes(c.Payload[0:17], 8) addr := uint(bytes[1]) addr += uint(bytes[0]) << 8 return fmt.Sprintf("%X:%s%s", addr, utils.TernaryStr(bool(c.Payload[18]), "1", "0"), utils.TernaryStr(bool(c.Payload[19]), "1", "0")) }