commit 7ad747c43ae22c29c6909684c9048028af1941b8 Author: cheetah Date: Sat Sep 9 13:11:04 2023 +0000 first commit diff --git a/_exmaples/test.txt b/_exmaples/test.txt new file mode 100644 index 0000000..2d7dc91 --- /dev/null +++ b/_exmaples/test.txt @@ -0,0 +1,112 @@ +{ + "packets": [ + { + "payload": [ + 1,0,0,0,235,3,0,0,232,3,238,0,4,0,0,0,49,48,48,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,40,0,1,77,101,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 40, + "payloadSize": 448, + "kind": 9233 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 40, + "payloadSize": 20, + "kind": 1 + },{ + "payload": [ + 48,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 15, + "payloadSize": 64, + "kind": 1553 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 15, + "payloadSize": 64, + "kind": 1554 + },{ + "payload": [ + 1,0,0,0,235,3,0,0,232,3,238,0,4,0,0,0,49,48,48,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,176,0,1,66,114,104,101,104,101,104,101,104,101,104,117,101,117,101,117,101,117,101,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 41, + "payloadSize": 448, + "kind": 9233 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 41, + "payloadSize": 20, + "kind": 1 + },{ + "payload": [ + 48,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 16, + "payloadSize": 64, + "kind": 1553 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 16, + "payloadSize": 64, + "kind": 1554 + },{ + "payload": [ + 48,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 17, + "payloadSize": 64, + "kind": 1553 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 17, + "payloadSize": 64, + "kind": 1554 + },{ + "payload": [ + 48,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 18, + "payloadSize": 64, + "kind": 1553 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 18, + "payloadSize": 64, + "kind": 1554 + },{ + "payload": [ + 48,0,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 19, + "payloadSize": 64, + "kind": 1553 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 19, + "payloadSize": 64, + "kind": 1554 + },{ + "payload": [ + 1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,49,48,48,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,3,1,2,1,2,1,65,98,99,100,101,102,103,104,106,105,106,108,109,110,105,112,113,114,97,116,117,118,119,120,121,122,49,50,51,51,52,52,56,50,56,51,56,51,56,51,55,51,55,51,55,55,51,55,55,51,51,55,51,51,55,51,55,51,55,51,65,98,99,100,101,102,103,104,106,105,106,108,109,110,105,112,113,114,97,116,117,118,119,120,121,122,49,50,51,51,52,52,56,50,56,51,56,51,56,51,55,51,55,51,55,55,51,55,55,51,51,55,51,51,55,51,55,51,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 42, + "payloadSize": 448, + "kind": 9233 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 42, + "payloadSize": 20, + "kind": 1 + },{ + "payload": [ + 1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,49,48,48,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,3,1,2,2,51,65,98,99,100,101,102,103,104,106,105,106,108,109,110,105,112,113,114,97,116,117,118,119,120,121,122,49,50,51,51,52,52,56,50,56,51,56,51,56,51,55,51,55,51,55,55,51,55,55,51,51,55,51,51,55,51,55,51,55,51,65,98,99,100,101,102,103,104,106,105,106,108,109,110,105,112,113,114,97,116,117,118,119,120,121,122,49,50,51,51,52,52,56,50,56,51,56,51,56,51,55,51,55,51,55,55,51,55,55,51,51,55,51,51,55,51,55,51,55,51,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 43, + "payloadSize": 448, + "kind": 9233 + },{ + "payload": [ + 0,0,0,0,0,0,0,0,0,0,0,0], + "handler": 43, + "payloadSize": 20, + "kind": 1 + }] +} \ No newline at end of file diff --git a/common/address.go b/common/address.go new file mode 100644 index 0000000..f20f35b --- /dev/null +++ b/common/address.go @@ -0,0 +1,57 @@ +package common + +type NetIdentity struct { + SSI uint32 + MNC uint16 + MCC uint16 +} + +func (identity *NetIdentity) IsValid() bool { + return identity.SSI > 0 +} + +type TetraFlexAddressKind byte + +const ( + SSI TetraFlexAddressKind = 0 + UserNo TetraFlexAddressKind = 1 +) + +type TetraFlexAddress struct { + Kind TetraFlexAddressKind + UserNo string + TSI NetIdentity +} + +func NewAddress() (addr *TetraFlexAddress) { + return &TetraFlexAddress{ + Kind: SSI, + UserNo: "", + TSI: NetIdentity{ + SSI: 0, + MNC: 0, + MCC: 0, + }, + } +} +func NewAddressFromSSINumber(ssi uint16) (addr *TetraFlexAddress) { + return &TetraFlexAddress{ + Kind: SSI, + UserNo: "", + TSI: NetIdentity{ + SSI: uint32(ssi), + MNC: 0, + MCC: 0, + }, + } +} + +var TetraFlexAddressEmpty = TetraFlexAddress{ + Kind: SSI, + UserNo: "", + TSI: NetIdentity{ + SSI: 0, + MNC: 0, + MCC: 0, + }, +} diff --git a/common/audiochanneltypes.go b/common/audiochanneltypes.go new file mode 100644 index 0000000..fb1bb3b --- /dev/null +++ b/common/audiochanneltypes.go @@ -0,0 +1,11 @@ +package common + +type TetraFlexAudioChannelTypes byte + +const ( + AudioChannel_RTP_uLaw TetraFlexAudioChannelTypes = 1 + AudioChannel_RTP_aLaw TetraFlexAudioChannelTypes = 2 + AudioChannel_CMoIP_uLaw TetraFlexAudioChannelTypes = 16 + AudioChannel_CMoIP_aLaw TetraFlexAudioChannelTypes = 32 + AudioChannel_CMoIP_Tetra TetraFlexAudioChannelTypes = 64 +) diff --git a/common/auth.go b/common/auth.go new file mode 100644 index 0000000..5801015 --- /dev/null +++ b/common/auth.go @@ -0,0 +1,9 @@ +package common + +type AuthenticationChallenge struct { + RandomSeed []byte + RandomChallenge []byte + Response []byte + PinRequested bool + SecurityKeyRequested bool +} diff --git a/common/calltypes.go b/common/calltypes.go new file mode 100644 index 0000000..46288a2 --- /dev/null +++ b/common/calltypes.go @@ -0,0 +1,37 @@ +package common + +type TetraFlexCallTypes byte + +const ( + CallTypeIndividualDuplex TetraFlexCallTypes = 0 + CallTypeIndividualSimplex TetraFlexCallTypes = 1 + CallTypeGroup TetraFlexCallTypes = 2 + CallTypeBroadcast TetraFlexCallTypes = 3 + CallTypeAmbience TetraFlexCallTypes = 4 +) + +type TetraFlexCallPriorities byte + +const ( + CallPriorityNotDefined TetraFlexCallPriorities = 0 + CallPriority1 TetraFlexCallPriorities = 1 + CallPriority2 TetraFlexCallPriorities = 2 + CallPriority3 TetraFlexCallPriorities = 3 + CallPriority4 TetraFlexCallPriorities = 4 + CallPriority5 TetraFlexCallPriorities = 5 + CallPriority6 TetraFlexCallPriorities = 6 + CallPriority7 TetraFlexCallPriorities = 7 + CallPriority8 TetraFlexCallPriorities = 8 + CallPriority9 TetraFlexCallPriorities = 9 + CallPriority10 TetraFlexCallPriorities = 10 + CallPriority11 TetraFlexCallPriorities = 11 + + CallPriorityPreEmptive1 TetraFlexCallPriorities = 12 + CallPriorityPreEmptive2 TetraFlexCallPriorities = 13 + CallPriorityPreEmptive3 TetraFlexCallPriorities = 14 + CallPriorityPreEmptive4 TetraFlexCallPriorities = 15 + CallPriorityPreEmptive5 TetraFlexCallPriorities = 16 + + CallPriorityDefault TetraFlexCallPriorities = 0 + CallPriorityEmergency TetraFlexCallPriorities = 15 +) diff --git a/common/groupscan.go b/common/groupscan.go new file mode 100644 index 0000000..fd1f56d --- /dev/null +++ b/common/groupscan.go @@ -0,0 +1,35 @@ +package common + +type AttachReasons uint16 + +const ( + AttachReasonPositions AttachReasons = 0 + AttachReasonPTT AttachReasons = 1 + AttachReasonScan AttachReasons = 2 +) + +type AttachedScanKind uint16 + +const ( + NotScanned AttachedScanKind = 0 + Selected AttachedScanKind = 1 + Scanned AttachedScanKind = 2 +) + +/* +// Token: 0x02000157 RID: 343 +public enum AttachedScanKind +{ + // Token: 0x040004E3 RID: 1251 + NotScanned, + // Token: 0x040004E4 RID: 1252 + Selected, + // Token: 0x040004E5 RID: 1253 + Scanned +} +*/ + +type GroupConfig struct { + Group *TetraFlexAddress + ScanMode AttachedScanKind +} diff --git a/common/helper.go b/common/helper.go new file mode 100644 index 0000000..09b85ea --- /dev/null +++ b/common/helper.go @@ -0,0 +1,9 @@ +package common + +func uint16ToBytes(n uint16) []byte { + return []byte{byte(n), byte(n >> 8)} +} + +func uint32ToBytes(n uint32) []byte { + return []byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} +} diff --git a/common/identity.go b/common/identity.go new file mode 100644 index 0000000..c4bb885 --- /dev/null +++ b/common/identity.go @@ -0,0 +1,42 @@ +package common + +type TetraFlexIdentityKind byte + +const ( + IdentityKindUnknown TetraFlexIdentityKind = 0x00 + IdentityKindMobile TetraFlexIdentityKind = 0x01 + IdentityKindGroup TetraFlexIdentityKind = 0x02 + IdentityKindDMRRadio TetraFlexIdentityKind = 0x03 + IdentityKindNumber TetraFlexIdentityKind = 0x04 + IdentityKindApplication TetraFlexIdentityKind = 0x05 + IdentityKindDialInUser TetraFlexIdentityKind = 0x06 + IdentityKindEmergencyNumber TetraFlexIdentityKind = 0x07 + IdentityKindTerminal TetraFlexIdentityKind = 0x08 + IdentityKindPersonal TetraFlexIdentityKind = 0x09 + IdentityKindSWMI TetraFlexIdentityKind = 0x3C + IdentityKindISDN TetraFlexIdentityKind = 0x3D + IdentityKindPABX TetraFlexIdentityKind = 0x3E + IdentityKindPSTN TetraFlexIdentityKind = 0x3F + IdentityKindAnonymous TetraFlexIdentityKind = 0x50 + IdentityKindExternal TetraFlexIdentityKind = 0x64 + IdentityKindExternalUnknown TetraFlexIdentityKind = 0x65 +) + +type TetraFlexUnifiedSSIKinds byte + +const ( + UnifiedKindUnifiedNumber TetraFlexUnifiedSSIKinds = 0x00 + UnifiedKindEmergencyNumber TetraFlexUnifiedSSIKinds = 0x01 + UnifiedKindPersonalNumber TetraFlexUnifiedSSIKinds = 0x02 + UnifiedKindMultiClient TetraFlexUnifiedSSIKinds = 0x03 + UnifiedKindExternalNumber TetraFlexUnifiedSSIKinds = 0x04 + UnifiedKindGSMPhone TetraFlexUnifiedSSIKinds = 0x05 + UnifiedKindPABXNumber TetraFlexUnifiedSSIKinds = 0x06 +) + +type TetraFlexIdentityInfo struct { + Description string + Kind TetraFlexIdentityKind + Address TetraFlexAddress + UnifiedSSIKinds TetraFlexUnifiedSSIKinds +} diff --git a/common/keepalive.go b/common/keepalive.go new file mode 100644 index 0000000..412a81d --- /dev/null +++ b/common/keepalive.go @@ -0,0 +1,15 @@ +package common + +type KeepAliveChallenge struct { + Value1 uint16 + Value2 uint16 + Value3 uint32 +} +type KeepAliveResponse struct { + GPSLatitude int32 + GPSLongitude int32 + Value3 uint16 + Value4 uint16 + Accuracy uint32 + GPSTime uint32 +} diff --git a/common/reginfo.go b/common/reginfo.go new file mode 100644 index 0000000..5a6a628 --- /dev/null +++ b/common/reginfo.go @@ -0,0 +1,14 @@ +package common + +type RegistrationInfo struct { + Address TetraFlexAddress + ConnectionState uint32 + RemoteVersion uint32 + MaxVersion uint32 + MyNumber uint32 + MyShortNumber uint32 + CallCount byte + StreamCount byte + RoamingRef uint32 + RTPPorts []uint16 +} diff --git a/common/terminalClient.go b/common/terminalClient.go new file mode 100644 index 0000000..0022449 --- /dev/null +++ b/common/terminalClient.go @@ -0,0 +1,91 @@ +package common + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "net" + "test/common/tmkind" +) + +type TerminalClient struct { + address string + conn net.Conn + netWriter *bufio.Writer + netReader *bufio.Reader + GroupConfig []GroupConfig + + HandlerMap map[uint32]chan any + + RX chan *TerminalMessageResponse +} + +func NewTerminalClient(address string) (tc *TerminalClient) { + return &TerminalClient{ + address: address, + RX: make(chan *TerminalMessageResponse), + } +} +func (tc *TerminalClient) Connect() (err error) { + tc.conn, err = net.Dial("tcp", tc.address) + if err != nil { + return err + } + tc.netWriter = bufio.NewWriter(tc.conn) + tc.netReader = bufio.NewReader(tc.conn) + go tc.rxLoop() + + return nil +} +func (tc *TerminalClient) Send(message *TerminalMessage) (err error) { + _, err = tc.netWriter.Write(message.Encode()) + if err != nil { + return err + } + err = tc.netWriter.Flush() + if err != nil { + return err + } + return nil +} +func (tc *TerminalClient) rxLoop() { + var err error + for { + dataHeader := make([]byte, 2) //2 bytes for uint16 + _, err = io.ReadFull(tc.netReader, dataHeader) + if err != nil { + panic(err) + } + payloadLength := binary.LittleEndian.Uint16(dataHeader) + fmt.Printf("length: %d bytes\n", payloadLength) + + kindData := make([]byte, 2) //2 bytes for uint16 + _, err = io.ReadFull(tc.netReader, kindData) + if err != nil { + panic(err) + } + messageKind := binary.LittleEndian.Uint16(kindData) + fmt.Printf("kind: %d\n", messageKind) + + handlerData := make([]byte, 4) //4 bytes for uint32 + _, err = io.ReadFull(tc.netReader, handlerData) + if err != nil { + panic(err) + } + messageHandler := binary.LittleEndian.Uint32(handlerData) + fmt.Printf("handler: %d\n", messageHandler) + + dataPayload := make([]byte, payloadLength-(2+2+4)) //8 bytes for header + _, err = io.ReadFull(tc.netReader, dataPayload) + if err != nil { + panic(err) + } + parsedResp, err := NewTerminalMessageResponse(payloadLength, tmkind.TetraFlexTerminalMessageKinds(messageKind), messageHandler, dataPayload) + if err != nil { + panic(err) + } + tc.RX <- parsedResp + + } +} diff --git a/common/terminalMessage.go b/common/terminalMessage.go new file mode 100644 index 0000000..fbe6180 --- /dev/null +++ b/common/terminalMessage.go @@ -0,0 +1,431 @@ +package common + +import ( + "bytes" + "test/common/tmkind" +) + +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, 0) + 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, 0) + 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, 0) + 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, 0) + 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 NewTMIpApiCallSetupRequest(address TetraFlexAddress, callType TetraFlexCallTypes, callPriority TetraFlexCallPriorities, idkBool bool, identityInfo TetraFlexIdentityInfo) (tm *TerminalMessage, err error) { + terminalMessage, err := NewTerminalMessage(192, tmkind.IpApiCallSetupRequest, 0) + 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 idkBool { + 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 NewTMSendIpApiCallStreamRequest(uint1 uint, callRef byte, streamRef byte, audioChannelType TetraFlexAudioChannelTypes) (tm *TerminalMessage, err error) { + terminalMessage, err := NewTerminalMessage(64, tmkind.IpApiCallStreamRequest, 0) + 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 +} diff --git a/common/terminalMessageResponse.go b/common/terminalMessageResponse.go new file mode 100644 index 0000000..24db724 --- /dev/null +++ b/common/terminalMessageResponse.go @@ -0,0 +1,205 @@ +package common + +import ( + "bytes" + "encoding/binary" + "test/common/tmkind" +) + +type TerminalMessageResponse struct { + Length uint16 + Kind tmkind.TetraFlexTerminalMessageKinds + Handler uint32 + + data bytes.Buffer + payload []byte +} + +func NewTerminalMessageResponse(length uint16, kind tmkind.TetraFlexTerminalMessageKinds, handler uint32, payload []byte) (tm *TerminalMessageResponse, err error) { + tm = &TerminalMessageResponse{ + Length: length, + Kind: kind, + Handler: handler, + data: *bytes.NewBuffer(payload), + payload: payload, + } + return tm, nil +} +func (tmr *TerminalMessageResponse) Bytes() []byte { + return tmr.payload +} + +func (tmr *TerminalMessageResponse) readUInt32() (result uint32, err error) { + temp := make([]byte, 4) + if _, err = tmr.data.Read(temp); err != nil { + return result, err + } + result = binary.LittleEndian.Uint32(temp) + return result, nil +} +func (tmr *TerminalMessageResponse) readUInt16() (result uint16, err error) { + temp := make([]byte, 2) + if _, err = tmr.data.Read(temp); err != nil { + return result, err + } + result = binary.LittleEndian.Uint16(temp) + return result, nil +} +func (tmr *TerminalMessageResponse) readByte() (result byte, err error) { + result, err = tmr.data.ReadByte() + return result, err +} +func (tmr *TerminalMessageResponse) skipByte() (err error) { + _, err = tmr.data.ReadByte() + return err +} +func (tmr *TerminalMessageResponse) skipBytes(count int) (err error) { + for i := 0; i < count; i++ { + _, err = tmr.data.ReadByte() + if err != nil { + return err + } + } + return nil +} +func (tmr *TerminalMessageResponse) readAddress() (result TetraFlexAddress, err error) { + kindByte, err := tmr.readByte() + if err != nil { + return result, err + } + result.Kind = TetraFlexAddressKind(kindByte) + if err = tmr.skipByte(); err != nil { + return result, err + } + if err = tmr.skipByte(); err != nil { + return result, err + } + if err = tmr.skipByte(); err != nil { + return result, err + } + + result.TSI.SSI, err = tmr.readUInt32() + if err != nil { + return result, err + } + result.TSI.MCC, err = tmr.readUInt16() + if err != nil { + return result, err + } + result.TSI.MCC, err = tmr.readUInt16() + if err != nil { + return result, err + } + textLength, err := tmr.readByte() + if err != nil { + return result, err + } + if err = tmr.skipByte(); err != nil { + return result, err + } + if err = tmr.skipByte(); err != nil { + return result, err + } + if err = tmr.skipByte(); err != nil { + return result, err + } + textBytes := make([]byte, textLength) + if _, err = tmr.data.Read(textBytes); err != nil { + return result, err + } + for i := textLength; i < 24; i++ { + if err = tmr.skipByte(); err != nil { + return result, err + } + } + + return result, nil +} + +func (tmr *TerminalMessageResponse) AsAuthenticationChallenge() (authChallenge AuthenticationChallenge, err error) { + authChallenge.RandomSeed = make([]byte, 10) + if _, err = tmr.data.Read(authChallenge.RandomSeed); err != nil { + return authChallenge, err + } + tmr.data.ReadByte() + tmr.data.ReadByte() + authChallenge.RandomChallenge = make([]byte, 10) + if _, err = tmr.data.Read(authChallenge.RandomChallenge); err != nil { + return authChallenge, err + } + flagByte, err := tmr.data.ReadByte() + if err != nil { + return authChallenge, err + } + authChallenge.PinRequested = flagByte&1 != 0 + authChallenge.SecurityKeyRequested = flagByte&2 != 0 + authChallenge.Response = make([]byte, 4) + if _, err = tmr.data.Read(authChallenge.Response); err != nil { + return authChallenge, err + } + + return authChallenge, nil +} +func (tmr *TerminalMessageResponse) AsRegistrationInfo() (regInfo RegistrationInfo, err error) { + + if regInfo.ConnectionState, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if regInfo.RemoteVersion, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if regInfo.Address, err = tmr.readAddress(); err != nil { + return regInfo, err + } + if regInfo.MyNumber, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if regInfo.MyShortNumber, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if err = tmr.skipBytes(4); err != nil { + return regInfo, err + } + if regInfo.CallCount, err = tmr.readByte(); err != nil { + return regInfo, err + } + if regInfo.StreamCount, err = tmr.readByte(); err != nil { + return regInfo, err + } + if err = tmr.skipBytes(2); err != nil { + return regInfo, err + } + if regInfo.MaxVersion, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if regInfo.RoamingRef, err = tmr.readUInt32(); err != nil { + return regInfo, err + } + if regInfo.RemoteVersion > 20120702 { + port1, err := tmr.readUInt16() + if err != nil { + return regInfo, err + } + port2, err := tmr.readUInt16() + if err != nil { + return regInfo, err + } + regInfo.RTPPorts = []uint16{port1, port2} + } + + return regInfo, nil +} + +func (tmr *TerminalMessageResponse) AsKeepAliveChallenge() (keepAliveChallenge KeepAliveChallenge, err error) { + if keepAliveChallenge.Value1, err = tmr.readUInt16(); err != nil { + return keepAliveChallenge, err + } + if keepAliveChallenge.Value2, err = tmr.readUInt16(); err != nil { + return keepAliveChallenge, err + } + if keepAliveChallenge.Value3, err = tmr.readUInt32(); err != nil { + return keepAliveChallenge, err + } + + return keepAliveChallenge, nil +} diff --git a/common/tmkind/tmkind.go b/common/tmkind/tmkind.go new file mode 100644 index 0000000..4a856bd --- /dev/null +++ b/common/tmkind/tmkind.go @@ -0,0 +1,41 @@ +package tmkind + +type TetraFlexTerminalMessageKinds uint16 + +const ( + NONE TetraFlexTerminalMessageKinds = 0 + IpApiGeneralConfirm TetraFlexTerminalMessageKinds = 1 + IpApiRegistrationRequest TetraFlexTerminalMessageKinds = 273 + IpApiRegistrationConfirm TetraFlexTerminalMessageKinds = 274 + IpApiAuthenticationChallenge TetraFlexTerminalMessageKinds = 529 + IpApiAuthenticationResponse TetraFlexTerminalMessageKinds = 530 + IpApiNotificationRequest TetraFlexTerminalMessageKinds = 785 + IpApiNotificationConfirm TetraFlexTerminalMessageKinds = 786 + IpApiGroupAttachRequest TetraFlexTerminalMessageKinds = 1041 + IpApiGroupAttachConfirm TetraFlexTerminalMessageKinds = 1042 + IpApiDeregistrationRequest TetraFlexTerminalMessageKinds = 1297 + IpApiKeepAliveChallenge TetraFlexTerminalMessageKinds = 1553 + IpApiKeepAliveResponse TetraFlexTerminalMessageKinds = 1554 + IpApiSubscriberInfoRequest TetraFlexTerminalMessageKinds = 1809 + IpApiSubscriberInfoConfirm TetraFlexTerminalMessageKinds = 1810 + IpApiSoftwareInfoRequest TetraFlexTerminalMessageKinds = 2065 + IpApiSoftwareInfoConfirm TetraFlexTerminalMessageKinds = 2066 + IpApiCallSetupRequest TetraFlexTerminalMessageKinds = 4369 + IpApiCallSetupConfirm TetraFlexTerminalMessageKinds = 4370 + IpApiCallConnectRequest TetraFlexTerminalMessageKinds = 4625 + IpApiCallDisconnectRequest TetraFlexTerminalMessageKinds = 4881 + IpApiCallPttRequest TetraFlexTerminalMessageKinds = 5137 + IpApiCallStreamRequest TetraFlexTerminalMessageKinds = 5393 + IpApiCallUpdateNotification TetraFlexTerminalMessageKinds = 5649 + IpApiCallRoamingFinishedNotification TetraFlexTerminalMessageKinds = 5905 + IpApiSdsDataType4Request TetraFlexTerminalMessageKinds = 9233 + IpApiSdsStatusRequest TetraFlexTerminalMessageKinds = 9489 + IpApiSdsTlTransferRequest TetraFlexTerminalMessageKinds = 9745 + IpApiSdsTlReportRequest TetraFlexTerminalMessageKinds = 10001 + IpApiSdsTlShortReportRequest TetraFlexTerminalMessageKinds = 10257 + IpApiSdsDataType4Notification TetraFlexTerminalMessageKinds = 13329 + IpApiSdsStatusNotification TetraFlexTerminalMessageKinds = 13585 + IpApiSdsTlTransferNotification TetraFlexTerminalMessageKinds = 13841 + IpApiSdsTlReportNotification TetraFlexTerminalMessageKinds = 14097 + IpApiSdsTlShortReportNotification TetraFlexTerminalMessageKinds = 14353 +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a7a1313 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.cheetah.cat/cheetah/opentetraflex-go + +go 1.21.0 diff --git a/main.go b/main.go new file mode 100644 index 0000000..e966d3b --- /dev/null +++ b/main.go @@ -0,0 +1,132 @@ +package main + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "test/common" + "test/common/tmkind" + // "strings" +) + +func main() { + var err error + terminalClient := common.NewTerminalClient("192.168.133.106:42381") + + //data := make([]byte, 256) + err = terminalClient.Connect() + if err != nil { + panic(err) + } + + randomBytes := make([]byte, 10) + _, err = rand.Read(randomBytes) + if err != nil { + panic(err) + } + myAddr := common.TetraFlexAddress{ + Kind: common.UserNo, + UserNo: "1005", + } + // 20160111 + tfAuthReq, err := common.NewTMAuthReq(myAddr, 0, randomBytes, 1, "OpenTetraFlex", 20230831, "1.0.0") + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(tfAuthReq.Encode())) + terminalClient.Send(tfAuthReq) + for { + select { + case parsedMsg := <-terminalClient.RX: + fmt.Println(hex.EncodeToString(parsedMsg.Bytes())) + if parsedMsg.Kind == tmkind.IpApiAuthenticationChallenge { + authChall, err := parsedMsg.AsAuthenticationChallenge() + if err != nil { + panic(err) + } + if authChall.PinRequested { + fmt.Println("Sending Auth Pin") + //terminalClient.SendTM() + } + } + if parsedMsg.Kind == tmkind.IpApiKeepAliveChallenge { + challenge, err := parsedMsg.AsKeepAliveChallenge() + if err != nil { + panic(err) + } + keepAliveBytes, _ := json.Marshal(challenge) + fmt.Println(string(keepAliveBytes)) + response, err := common.NewTMKeepAliveResponse(challenge) + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(response.Encode())) + terminalClient.Send(response) + + // Send Subscribe + + response, err = common.NewTMNotificationRequest([]tmkind.TetraFlexTerminalMessageKinds{ + tmkind.IpApiCallUpdateNotification, + tmkind.IpApiSdsTlReportNotification, + tmkind.IpApiSdsTlShortReportNotification, + tmkind.IpApiSdsDataType4Notification, + tmkind.IpApiSdsStatusNotification, + tmkind.IpApiSdsTlTransferNotification, + }) + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(response.Encode())) + terminalClient.Send(response) + + response, err = common.NewTMIpApiGroupAttachRequest([]common.GroupConfig{ + { + Group: common.NewAddressFromSSINumber(101), + ScanMode: common.Scanned, + }, + { + Group: common.NewAddressFromSSINumber(102), + ScanMode: common.Scanned, + }, + { + Group: common.NewAddressFromSSINumber(103), + ScanMode: common.Scanned, + }, + }) + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(response.Encode())) + terminalClient.Send(response) + + groupAddr := common.NewAddressFromSSINumber(103) + identityNum := common.NewAddressFromSSINumber(1007) + response, err = common.NewTMIpApiCallSetupRequest(*groupAddr, common.CallTypeGroup, common.CallPriorityDefault, false, common.TetraFlexIdentityInfo{ + Description: "blurb", + Kind: common.IdentityKindTerminal, + Address: *identityNum, + UnifiedSSIKinds: common.UnifiedKindPersonalNumber, + }) + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(response.Encode())) + terminalClient.Send(response) + + } + if parsedMsg.Kind == tmkind.IpApiRegistrationConfirm { + regInfo, err := parsedMsg.AsRegistrationInfo() + if err != nil { + panic(err) + } + fmt.Println(hex.EncodeToString(parsedMsg.Bytes())) + regInfoBytes, _ := json.Marshal(regInfo) + fmt.Println(string(regInfoBytes)) + + } + + //if parsedMsg.Kind == tmkind.IpApiNo + } + } +}