-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
398 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
config/config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,3 @@ | ||
[submodule "src/md380tools"] | ||
path = src/md380tools | ||
url = [email protected]:travisgoodspeed/md380tools.git | ||
[submodule "src/callrec"] | ||
path = src/callrec | ||
url = [email protected]:BrandMeister/callrec.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,53 @@ | ||
FROM debian:stretch | ||
# | ||
# callrec builder | ||
# | ||
FROM golang AS callrecbuilder | ||
|
||
RUN apt-get update && apt-get install -y \ | ||
build-essential \ | ||
gcc-arm-linux-gnueabi \ | ||
WORKDIR /go | ||
RUN go get github.com/BrandMeister/callrec | ||
RUN go build github.com/BrandMeister/callrec | ||
|
||
|
||
# | ||
# MD380 builder | ||
# | ||
FROM debian:stretch AS md380builder | ||
|
||
RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
build-essential gcc-arm-linux-gnueabi unzip curl libc6-armel-cross libc6-dev-armel-cross ca-certificates python | ||
|
||
WORKDIR /md380tools | ||
COPY src/md380tools . | ||
|
||
WORKDIR /md380tools/emulator | ||
RUN make md380-emu | ||
|
||
# | ||
# Running container | ||
# | ||
|
||
FROM ruby:2.7-buster | ||
|
||
RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
sox \ | ||
wget \ | ||
mplayer | ||
mplayer \ | ||
python \ | ||
python3 \ | ||
python-pip python-setuptools python-dev python-wheel \ | ||
qemu-user \ | ||
libopus-dev \ | ||
nano | ||
|
||
RUN pip install bitarray bitstring | ||
RUN gem install mumble-ruby | ||
|
||
WORKDIR /app | ||
COPY --from=callrecbuilder /go/callrec . | ||
COPY --from=md380builder /md380tools/emulator/md380-emu . | ||
|
||
COPY src . | ||
COPY config . | ||
|
||
|
||
CMD ./start.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#!/bin/bash | ||
docker build -t dmr . |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"serverHost": "master.ham-dmr.be", | ||
"serverPort": 54005, | ||
"serverPassword": "<insert password here>", | ||
"serverTimeoutSeconds": 12, | ||
"appID": 123456, | ||
"recTalkgroupID": 91, | ||
"callHangTimeSeconds": 3, | ||
"callExecCommand1": "tee talk.log", | ||
"callExecCommand1ShowStderr": false, | ||
"callExecCommand2": "tee /tmp/dmr.fifo", | ||
"callExecCommand2ShowStderr": false, | ||
"callExecCommand3": "", | ||
"callExecCommand3ShowStderr": false, | ||
"outputDir": "", | ||
"outputFileExtension": "ambe", | ||
"createDailyAggregateFile": true, | ||
"mumble" : { | ||
"server": "mumble.example.com", | ||
"username": "DMR-bot", | ||
"password": "<mumble password>", | ||
"channel": "amateurradio", | ||
"fifo": "/tmp/audio.fifo" | ||
} | ||
} |
Submodule callrec
deleted from
6b2665
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
#!/usr/bin/env python2 | ||
|
||
from binascii import b2a_hex as ahex | ||
import sys | ||
from bitarray import bitarray | ||
from bitstring import BitArray | ||
from bitstring import BitString | ||
from datetime import datetime | ||
|
||
## | ||
# 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]) | ||
|
||
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 | ||
ambe_fr[rY[y]][rZ[z]] = bit0 | ||
|
||
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 | ||
|
||
if __name__ == '__main__': | ||
for line in iter(sys.stdin.readline, b''): | ||
line = line.rstrip() | ||
parts = [line[:2*9], line[2*9:4*9], line[4*9:]] | ||
for part in parts: | ||
try: | ||
print(ahex(convert72BitTo49BitAMBE(BitArray("0x" + part)))) | ||
except: | ||
pass | ||
sys.stdout.flush() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#!/usr/bin/python3 | ||
|
||
import sys | ||
while True: | ||
inp = sys.stdin.buffer.read(27) | ||
if not inp: | ||
# raise ValueError("input empty") | ||
sys.exit() | ||
if len(inp) != 27: | ||
raise ValueError(f"incorrect len {len(inp)}") | ||
print("".join(f"{b:02x}" for b in inp), flush=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
require 'mumble-ruby' | ||
require 'json' | ||
|
||
json_from_file = File.read('config.json') | ||
config = JSON.parse(json_from_file)['mumble'] | ||
|
||
Mumble.configure do |conf| | ||
# sample rate of sound (48 khz recommended) | ||
conf.sample_rate = 48000 | ||
|
||
# bitrate of sound (32 kbit/s recommended) | ||
conf.bitrate = 32000 | ||
|
||
# directory to store user's ssl certs | ||
conf.ssl_cert_opts[:cert_dir] = File.expand_path("./certs/") | ||
end | ||
|
||
# Create client instance for your server | ||
cli = Mumble::Client.new(config['server']) do |conf| | ||
conf.username = config['username'] | ||
conf.password = config['password'] | ||
end | ||
|
||
cli.connect() | ||
while cli.channels.empty? do | ||
sleep 1 | ||
puts "waiting until fully connected" | ||
end | ||
cli.join_channel(config['channel']) | ||
cli.player.stream_named_pipe(config['fifo']) | ||
|
||
while true do | ||
sleep 5 | ||
end |
Oops, something went wrong.
a8e5afb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have something better. feel free to contact me on telegram ;)
a8e5afb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stefansaraev I don't have telegram anymore, but am curious. Would you mind sending me an email instead? My contact details are on https://redfast00.github.io/about/