197 lines
4.4 KiB
Go
197 lines
4.4 KiB
Go
package tutk
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"time"
|
|
)
|
|
|
|
func (c *Conn) WriteCh0(msg []byte) error {
|
|
binary.LittleEndian.PutUint16(msg[6:], c.seqSendCh0)
|
|
c.seqSendCh0++
|
|
return c.Write(msg)
|
|
}
|
|
|
|
func (c *Conn) WriteCh1(msg []byte) error {
|
|
binary.LittleEndian.PutUint16(msg[6:], c.seqSendCh1)
|
|
c.seqSendCh1++
|
|
msg[14] = 1 // channel
|
|
return c.Write(msg)
|
|
}
|
|
|
|
func (c *Conn) msgConnectByUID(uid []byte, i byte) []byte {
|
|
const size = 68 // or 52 or 68 or 88
|
|
b := make([]byte, size)
|
|
copy(b, "\x04\x02\x19\x02")
|
|
b[4] = size - 16
|
|
copy(b[8:], "\x01\x06\x21\x00")
|
|
copy(b[16:], uid)
|
|
copy(b[52:], "\x00\x03\x01\x02") // or 07000303 or 01010204
|
|
copy(b[56:], c.sid[8:])
|
|
b[64] = i // 1 or 2
|
|
return b
|
|
}
|
|
|
|
func (c *Conn) msgAvClientStart() []byte {
|
|
const size = 566 + 32
|
|
msg := c.msg(size)
|
|
|
|
cmd := msg[msgHhrSize:]
|
|
copy(cmd, "\x00\x00\x0b\x00")
|
|
binary.LittleEndian.PutUint16(cmd[16:], size-52)
|
|
//cmd[18] = 1 // ???
|
|
binary.LittleEndian.PutUint32(cmd[20:], uint32(time.Now().UnixMilli()))
|
|
|
|
// important values for some cameras (not for df3)
|
|
data := cmd[cmdHdrSize:]
|
|
copy(data, "Miss")
|
|
copy(data[257:], "client")
|
|
|
|
// 0100000004000000fb071f000000000000000000000003000000000001000000
|
|
cfg := msg[566:]
|
|
cfg[0] = 0 // 0 - simple proto, 1 - complex proto with "0Cxx" commands
|
|
cfg[4] = 4
|
|
copy(cfg[8:], "\xfb\x07\x1f\x00")
|
|
cfg[22] = 3
|
|
cfg[28] = 1
|
|
return msg
|
|
}
|
|
|
|
func (c *Conn) msg(size uint16) []byte {
|
|
b := make([]byte, size)
|
|
copy(b, "\x04\x02\x19\x0a")
|
|
binary.LittleEndian.PutUint16(b[4:], size-16)
|
|
copy(b[8:], "\x07\x04\x21\x00")
|
|
copy(b[12:], c.sid)
|
|
return b
|
|
}
|
|
|
|
const (
|
|
msgPing = iota + 1
|
|
msgClientStart00
|
|
msgClientStart20
|
|
msgCommand
|
|
msgCounters
|
|
msgMediaChunk
|
|
msgMediaFrame
|
|
msgMediaLost
|
|
msgCh5
|
|
msgUnknown0010
|
|
msgUnknown0a08
|
|
msgDafang0012
|
|
msgDafang0071
|
|
)
|
|
|
|
// handleMsg will return parsed msg type or zero
|
|
func (c *Conn) handleMsg(msg []byte) int8 {
|
|
//log.Printf("<- %x", msg)
|
|
// off sample
|
|
// 0 0402 tutk magic
|
|
// 2 120a tutk version (120a, 190a...)
|
|
// 4 0800 msg size = len(b)-16
|
|
// 6 0000 channel seq
|
|
// 8 28041200 msg type
|
|
// 14 0100 channel (not all msg)
|
|
// 28 0700 msg data (not all msg)
|
|
switch msg[8] {
|
|
case 0x28:
|
|
_ = c.Write(msgAckPing(msg))
|
|
return msgPing
|
|
case 0x08:
|
|
switch ch := msg[14]; ch {
|
|
case 0:
|
|
return c.handleCh0(msg[28:])
|
|
case 1:
|
|
return c.handleCh1(msg[28:])
|
|
case 5:
|
|
return c.handleCh5(msg)
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (c *Conn) handleCh1(cmd []byte) int8 {
|
|
switch cid := string(cmd[:2]); cid {
|
|
case "\x00\x00":
|
|
_ = c.WriteCh1(c.msgAck0000(cmd))
|
|
return msgClientStart00
|
|
case "\x00\x20":
|
|
//_ = c.WriteCh1(c.msgAck0020(cmd))
|
|
return msgClientStart20
|
|
case "\x09\x00": // skip
|
|
return msgCounters
|
|
case "\x0a\x08":
|
|
_ = c.WriteCh1(c.msgAck0A08(cmd))
|
|
return msgUnknown0a08
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (c *Conn) handleCh5(msg []byte) int8 {
|
|
if len(msg) != 48 {
|
|
return 0
|
|
}
|
|
|
|
// <- [48] 0402190a 20000400 07042100 7ecc05000c0000007ecc93c456c2561f 5a97c2f101050000000000000000000000010000
|
|
// -> [48] 0402190a 20000400 08041200 7ecc05000c0000007ecc93c456c2561f 5a97c2f141050000000000000000000000010000
|
|
copy(msg[8:], "\x07\x04\x21\x00")
|
|
msg[32] = 0x41
|
|
_ = c.Write(msg)
|
|
return msgCh5
|
|
}
|
|
|
|
const msgHhrSize = 28
|
|
const cmdHdrSize = 24
|
|
|
|
func (c *Conn) msgAck0000(msg28 []byte) []byte {
|
|
const cmdDataSize = 36
|
|
|
|
msg := c.msg(msgHhrSize + cmdHdrSize + cmdDataSize)
|
|
|
|
cmd := msg[msgHhrSize:]
|
|
copy(cmd, "\x00\x14\x0b\x00")
|
|
cmd[16] = cmdDataSize
|
|
copy(cmd[20:], msg28[20:24]) // request id (random)
|
|
|
|
// It's better not to answer anything, so camera won't send anything to this channel.
|
|
//data := cmd[cmdHdrSize:]
|
|
//copy(data, msg28[len(msg28)-32:])
|
|
return msg
|
|
}
|
|
|
|
//func (c *Conn) msgAck0020(msg28 []byte) []byte {
|
|
// const cmdDataSize = 36
|
|
//
|
|
// msg := c.msg(msgHhrSize + cmdHdrSize + cmdDataSize)
|
|
//
|
|
// cmd := msg[msgHhrSize:]
|
|
// copy(cmd, "\x00\x14\x0b\x00")
|
|
// cmd[16] = cmdDataSize
|
|
// copy(cmd[20:], msg28[20:24]) // request id (random)
|
|
//
|
|
// data := cmd[cmdHdrSize:]
|
|
// data[5] = 1
|
|
// data[7] = 1
|
|
// data[8] = 1
|
|
// data[12] = 4
|
|
// copy(data[16:], "\xfb\x07\x1f\x00")
|
|
// data[30] = 3
|
|
// data[32] = 1
|
|
// return msg
|
|
//}
|
|
|
|
func (c *Conn) msgAck0A08(msg28 []byte) []byte {
|
|
msg := c.msg(48)
|
|
cmd := msg[msgHhrSize:]
|
|
copy(cmd, "\x0b\x00\x0b\x00")
|
|
copy(cmd[8:], msg28[8:10])
|
|
return msg
|
|
}
|
|
|
|
func msgAckPing(req []byte) []byte {
|
|
// <- [24] 0402120a 08000000 28041200 000000005b0d4202070aa8c0
|
|
// -> [24] 04021a0a 08000000 27042100 000000005b0d4202070aa8c0
|
|
req[8] = 0x27
|
|
req[10] = 0x21
|
|
return req
|
|
}
|