first commit
commit
7ad747c43a
@ -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
|
||||
}]
|
||||
}
|
@ -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,
|
||||
},
|
||||
}
|
@ -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
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package common
|
||||
|
||||
type AuthenticationChallenge struct {
|
||||
RandomSeed []byte
|
||||
RandomChallenge []byte
|
||||
Response []byte
|
||||
PinRequested bool
|
||||
SecurityKeyRequested bool
|
||||
}
|
@ -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
|
||||
)
|
@ -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
|
||||
}
|
@ -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)}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
)
|
@ -0,0 +1,3 @@
|
||||
module git.cheetah.cat/cheetah/opentetraflex-go
|
||||
|
||||
go 1.21.0
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue