package common import ( "bytes" "math/rand" "git.cheetah.cat/cheetah/opentetraflex-go/common/tmkind" ) func NextHandlerID() uint32 { return uint32(rand.Int()) } type TerminalMessage struct { length uint16 kind tmkind.TetraFlexTerminalMessageKinds handler uint32 data bytes.Buffer } func NewTerminalMessage(length uint16, kind tmkind.TetraFlexTerminalMessageKinds, handler uint32) (tm *TerminalMessage, err error) { tm = &TerminalMessage{ length: length, kind: kind, handler: handler, } if err = tm.WriteShort(length); err != nil { return nil, err } if err = tm.WriteShort(uint16(kind)); err != nil { return nil, err } if err = tm.WriteUInt(handler); err != nil { return nil, err } return tm, nil } func (tm *TerminalMessage) WriteShort(data uint16) (err error) { _, err = tm.data.Write(uint16ToBytes(data)) return err } func (tm *TerminalMessage) WriteUInt(data uint32) (err error) { _, err = tm.data.Write(uint32ToBytes(data)) return err } func (tm *TerminalMessage) WriteByte(data byte) (err error) { return tm.data.WriteByte(data) } func (tm *TerminalMessage) WriteBytes(data []byte, count int) (err error) { bytes := make([]byte, count) copy(bytes, data) _, err = tm.data.Write(bytes) return err } func (tm *TerminalMessage) WriteString(text string, len int) (err error) { bytes := make([]byte, len) copy(bytes, text) _, err = tm.data.Write(bytes) return err } func (tm *TerminalMessage) WriteTFAddress(addr TetraFlexAddress) (err error) { if err = tm.data.WriteByte(byte(addr.Kind)); err != nil { return err } var ( text string num1 uint32 num2, num3 uint16 num4 byte ) if len(addr.UserNo) > 0 { text = addr.UserNo } if addr.TSI.IsValid() { num1 = addr.TSI.SSI num2 = addr.TSI.MNC num3 = addr.TSI.MCC } if err = tm.FillZero(3); err != nil { return err } if err = tm.WriteUInt(num1); err != nil { return err } if err = tm.WriteShort(num2); err != nil { return err } if err = tm.WriteShort(num3); err != nil { return err } num4 = byte(len(text)) if num4 > 24 { num4 = 24 } // this.#c.Write((byte)num4); if err = tm.data.WriteByte(num4); err != nil { return err } // this.#c.Write(0); 3x if err = tm.FillZero(3); err != nil { return err } if err = tm.WriteString(text, 24); err != nil { return err } /* AddressType kind = #LBc.Kind; string text = #i.#f.#8q(473); uint num = 0U; ushort num2 = 0; ushort num3 = 0; if (#LBc.#v6c()) { text = #LBc.UserNumber.Number; } if (#LBc.#x6c()) { num = #LBc.TSI.SSI; num2 = #LBc.TSI.MNC; num3 = #LBc.TSI.MCC; } this.#c.Write((byte)kind); this.#c.Write(num); this.#c.Write(num2); this.#c.Write(num3); uint num4 = (uint)text.Length; if (num4 > 24U) { num4 = 24U; } this.#c.Write((byte)num4); this.#c.Write(0); this.#c.Write(0); this.#c.Write(0); for (uint num5 = 0U; num5 < num4; num5 += 1U) { this.#c.Write((byte)text[(int)num5]); } for (uint num6 = num4; num6 < 24U; num6 += 1U) { this.#c.Write(0); } */ //return tm.data.WriteByte(data) return nil } func (tm *TerminalMessage) WriteIdentityInfoAddress(identityInfo TetraFlexIdentityInfo) (err error) { return tm.WriteTFAddress(identityInfo.Address) } func (tm *TerminalMessage) WriteIdentityInfoKind(identityInfo TetraFlexIdentityInfo) (err error) { /* case TetraFlexIdentityKind.Mobile: case TetraFlexIdentityKind.Group: case TetraFlexIdentityKind.DMRRADIO: case TetraFlexIdentityKind.Application: case TetraFlexIdentityKind.DialInUser: case TetraFlexIdentityKind.EmergencyNumber: case TetraFlexIdentityKind.Terminal: case TetraFlexIdentityKind.Personal: */ return tm.data.WriteByte(byte(identityInfo.Kind)) } func (tm *TerminalMessage) WriteIdentityInfoUnfied(identityInfo TetraFlexIdentityInfo) (err error) { byteVal := byte(0) if identityInfo.Kind == IdentityKindPersonal { byteVal = byte(UnifiedKindPersonalNumber) } return tm.data.WriteByte(byteVal) } func (tm *TerminalMessage) FillZero(zeroCount uint32) (err error) { _, err = tm.data.Write(make([]byte, zeroCount)) return err } func (tm *TerminalMessage) Encode() []byte { return tm.data.Bytes() } func NewTMAuthReq(addr TetraFlexAddress, num uint32, randomBytes []byte, terminalTypeID byte, terminalTypeStr string, terminalVersionDate uint32, terminalVersionStr string) (tm *TerminalMessage, err error) { tfAuthReq, err := NewTerminalMessage(256, tmkind.IpApiRegistrationRequest, NextHandlerID()) if err != nil { return nil, err } if err = tfAuthReq.WriteUInt(20140604); err != nil { return nil, err } if err = tfAuthReq.WriteTFAddress(addr); err != nil { return nil, err } if err = tfAuthReq.WriteByte(10); err != nil { return nil, err } if err = tfAuthReq.WriteByte(10); err != nil { return nil, err } if err = tfAuthReq.WriteByte(0); err != nil { return nil, err } if err = tfAuthReq.WriteByte(terminalTypeID); err != nil { return nil, err } if err = tfAuthReq.WriteUInt(num); err != nil { return nil, err } if err = tfAuthReq.WriteString(terminalTypeStr, 16); err != nil { return nil, err } if err = tfAuthReq.WriteString(terminalVersionStr, 16); err != nil { return nil, err } if err = tfAuthReq.WriteBytes(randomBytes, 10); err != nil { return nil, err } if err = tfAuthReq.FillZero(2); err != nil { return nil, err } if err = tfAuthReq.WriteUInt(terminalVersionDate); err != nil { return nil, err } if err = tfAuthReq.FillZero(148); err != nil { return nil, err } return tfAuthReq, nil } func NewTMKeepAliveResponse(challenge KeepAliveChallenge) (tm *TerminalMessage, err error) { response := KeepAliveResponse{} terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiKeepAliveResponse, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.FillZero(8); err != nil { return nil, err } if err = terminalMessage.WriteUInt(uint32(response.GPSLatitude)); err != nil { return nil, err } if err = terminalMessage.WriteUInt(uint32(response.GPSLongitude)); err != nil { return nil, err } if err = terminalMessage.WriteShort(response.Value3); err != nil { return nil, err } if err = terminalMessage.WriteShort(response.Value4); err != nil { return nil, err } if err = terminalMessage.WriteUInt(response.GPSTime); err != nil { return nil, err } if err = terminalMessage.WriteUInt(response.Accuracy); err != nil { return nil, err } if err = terminalMessage.FillZero(28); err != nil { return nil, err } return terminalMessage, nil } func NewTMNotificationRequest(messageTypes []tmkind.TetraFlexTerminalMessageKinds) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(128, tmkind.IpApiNotificationRequest, NextHandlerID()) if err != nil { return nil, err } // IpApiNotificationRequest if err = terminalMessage.WriteShort(uint16(len(messageTypes))); err != nil { return nil, err } if err = terminalMessage.FillZero(2); err != nil { return nil, err } for i := range messageTypes { if err = terminalMessage.WriteShort(uint16(messageTypes[i])); err != nil { return nil, err } } for i := len(messageTypes); i < 32; i++ { if err = terminalMessage.WriteShort(0); err != nil { return nil, err } } /* if err = terminalMessage.FillZero(uint32(2 * (32 - len(messageTypes)))); err != nil { return nil, err }*/ if err = terminalMessage.FillZero(52); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiGroupAttachRequest(groupConfig []GroupConfig) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(384, tmkind.IpApiGroupAttachRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.FillZero(4); err != nil { return nil, err } for _, group := range groupConfig { if err = terminalMessage.WriteTFAddress(*group.Group); err != nil { return nil, err } } for i := 0; i < 8-len(groupConfig); i++ { if err = terminalMessage.WriteTFAddress(TetraFlexAddressEmpty); err != nil { return nil, err } } if err = terminalMessage.FillZero(52); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiCallConnectRequest(callRef byte) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiCallConnectRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteByte(callRef); err != nil { return nil, err } //Fill 55 if err = terminalMessage.FillZero(55); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiSoftwareInfoRequest(ref byte) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiSoftwareInfoRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteByte(ref); err != nil { return nil, err } //Fill 55 if err = terminalMessage.FillZero(55); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiSubscriberInfoRequest(address TetraFlexAddress) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiSubscriberInfoRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteTFAddress(address); err != nil { return nil, err } if err = terminalMessage.FillZero(16); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiCallSetupRequest(address TetraFlexAddress, callType TetraFlexCallTypes, callPriority TetraFlexCallPriorities, hookCall bool, identityInfo TetraFlexIdentityInfo) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(192, tmkind.IpApiCallSetupRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteByte(byte(callType)); err != nil { return nil, err } if err = terminalMessage.FillZero(1); err != nil { return nil, err } if err = terminalMessage.WriteByte(byte(callPriority)); err != nil { return nil, err } if hookCall { if err = terminalMessage.WriteByte(4); err != nil { return nil, err } } else { if err = terminalMessage.WriteByte(0); err != nil { return nil, err } } if err = terminalMessage.WriteTFAddress(address); err != nil { return nil, err } //WriteIdentityInfoAddress if err = terminalMessage.WriteIdentityInfoAddress(identityInfo); err != nil { return nil, err } //WriteIdentityInfoDescr (protoHelper1:334) if err = terminalMessage.WriteString(identityInfo.Description, 64); err != nil { return nil, err } //WriteIdentityInfoKind if err = terminalMessage.WriteIdentityInfoKind(identityInfo); err != nil { return nil, err } //WriteByte 0 if err = terminalMessage.WriteByte(0); err != nil { return nil, err } //WriteIdentityInfoUnfied () if err = terminalMessage.WriteIdentityInfoUnfied(identityInfo); err != nil { return nil, err } //Fill 33 if err = terminalMessage.FillZero(33); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiCallStreamRequest(uint1 uint, callRef byte, streamRef byte, audioChannelType TetraFlexAudioChannelTypes) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiCallStreamRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteByte(callRef); err != nil { return nil, err } if audioChannelType < AudioChannel_CMoIP_uLaw { switch audioChannelType { case AudioChannel_RTP_uLaw: if err = terminalMessage.WriteByte(1); err != nil { return nil, err } if err = terminalMessage.WriteByte(0); err != nil { return nil, err } case AudioChannel_RTP_aLaw: if err = terminalMessage.WriteByte(1); err != nil { return nil, err } if err = terminalMessage.WriteByte(8); err != nil { return nil, err } default: if audioChannelType == AudioChannel_CMoIP_uLaw { if err = terminalMessage.WriteByte(2); err != nil { return nil, err } if err = terminalMessage.WriteByte(16); err != nil { return nil, err } } } } else { if audioChannelType == AudioChannel_CMoIP_aLaw { if err = terminalMessage.WriteByte(2); err != nil { return nil, err } if err = terminalMessage.WriteByte(1); err != nil { return nil, err } } if audioChannelType == AudioChannel_CMoIP_Tetra { if err = terminalMessage.WriteByte(2); err != nil { return nil, err } if err = terminalMessage.WriteByte(2); err != nil { return nil, err } } } if err = terminalMessage.WriteByte(streamRef); err != nil { return nil, err } //Fill 52 if err = terminalMessage.FillZero(52); err != nil { return nil, err } return terminalMessage, nil } func NewTMIpApiCallPTTRequest(callRef byte, identityInfo TetraFlexIdentityInfo, octaStateByte byte) (tm *TerminalMessage, err error) { terminalMessage, err := NewTerminalMessage(128, tmkind.IpApiCallPttRequest, NextHandlerID()) if err != nil { return nil, err } if err = terminalMessage.WriteByte(callRef); err != nil { return nil, err } if err = terminalMessage.WriteByte(octaStateByte); err != nil { return nil, err } if err = terminalMessage.FillZero(2); err != nil { return nil, err } //WriteIdentityInfoAddress if err = terminalMessage.WriteIdentityInfoAddress(identityInfo); err != nil { return nil, err } //WriteIdentityInfoDescr (protoHelper1:334) if err = terminalMessage.WriteString(identityInfo.Description, 64); err != nil { return nil, err } //WriteIdentityInfoKind if err = terminalMessage.WriteIdentityInfoKind(identityInfo); err != nil { return nil, err } //WriteIdentityInfoUnfied () if err = terminalMessage.WriteIdentityInfoUnfied(identityInfo); err != nil { return nil, err } if err = terminalMessage.FillZero(10); err != nil { return nil, err } return terminalMessage, nil }