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