Skip to content

Instantly share code, notes, and snippets.

@tehmaze
Last active February 24, 2017 01:28
Show Gist options
  • Save tehmaze/e92a096c7e067b76a4d1c9a4bf62c0bd to your computer and use it in GitHub Desktop.
Save tehmaze/e92a096c7e067b76a4d1c9a4bf62c0bd to your computer and use it in GitHub Desktop.
talker alias stuff
package session
import (
"strings"
"dmr"
"golang.org/x/text/encoding/unicode"
)
var (
talkerAliasBlocks = [][]uint8{
[]uint8{7, 15, 23, 31},
[]uint8{6, 13, 20, 27},
[]uint8{6, 13, 20, 27},
[]uint8{3, 6, 10, 13},
}
zeroRaw dmr.Raw
)
type talkerAlias struct {
format uint8
length uint8
blocks uint8
text [28]byte
}
func (ta *talkerAlias) Decode(meta *dmr.Meta) (string, bool) {
if fid := meta.Raw[1]; fid != 0 {
logger.Debugf("skip embedded data, not ETSI FID; got %#06b", fid)
return "", false
}
//logger.Debugf("embedded data flco=%s", dmr.FLCO(meta.Raw[0]&0x7f))
switch flco := dmr.FLCO(meta.Raw[0] & 0x7f); flco {
case dmr.TalkerAliasHeaderValue:
// byte 0: code
// byte 1: feature
// byte 2: options
// byte 3-9: data
ta.format = (meta.Raw[2] >> 6) & 0x03
ta.length = (meta.Raw[2] >> 1) & 0x1f
copy(ta.text[:], zeroRaw[:])
copy(ta.text[1:], meta.Raw[3:9])
if ta.length <= talkerAliasBlocks[ta.format][0] {
return ta.decodeString()
}
case dmr.TalkerAliasBlock1Value, dmr.TalkerAliasBlock2Value, dmr.TalkerAliasBlock3Value:
// byte 0: code
// byte 1: feature
// bute 2-9: data
block := uint8(flco - dmr.TalkerAliasHeaderValue)
copy(ta.text[7*block:], meta.Raw[2:9])
if ta.length <= talkerAliasBlocks[ta.format][block] {
return ta.decodeString()
}
default:
}
return "", false
}
// Character encodings
var (
utf8 = unicode.UTF8
utf8Decoder = utf8.NewDecoder()
utf16be = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
utf16beDecoder = utf16be.NewDecoder()
)
func (ta *talkerAlias) decodeString() (s string, ok bool) {
switch ta.format {
case 0x00: // US-ASCII 7-bit
var data = make([]byte, 32)
for i := 0; i < 4; i++ {
decode7bit(data[i*8:], ta.text[i*7:])
}
s = string(data[1:])
case 0x01: // US-ASCII 8-bit
var data = make([]rune, ta.length)
for i := range data {
data[i] = rune(ta.text[i+1])
}
s = string(data)
case 0x02: // UTF-8
s, _ = utf8Decoder.String(string(ta.text[1:]))
case 0x03: // UTF-16BE
s, _ = utf16beDecoder.String(string(ta.text[1:]))
default:
return
}
// Cleanup cruft left by cheap radios. Some radios re-use the talker alias
// internal buffer without clearing the old buffer. Thank you China.
return strings.SplitN(strings.TrimRight(s, " "), "\x00", 2)[0], true
}
// decode7bit decodes a block of 7-bit bytes to 8-bit bytes in chunks of 7
func decode7bit(dst, src []byte) {
dst[0] |= (src[0]>>1)&0x7f | 0
dst[1] |= (src[0]<<6)&0x40 | (src[1]>>2)&0x3f
dst[2] |= (src[1]<<5)&0x60 | (src[2]>>3)&0x1f
dst[3] |= (src[2]<<4)&0x70 | (src[3]>>4)&0x0f
dst[4] |= (src[3]<<3)&0x78 | (src[4]>>5)&0x07
dst[5] |= (src[4]<<2)&0x7c | (src[5]>>6)&0x03
dst[6] |= (src[5]<<1)&0x7e | (src[6]>>7)&0x01
dst[7] |= (src[6]<<0)&0x7f | 0
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment