package repeater import ( "fmt" "log" "time" "github.com/tehmaze/go-dmr/bit" "github.com/tehmaze/go-dmr/ipsc" ) const ( Idle uint8 = iota VoiceCallRunning DataCallRunning ) type SlotData struct { BlocksReceived uint8 BlocksExpected uint8 PacketHeaderValid bool } type SlotVoice struct { // Last frame number Frame uint8 } type Slot struct { State uint8 LastCallReceived time.Time CallStart time.Time CallEnd time.Time CallType uint8 SrcID, DstID uint32 Data SlotData Voice SlotVoice LastSequence uint8 LastSlotType uint16 } type Repeater struct { Slot []*Slot DataFrameFunc func(*ipsc.Packet, bit.Bits) VoiceFrameFunc func(*ipsc.Packet, bit.Bits) } func New() *Repeater { r := &Repeater{ Slot: make([]*Slot, 2), } r.Slot[0] = &Slot{} r.Slot[1] = &Slot{} return r } func (r *Repeater) DataCallEnd(p *ipsc.Packet) { if p.Timeslot > 1 { return } slot := r.Slot[p.Timeslot] if slot.State != DataCallRunning { return } log.Printf("dmr/repeater: data call ended on TS%d, %d -> %d\n", p.Timeslot+1, slot.SrcID, slot.DstID) slot.State = Idle slot.CallEnd = time.Now() slot.Data.PacketHeaderValid = false } func (r *Repeater) VoiceCallStart(p *ipsc.Packet) { if p.Timeslot > 1 { return } slot := r.Slot[p.Timeslot] if slot.State == VoiceCallRunning { r.VoiceCallEnd(p) } log.Printf("dmr/repeater: voice call started on TS%d, %d -> %d\n", p.Timeslot+1, slot.SrcID, slot.DstID) slot.CallStart = time.Now() slot.CallType = p.CallType slot.SrcID = p.SrcID slot.DstID = p.DstID slot.State = VoiceCallRunning } func (r *Repeater) VoiceCallEnd(p *ipsc.Packet) { if p.Timeslot > 1 { return } slot := r.Slot[p.Timeslot] if slot.State != VoiceCallRunning { return } log.Printf("dmr/repeater: voice call ended on TS%d, %d -> %d\n", p.Timeslot+1, slot.SrcID, slot.DstID) slot.State = Idle slot.CallEnd = time.Now() } func (r *Repeater) Stream(p *ipsc.Packet) { // Kill errneous timeslots here if p.Timeslot > 1 { log.Printf("killed packet with timeslot %d\n", p.Timeslot) return } if p.Sequence == r.Slot[p.Timeslot].LastSequence { return } r.Slot[p.Timeslot].LastSequence = p.Sequence var err error fmt.Printf("ts%d/dmr[%03d] [%d->%d]: %s: ", p.Timeslot+1, p.Sequence, p.SrcID, p.DstID, ipsc.SlotTypeName[p.SlotType]) switch p.SlotType { case ipsc.VoiceLCHeader: err = r.HandleVoiceLCHeader(p) case ipsc.TerminatorWithLC: err = r.HandleTerminatorWithLC(p) case ipsc.DataHeader: err = r.HandleDataHeader(p) case ipsc.VoiceDataA, ipsc.VoiceDataB, ipsc.VoiceDataC, ipsc.VoiceDataD, ipsc.VoiceDataE, ipsc.VoiceDataF: // De-duplicate packets, since we could run in merged TS1/2 mode if r.Slot[p.Timeslot].LastSlotType == p.SlotType { fmt.Println("(ignored)") } else { err = r.HandleVoiceData(p) } r.Slot[p.Timeslot].LastSlotType = p.SlotType default: fmt.Println("unhandled") } if err != nil { fmt.Printf("error: %v\n", err) } }