|
|
package dmr
|
|
|
|
|
|
// Data Type information element definitions, DMR Air Interface (AI) protocol, Table 6.1
|
|
|
const (
|
|
|
PrivacyIndicator uint8 = iota // Privacy Indicator information in a standalone burst
|
|
|
VoiceLC // Indicates the beginning of voice transmission, carries addressing information
|
|
|
TerminatorWithLC // Indicates the end of transmission, carries LC information
|
|
|
CSBK // Carries a control block
|
|
|
MultiBlockControl // Header for multi-block control
|
|
|
MultiBlockControlContinuation // Follow-on blocks for multi-block control
|
|
|
Data // Carries addressing and numbering of packet data blocks
|
|
|
Rate12Data // Payload for rate 1/2 packet data
|
|
|
Rate34Data // Payload for rate 3⁄4 packet data
|
|
|
Idle // Fills channel when no info to transmit
|
|
|
VoiceBurstA // Burst A marks the start of a superframe and always contains a voice SYNC pattern
|
|
|
VoiceBurstB // Bursts B to F carry embedded signalling in place of the SYNC pattern
|
|
|
VoiceBurstC // Bursts B to F carry embedded signalling in place of the SYNC pattern
|
|
|
VoiceBurstD // Bursts B to F carry embedded signalling in place of the SYNC pattern
|
|
|
VoiceBurstE // Bursts B to F carry embedded signalling in place of the SYNC pattern
|
|
|
VoiceBurstF // Bursts B to F carry embedded signalling in place of the SYNC pattern
|
|
|
IPSCSync
|
|
|
UnknownSlotType
|
|
|
)
|
|
|
|
|
|
var DataTypeName = map[uint8]string{
|
|
|
PrivacyIndicator: "privacy indicator",
|
|
|
VoiceLC: "voice LC",
|
|
|
TerminatorWithLC: "terminator with LC",
|
|
|
CSBK: "control block",
|
|
|
MultiBlockControl: "multi-block control",
|
|
|
MultiBlockControlContinuation: "multi-block control follow-on",
|
|
|
Data: "data",
|
|
|
Rate12Data: "rate ½ packet data",
|
|
|
Rate34Data: "rate ¾ packet data",
|
|
|
Idle: "idle",
|
|
|
VoiceBurstA: "voice (burst A)",
|
|
|
VoiceBurstB: "voice (burst B)",
|
|
|
VoiceBurstC: "voice (burst C)",
|
|
|
VoiceBurstD: "voice (burst D)",
|
|
|
VoiceBurstE: "voice (burst E)",
|
|
|
VoiceBurstF: "voice (burst F)",
|
|
|
IPSCSync: "IPSC sync",
|
|
|
UnknownSlotType: "uknown",
|
|
|
}
|
|
|
|
|
|
// Call Type
|
|
|
const (
|
|
|
CallTypePrivate uint8 = iota
|
|
|
CallTypeGroup
|
|
|
)
|
|
|
|
|
|
// Packet represents a frame transported by the Air Interface
|
|
|
type Packet struct {
|
|
|
// 0 for slot 1, 1 for slot 2
|
|
|
Timeslot uint8
|
|
|
|
|
|
// Starts at zero for each incoming transmission, wraps back to zero when 256 is reached
|
|
|
Sequence uint8
|
|
|
|
|
|
// Source and destination DMR ID
|
|
|
SrcID uint32
|
|
|
DstID uint32
|
|
|
|
|
|
// 3 bytes registered DMR-ID for public repeaters, 4 bytes for private repeaters
|
|
|
RepeaterID uint32
|
|
|
|
|
|
// Random or incremented number which stays the same from PTT-press to PTT-release which identifies a stream
|
|
|
StreamID uint32
|
|
|
|
|
|
// Data Type or Slot type
|
|
|
DataType uint8
|
|
|
|
|
|
// 0 for group call, 1 for unit to unit
|
|
|
CallType uint8
|
|
|
|
|
|
// The on-air DMR data with possible FEC fixes to the AMBE data and/or Slot Type and/or EMB, etc
|
|
|
Data []byte // 34 bytes
|
|
|
Bits []byte // 264 bits
|
|
|
}
|
|
|
|
|
|
// EMBBits returns the frame EMB bits from the SYNC bits
|
|
|
func (p *Packet) EMBBits() []byte {
|
|
|
var (
|
|
|
b = make([]byte, EMBBits)
|
|
|
o = EMBHalfBits + EMBSignallingLCFragmentBits
|
|
|
sync = p.SyncBits()
|
|
|
)
|
|
|
copy(b[:EMBHalfBits], sync[:EMBHalfBits])
|
|
|
copy(b[EMBHalfBits:], sync[o:o+EMBHalfBits])
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
// InfoBits returns the frame Info bits
|
|
|
func (p *Packet) InfoBits() []byte {
|
|
|
var b = make([]byte, InfoBits)
|
|
|
copy(b[0:InfoHalfBits], p.Bits[0:InfoHalfBits])
|
|
|
copy(b[InfoHalfBits:], p.Bits[InfoHalfBits+SlotTypeBits+SignalBits:])
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
// SyncBits returns the frame SYNC bits
|
|
|
func (p *Packet) SyncBits() []byte {
|
|
|
return p.Bits[SyncOffsetBits : SyncOffsetBits+SyncBits]
|
|
|
}
|
|
|
|
|
|
// SlotType returns the frame Slot Type parsed from the Slot Type bits
|
|
|
func (p *Packet) SlotType() []byte {
|
|
|
return BitsToBytes(p.SlotTypeBits())
|
|
|
}
|
|
|
|
|
|
// SlotTypeBits returns the SloT Type bits
|
|
|
func (p *Packet) SlotTypeBits() []byte {
|
|
|
var o = InfoHalfBits + SlotTypeHalfBits + SyncBits
|
|
|
return append(p.Bits[InfoHalfBits:InfoHalfBits+SlotTypeHalfBits], p.Bits[o:o+SlotTypeHalfBits]...)
|
|
|
}
|
|
|
|
|
|
// VoiceBits returns the bits containing voice data
|
|
|
func (p *Packet) VoiceBits() []byte {
|
|
|
var b = make([]byte, VoiceBits)
|
|
|
copy(b[:VoiceHalfBits], p.Bits[:VoiceHalfBits])
|
|
|
copy(b[VoiceHalfBits:], p.Bits[VoiceHalfBits+SignalBits:])
|
|
|
return b
|
|
|
}
|
|
|
|
|
|
func (p *Packet) SetData(data []byte) {
|
|
|
p.Data = data
|
|
|
p.Bits = BytesToBits(data)
|
|
|
}
|
|
|
|
|
|
// PacketFunc is a callback function that handles DMR packets
|
|
|
type PacketFunc func(Repeater, *Packet) error
|