dmr_utils3/dmr_utils3/ambe_utils.py

278 lines
8.3 KiB
Python
Executable File

#!/usr/bin/env python
#
###############################################################################
# Copyright (C) 2017 Mike Zingman N4IRR
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
'''
'''
from binascii import b2a_hex as ahex
from bitarray import bitarray
from bitstring import BitArray
from bitstring import BitString
__author__ = 'Mike Zingman, N4IRR and Cortney T. Buffington, N0MJS'
__copyright__ = 'Copyright (c) 2017 Mike Zingman N4IRR'
__credits__ = 'Cortney T. Buffington, N0MJS; Colin Durbridge, G4EML, Steve Zingman, N4IRS; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT'
__license__ = 'GNU GPLv3'
__maintainer__ = 'Cort Buffington, N0MJS'
__email__ = 'n0mjs@me.com'
##
# DMR AMBE interleave schedule
##
rW = [
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 1,
0, 1, 0, 1, 0, 2,
0, 2, 0, 2, 0, 2,
0, 2, 0, 2, 0, 2
]
rX = [
23, 10, 22, 9, 21, 8,
20, 7, 19, 6, 18, 5,
17, 4, 16, 3, 15, 2,
14, 1, 13, 0, 12, 10,
11, 9, 10, 8, 9, 7,
8, 6, 7, 5, 6, 4
]
rY = [
0, 2, 0, 2, 0, 2,
0, 2, 0, 3, 0, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3
]
rZ = [
5, 3, 4, 2, 3, 1,
2, 0, 1, 13, 0, 12,
22, 11, 21, 10, 20, 9,
19, 8, 18, 7, 17, 6,
16, 5, 15, 4, 14, 3,
13, 2, 12, 1, 11, 0
]
# This function calculates [23,12] Golay codewords.
# The format of the returned longint is [checkbits(11),data(12)].
def golay2312(cw):
POLY = 0xAE3 #/* or use the other polynomial, 0xC75 */
cw = cw & 0xfff # Strip off check bits and only use data
c = cw #/* save original codeword */
for i in range(1,13): #/* examine each data bit */
if (cw & 1): #/* test data bit */
cw = cw ^ POLY #/* XOR polynomial */
cw = cw >> 1 #/* shift intermediate result */
return((cw << 12) | c) #/* assemble codeword */
# This function checks the overall parity of codeword cw.
# If parity is even, 0 is returned, else 1.
def parity(cw):
#/* XOR the bytes of the codeword */
p = cw & 0xff
p = p ^ ((cw >> 8) & 0xff)
p = p ^ ((cw >> 16) & 0xff)
#/* XOR the halves of the intermediate result */
p = p ^ (p >> 4)
p = p ^ (p >> 2)
p = p ^ (p >> 1)
#/* return the parity result */
return(p & 1)
# Demodulate ambe frame (C1)
# Frame is an array [4][24]
def demodulateAmbe3600x2450(ambe_fr):
pr = [0] * 115
foo = 0
# create pseudo-random modulator
for i in range(23, 11, -1):
foo = foo << 1
foo = foo | ambe_fr[0][i]
pr[0] = (16 * foo)
for i in range(1, 24):
pr[i] = (173 * pr[i - 1]) + 13849 - (65536 * (((173 * pr[i - 1]) + 13849) // 65536))
for i in range(1, 24):
pr[i] = pr[i] // 32768
# demodulate ambe_fr with pr
k = 1
for j in range(22, -1, -1):
ambe_fr[1][j] = ((ambe_fr[1][j]) ^ pr[k])
k = k + 1
return ambe_fr # Pass it back since there is no pass by reference
def eccAmbe3600x2450Data(ambe_fr):
ambe = bitarray()
# just copy C0
for j in range(23, 11, -1):
ambe.append(ambe_fr[0][j])
# # ecc and copy C1
# gin = 0
# for j in range(23):
# gin = (gin << 1) | ambe_fr[1][j]
#
# gout = BitArray(hex(golay2312(gin)))
# for j in range(22, 10, -1):
# ambe[bitIndex] = gout[j]
# bitIndex += 1
for j in range(22, 10, -1):
ambe.append(ambe_fr[1][j])
# just copy C2
for j in range(10, -1, -1):
ambe.append(ambe_fr[2][j])
# just copy C3
for j in range(13, -1, -1):
ambe.append(ambe_fr[3][j])
return ambe
# Convert a 49 bit raw AMBE frame into a deinterleaved structure (ready for decode by AMBE3000)
def convert49BitAmbeTo72BitFrames( ambe_d ):
index = 0
ambe_fr = [[None for x in range(24)] for y in range(4)]
#Place bits into the 4x24 frames. [bit0...bit23]
#fr0: [P e10 e9 e8 e7 e6 e5 e4 e3 e2 e1 e0 11 10 9 8 7 6 5 4 3 2 1 0]
#fr1: [e10 e9 e8 e7 e6 e5 e4 e3 e2 e1 e0 23 22 21 20 19 18 17 16 15 14 13 12 xx]
#fr2: [34 33 32 31 30 29 28 27 26 25 24 x x x x x x x x x x x x x]
#fr3: [48 47 46 45 44 43 42 41 40 39 38 37 36 35 x x x x x x x x x x]
# ecc and copy C0: 12bits + 11ecc + 1 parity
# First get the 12 bits that actually exist
# Then calculate the golay codeword
# And then add the parity bit to get the final 24 bit pattern
tmp = 0
for i in range(11, -1, -1): #grab the 12 MSB
tmp = (tmp << 1) | ambe_d[i]
tmp = golay2312(tmp) #Generate the 23 bit result
parityBit = parity(tmp)
tmp = tmp | (parityBit << 23) #And create a full 24 bit value
for i in range(23, -1, -1):
ambe_fr[0][i] = (tmp & 1)
tmp = tmp >> 1
# C1: 12 bits + 11ecc (no parity)
tmp = 0
for i in range(23,11, -1) : #grab the next 12 bits
tmp = (tmp << 1) | ambe_d[i]
tmp = golay2312(tmp) #Generate the 23 bit result
for j in range(22, -1, -1):
ambe_fr[1][j] = (tmp & 1)
tmp = tmp >> 1;
#C2: 11 bits (no ecc)
for j in range(10, -1, -1):
ambe_fr[2][j] = ambe_d[34 - j]
#C3: 14 bits (no ecc)
for j in range(13, -1, -1):
ambe_fr[3][j] = ambe_d[48 - j];
return ambe_fr
def interleave(ambe_fr):
bitIndex = 0
w = 0
x = 0
y = 0
z = 0
data = bytearray(9)
for i in range(36):
bit1 = ambe_fr[rW[w]][rX[x]] # bit 1
bit0 = ambe_fr[rY[y]][rZ[z]] # bit 0
data[bitIndex // 8] = ((data[bitIndex // 8] << 1) & 0xfe) | (1 if (bit1 == 1) else 0)
bitIndex += 1
data[bitIndex // 8] = ((data[bitIndex // 8] << 1) & 0xfe) | (1 if (bit0 == 1) else 0)
bitIndex += 1
w += 1
x += 1
y += 1
z += 1
return data
def deinterleave(data):
ambe_fr = [[None for x in range(24)] for y in range(4)]
bitIndex = 0
w = 0
x = 0
y = 0
z = 0
for i in range(36):
bit1 = 1 if data[bitIndex] else 0
bitIndex += 1
bit0 = 1 if data[bitIndex] else 0
bitIndex += 1
ambe_fr[rW[w]][rX[x]] = bit1; # bit 1
ambe_fr[rY[y]][rZ[z]] = bit0; # bit 0
w += 1
x += 1
y += 1
z += 1
return ambe_fr
def convert72BitTo49BitAMBE( ambe72 ):
ambe_fr = deinterleave(ambe72) # take 72 bit ambe and lay it out in C0-C3
ambe_fr = demodulateAmbe3600x2450(ambe_fr) # demodulate C1
ambe49 = eccAmbe3600x2450Data(ambe_fr) # pick out the 49 bits of raw ambe
return ambe49
def convert49BitTo72BitAMBE( ambe49 ):
ambe_fr = convert49BitAmbeTo72BitFrames(ambe49) # take raw ambe 49 + ecc and place it into C0-C3
ambe_fr = demodulateAmbe3600x2450(ambe_fr) # demodulate C1
ambe72 = interleave(ambe_fr); # Re-interleave it, returning 72 bits
return ambe72
def testit():
ambe72 = BitArray('0xACAA40200044408080') #silence frame
print('ambe72=',ambe72)
ambe49 = convert72BitTo49BitAMBE(ambe72)
print('ambe49=',ahex(ambe49.tobytes()))
ambe72 = convert49BitTo72BitAMBE(ambe49)
print('ambe72=',ahex(ambe72))
#------------------------------------------------------------------------------
# Used to execute the module directly to run built-in tests
#------------------------------------------------------------------------------
if __name__ == '__main__':
testit()