Cleanup, not finished yet

This commit is contained in:
Nonoo 2020-10-17 23:33:09 +02:00
parent 01c030808c
commit 6bb6c1bff6
4 changed files with 480 additions and 449 deletions

View file

@ -1,82 +0,0 @@
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"time"
"github.com/nonoo/kappanhang/log"
)
var audioConn *net.UDPConn
var audioSendSeq uint16
var localAudioSID uint32
var remoteAudioSID uint32
func audioStreamSend(d []byte) {
_, err := audioConn.Write(d)
if err != nil {
log.Fatal(err)
}
}
func readAudioStream() ([]byte, error) {
err := audioConn.SetReadDeadline(time.Now().Add(time.Second))
if err != nil {
log.Fatal(err)
}
b := make([]byte, 1500)
n, _, err := audioConn.ReadFromUDP(b)
if err != nil {
if err, ok := err.(net.Error); ok && !err.Timeout() {
log.Fatal(err)
}
}
return b[:n], err
}
func sendAudioPkt3() {
audioStreamSend([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, byte(audioSendSeq), byte(audioSendSeq >> 8),
byte(localAudioSID >> 24), byte(localAudioSID >> 16), byte(localAudioSID >> 8), byte(localAudioSID),
byte(remoteAudioSID >> 24), byte(remoteAudioSID >> 16), byte(remoteAudioSID >> 8), byte(remoteAudioSID)})
}
func sendAudioPkt6() {
audioStreamSend([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)})
}
func openAudioStream() {
hostPort := fmt.Sprint(connectAddress, ":50003")
log.Print("connecting to ", hostPort)
raddr, err := net.ResolveUDPAddr("udp", hostPort)
if err != nil {
log.Fatal(err)
}
laddr := net.UDPAddr{
Port: 50003,
}
audioConn, err = net.DialUDP("udp", &laddr, raddr)
if err != nil {
log.Fatal(err)
}
localAudioSID = uint32(time.Now().Unix())
log.Debugf("using audio session id %.8x", localAudioSID)
sendAudioPkt3()
for {
// Expecting a Pkt4 answer.
// Example answer from radio: 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x7d, 0x45, 0x7a, 0x1d, 0xf6, 0xe9, 0x0b
r, _ := readAudioStream()
if len(r) == 16 && bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}) {
remoteSID = binary.BigEndian.Uint32(r[8:12])
break
}
}
sendAudioPkt6()
}

371
main.go
View file

@ -1,52 +1,15 @@
package main
import (
"bytes"
"crypto/rand"
"encoding/binary"
"fmt"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/nonoo/kappanhang/log"
)
var conn *net.UDPConn
var localSID uint32
var remoteSID uint32
var sendSeq uint16
var authSendSeq uint16
var authInnerSendSeq uint16
var authID [6]byte
var randIDByteForPktSeven [1]byte
var expectedPkt7ReplySeq uint16
var lastReauthAt time.Time
func send(d []byte) {
_, err := conn.Write(d)
if err != nil {
log.Fatal(err)
}
}
func read() ([]byte, error) {
err := conn.SetReadDeadline(time.Now().Add(time.Second))
if err != nil {
log.Fatal(err)
}
b := make([]byte, 1500)
n, _, err := conn.ReadFromUDP(b)
if err != nil {
if err, ok := err.(net.Error); ok && !err.Timeout() {
log.Fatal(err)
}
}
return b[:n], err
}
var portControl PortControl
var portAudio PortAudio
func setupCloseHandler() {
c := make(chan os.Signal)
@ -54,341 +17,15 @@ func setupCloseHandler() {
go func() {
<-c
log.Print("disconnecting")
sendDisconnect()
portControl.SendDisconnect()
os.Exit(0)
}()
}
func sendPkt7(replyID []byte, seq uint16) {
// Example request from PC: 0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x00, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72, 0x00, 0x78, 0x40, 0xf6, 0x02
// Example reply from radio: 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x00, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63, 0x01, 0x78, 0x40, 0xf6, 0x02
var replyFlag byte
if replyID == nil {
replyID = make([]byte, 4)
var randID [2]byte
_, err := rand.Read(randID[:])
if err != nil {
log.Fatal(err)
}
replyID[0] = randID[0]
replyID[1] = randID[1]
replyID[2] = randIDByteForPktSeven[0]
replyID[3] = 0x03
} else {
replyFlag = 0x01
}
expectedPkt7ReplySeq = sendSeq
send([]byte{0x15, 0x00, 0x00, 0x00, 0x07, 0x00, byte(seq), byte(seq >> 8),
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID),
replyFlag, replyID[0], replyID[1], replyID[2], replyID[3]})
}
func sendPkt3() {
send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, byte(sendSeq), byte(sendSeq >> 8),
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)})
}
func sendPkt6() {
send([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)})
}
func sendPktLogin() {
// The reply to the login packet will contain a 6 bytes long auth ID with the first 2 bytes set to our randID.
var randID [2]byte
_, err := rand.Read(randID[:])
if err != nil {
log.Fatal(err)
}
send([]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID),
0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, byte(authInnerSendSeq),
byte(authInnerSendSeq >> 8), 0x00, randID[0], randID[1], 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x3f, 0x25, 0x77, 0x58, // pass: beerbeer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x63, 0x6f, 0x6d, 0x2d, 0x70, 0x63, 0x00, // icom-pc in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
authSendSeq++
authInnerSendSeq++
}
func sendPktReauth(firstReauthSend bool) {
var magic byte
if firstReauthSend {
magic = 0x02
} else {
magic = 0x05
}
// Example request from PC: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
// 0xbb, 0x41, 0x3f, 0x2b, 0xe6, 0xb2, 0x7b, 0x7b,
// 0x00, 0x00, 0x00, 0x30, 0x01, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// Example reply from radio: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(authSendSeq), byte(authSendSeq >> 8),
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID),
0x00, 0x00, 0x00, 0x30, 0x01, magic, 0x00, byte(authInnerSendSeq),
byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
authSendSeq++
authInnerSendSeq++
lastReauthAt = time.Now()
}
func sendDisconnect() {
send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(sendSeq), byte(sendSeq >> 8),
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID),
0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, byte(authInnerSendSeq),
byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
send([]byte{0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID),
byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)})
}
func sendRequestSerialAndAudio() {
log.Print("requesting serial and audio stream")
send([]byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, byte(authSendSeq), byte(authSendSeq >> 8),
byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID),
0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, byte(authInnerSendSeq),
byte(authInnerSendSeq >> 8), 0x00, authID[0], authID[1], authID[2], authID[3], authID[4], authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, // The last 5 bytes from this row can be acquired from a reply starting with 0xa8 or 0x90
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x04, 0x04, 0x00, 0x00, 0xbb, 0x80,
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xc3, 0x52,
0x00, 0x00, 0xc3, 0x53, 0x00, 0x00, 0x00, 0x64,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
authSendSeq++
authInnerSendSeq++
}
func main() {
log.Init()
parseArgs()
setupCloseHandler()
hostPort := fmt.Sprint(connectAddress, ":50001")
log.Print("connecting to ", hostPort)
raddr, err := net.ResolveUDPAddr("udp", hostPort)
if err != nil {
log.Fatal(err)
}
laddr := net.UDPAddr{
Port: 50001,
}
conn, err = net.DialUDP("udp", &laddr, raddr)
if err != nil {
log.Fatal(err)
}
localSID = uint32(time.Now().Unix())
log.Debugf("using session id %.8x", localSID)
sendPkt3()
sendSeq = 1
sendPkt7(nil, sendSeq)
sendSeq = 0
sendPkt3()
for {
// Expecting a Pkt4 answer.
// Example answer from radio: 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x7d, 0x45, 0x7a, 0x1d, 0xf6, 0xe9, 0x0b
r, _ := read()
if len(r) == 16 && bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}) {
remoteSID = binary.BigEndian.Uint32(r[8:12])
break
}
}
log.Debugf("got remote session id %.8x", remoteSID)
authSendSeq = 1
authInnerSendSeq = 0x50
sendPkt6()
for {
// Expecting a Pkt6 answer.
r, _ := read()
if len(r) == 16 && bytes.Equal(r[:8], []byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00}) {
remoteSID = binary.BigEndian.Uint32(r[8:12])
break
}
}
sendPktLogin()
sendSeq = 5
// Example success auth packet: 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x46, 0x54, 0x54, 0x48, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
for {
r, _ := read()
if len(r) == 96 && bytes.Equal(r[:8], []byte{0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}) {
if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) {
log.Fatal("invalid user/password")
}
copy(authID[:], r[26:32])
log.Print("auth ok")
sendPktReauth(true)
time.AfterFunc(time.Second*2, sendRequestSerialAndAudio)
break
}
}
var lastPingAt time.Time
var lastStatusLog time.Time
var errCount int
_, err = rand.Read(randIDByteForPktSeven[:])
if err != nil {
log.Fatal(err)
}
for {
r, err := read()
if err != nil {
errCount++
if errCount > 5 {
log.Fatal("timeout")
}
log.Error("stream break detected")
}
errCount = 0
if len(r) == 21 && bytes.Equal(r[1:6], []byte{0x00, 0x00, 0x00, 0x07, 0x00}) {
gotSeq := binary.LittleEndian.Uint16(r[6:8])
if r[16] == 0x00 { // This is a pkt7 request from the radio.
// Replying to the radio.
// Example request from radio: 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1c, 0x0e, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63, 0x00, 0x57, 0x2b, 0x12, 0x00
// Example answer from PC: 0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1c, 0x0e, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72, 0x01, 0x57, 0x2b, 0x12, 0x00
sendPkt7(r[17:21], gotSeq)
} else {
if expectedPkt7ReplySeq != gotSeq { // TODO
var missingPkts int
if gotSeq > expectedPkt7ReplySeq {
missingPkts = int(gotSeq) - int(expectedPkt7ReplySeq)
} else {
missingPkts = int(gotSeq) + 65536 - int(expectedPkt7ReplySeq)
}
if missingPkts < 1000 {
log.Error("lost ", missingPkts, " packets ", gotSeq, " ", expectedPkt7ReplySeq)
}
}
}
}
if len(r) == 16 && bytes.Equal(r[:6], []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}) {
// Replying to the radio.
// Example request from radio: 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63
// Example answer from PC: 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72
gotSeq := binary.LittleEndian.Uint16(r[6:8])
send([]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, byte(gotSeq), byte(gotSeq >> 8), byte(localSID >> 24), byte(localSID >> 16), byte(localSID >> 8), byte(localSID), byte(remoteSID >> 24), byte(remoteSID >> 16), byte(remoteSID >> 8), byte(remoteSID)})
}
if len(r) == 80 && bytes.Equal(r[:6], []byte{0x50, 0x00, 0x00, 0x00, 0x00, 0x00}) && bytes.Equal(r[48:51], []byte{0xff, 0xff, 0xff}) {
// Example answer from radio: 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
// 0x86, 0x1f, 0x2f, 0xcc, 0x03, 0x03, 0x89, 0x29,
// 0x00, 0x00, 0x00, 0x40, 0x02, 0x03, 0x00, 0x52,
// 0x00, 0x00, 0xf8, 0xad, 0x06, 0x8d, 0xda, 0x7b,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
log.Error("reauth failed")
sendDisconnect()
os.Exit(1)
}
if len(r) == 144 && bytes.Equal(r[:6], []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00}) && r[96] == 1 {
// Example answer:
// 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00,
// 0xc6, 0x5f, 0x6f, 0x0c, 0x5f, 0x8b, 0x1e, 0x89,
// 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x31, 0x30, 0x31, 0x47, 0x39, 0x07,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x69, 0x63, 0x6f, 0x6d,
// 0x2d, 0x70, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x03,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
log.Print("serial and audio request success")
go openAudioStream()
}
if time.Since(lastPingAt) >= 100*time.Millisecond {
sendPkt7(nil, sendSeq)
sendPkt3()
sendSeq++
lastPingAt = time.Now()
if time.Since(lastReauthAt) >= 60*time.Second {
sendPktReauth(false)
}
if time.Since(lastStatusLog) >= 10*time.Second {
log.Print("still connected")
lastStatusLog = time.Now()
}
}
}
portControl.StartStream()
}

97
portaudio.go Normal file
View file

@ -0,0 +1,97 @@
package main
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"time"
"github.com/nonoo/kappanhang/log"
)
type PortAudio struct {
conn *net.UDPConn
sendSeq uint16
localSID uint32
remoteSID uint32
}
func (p *PortAudio) send(d []byte) {
_, err := p.conn.Write(d)
if err != nil {
log.Fatal(err)
}
}
func (p *PortAudio) read() ([]byte, error) {
err := p.conn.SetReadDeadline(time.Now().Add(time.Second))
if err != nil {
log.Fatal(err)
}
b := make([]byte, 1500)
n, _, err := p.conn.ReadFromUDP(b)
if err != nil {
if err, ok := err.(net.Error); ok && !err.Timeout() {
log.Fatal(err)
}
}
return b[:n], err
}
func (p *PortAudio) expect(packetLength int, b []byte) []byte {
var r []byte
expectStart := time.Now()
for {
r, _ = p.read()
if len(r) == packetLength && bytes.Equal(r[:len(b)], b) {
break
}
if time.Since(expectStart) > time.Second {
log.Fatal("expect timeout")
}
}
return r
}
func (p *PortAudio) sendAudioPkt3() {
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, byte(p.sendSeq), byte(p.sendSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
func (p *PortAudio) sendAudioPkt6() {
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
func (p *PortAudio) StartStream() {
hostPort := fmt.Sprint(connectAddress, ":50003")
log.Print("connecting to ", hostPort)
raddr, err := net.ResolveUDPAddr("udp", hostPort)
if err != nil {
log.Fatal(err)
}
laddr := net.UDPAddr{
Port: 50003,
}
p.conn, err = net.DialUDP("udp", &laddr, raddr)
if err != nil {
log.Fatal(err)
}
p.localSID = uint32(time.Now().Unix())
log.Debugf("using local session id %.8x", p.localSID)
p.sendAudioPkt3()
// Expecting a Pkt4 answer.
// Example answer from radio: 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x7d, 0x45, 0x7a, 0x1d, 0xf6, 0xe9, 0x0b
r := p.expect(16, []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00})
p.remoteSID = binary.BigEndian.Uint32(r[8:12])
p.sendAudioPkt6()
log.Debugf("got remote session id %.8x", p.remoteSID)
}

379
portcontrol.go Normal file
View file

@ -0,0 +1,379 @@
package main
import (
"bytes"
"crypto/rand"
"encoding/binary"
"fmt"
"net"
"os"
"time"
"github.com/nonoo/kappanhang/log"
)
type PortControl struct {
conn *net.UDPConn
localSID uint32
remoteSID uint32
sendSeq uint16
authSendSeq uint16
authInnerSendSeq uint16
authID [6]byte
randIDByteForPktSeven [1]byte
expectedPkt7ReplySeq uint16
lastReauthAt time.Time
}
func (p *PortControl) send(d []byte) {
_, err := p.conn.Write(d)
if err != nil {
log.Fatal(err)
}
}
func (p *PortControl) read() ([]byte, error) {
err := p.conn.SetReadDeadline(time.Now().Add(time.Second))
if err != nil {
log.Fatal(err)
}
b := make([]byte, 1500)
n, _, err := p.conn.ReadFromUDP(b)
if err != nil {
log.Fatal(err)
}
return b[:n], err
}
func (p *PortControl) expect(packetLength int, b []byte) []byte {
var r []byte
expectStart := time.Now()
for {
r, _ = p.read()
if len(r) == packetLength && bytes.Equal(r[:len(b)], b) {
break
}
if time.Since(expectStart) > time.Second {
log.Fatal("expect timeout")
}
}
return r
}
func (p *PortControl) sendPkt7(replyID []byte, seq uint16) {
// Example request from PC: 0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x00, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72, 0x00, 0x78, 0x40, 0xf6, 0x02
// Example reply from radio: 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x09, 0x00, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63, 0x01, 0x78, 0x40, 0xf6, 0x02
var replyFlag byte
if replyID == nil {
replyID = make([]byte, 4)
var randID [2]byte
_, err := rand.Read(randID[:])
if err != nil {
log.Fatal(err)
}
replyID[0] = randID[0]
replyID[1] = randID[1]
replyID[2] = p.randIDByteForPktSeven[0]
replyID[3] = 0x03
} else {
replyFlag = 0x01
}
p.expectedPkt7ReplySeq = p.sendSeq
p.send([]byte{0x15, 0x00, 0x00, 0x00, 0x07, 0x00, byte(seq), byte(seq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID),
replyFlag, replyID[0], replyID[1], replyID[2], replyID[3]})
}
func (p *PortControl) sendPkt3() {
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x03, 0x00, byte(p.sendSeq), byte(p.sendSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
func (p *PortControl) sendPkt6() {
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
func (p *PortControl) sendPktLogin() {
// The reply to the login packet will contain a 6 bytes long auth ID with the first 2 bytes set to our randID.
var randID [2]byte
_, err := rand.Read(randID[:])
if err != nil {
log.Fatal(err)
}
p.send([]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID),
0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, byte(p.authInnerSendSeq),
byte(p.authInnerSendSeq >> 8), 0x00, randID[0], randID[1], 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x3f, 0x25, 0x77, 0x58, // pass: beerbeer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x69, 0x63, 0x6f, 0x6d, 0x2d, 0x70, 0x63, 0x00, // icom-pc in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
p.authSendSeq++
p.authInnerSendSeq++
}
func (p *PortControl) sendPktReauth(firstReauthSend bool) {
var magic byte
if firstReauthSend {
magic = 0x02
} else {
magic = 0x05
}
// Example request from PC: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
// 0xbb, 0x41, 0x3f, 0x2b, 0xe6, 0xb2, 0x7b, 0x7b,
// 0x00, 0x00, 0x00, 0x30, 0x01, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
// Example reply from radio: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x30, 0x02, 0x05, 0x00, 0x02,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
p.send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(p.authSendSeq), byte(p.authSendSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID),
0x00, 0x00, 0x00, 0x30, 0x01, magic, 0x00, byte(p.authInnerSendSeq),
byte(p.authInnerSendSeq >> 8), 0x00, p.authID[0], p.authID[1], p.authID[2], p.authID[3], p.authID[4], p.authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
p.authSendSeq++
p.authInnerSendSeq++
p.lastReauthAt = time.Now()
}
func (p *PortControl) SendDisconnect() {
p.send([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, byte(p.sendSeq), byte(p.sendSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID),
0x00, 0x00, 0x00, 0x30, 0x01, 0x01, 0x00, byte(p.authInnerSendSeq),
byte(p.authInnerSendSeq >> 8), 0x00, p.authID[0], p.authID[1], p.authID[2], p.authID[3], p.authID[4], p.authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
func (p *PortControl) sendRequestSerialAndAudio() {
log.Print("requesting serial and audio stream")
p.send([]byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00, byte(p.authSendSeq), byte(p.authSendSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID), byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID),
0x00, 0x00, 0x00, 0x80, 0x01, 0x03, 0x00, byte(p.authInnerSendSeq),
byte(p.authInnerSendSeq >> 8), 0x00, p.authID[0], p.authID[1], p.authID[2], p.authID[3], p.authID[4], p.authID[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01, // The last 5 bytes from this row can be acquired from a reply starting with 0xa8 or 0x90
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00, // IC-705 in plain text
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2b, 0x3f, 0x55, 0x5c, 0x00, 0x00, 0x00, 0x00, // username: beer
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x04, 0x04, 0x00, 0x00, 0xbb, 0x80,
0x00, 0x00, 0xbb, 0x80, 0x00, 0x00, 0xc3, 0x52,
0x00, 0x00, 0xc3, 0x53, 0x00, 0x00, 0x00, 0x64,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00})
p.authSendSeq++
p.authInnerSendSeq++
}
func (p *PortControl) StartStream() {
hostPort := fmt.Sprint(connectAddress, ":50001")
log.Print("connecting to ", hostPort)
raddr, err := net.ResolveUDPAddr("udp", hostPort)
if err != nil {
log.Fatal(err)
}
laddr := net.UDPAddr{
Port: 50001,
}
p.conn, err = net.DialUDP("udp", &laddr, raddr)
if err != nil {
log.Fatal(err)
}
p.localSID = uint32(time.Now().Unix())
log.Debugf("using session id %.8x", p.localSID)
p.sendPkt3()
p.sendSeq = 1
p.sendPkt7(nil, p.sendSeq)
p.sendSeq = 0
p.sendPkt3()
// Expecting a Pkt4 answer.
// Example answer from radio: 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x7d, 0x45, 0x7a, 0x1d, 0xf6, 0xe9, 0x0b
r := p.expect(16, []byte{0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00})
p.remoteSID = binary.BigEndian.Uint32(r[8:12])
log.Debugf("got remote session id %.8x", p.remoteSID)
p.authSendSeq = 1
p.authInnerSendSeq = 0x50
p.sendPkt6()
// Expecting a Pkt6 answer.
r = p.expect(16, []byte{0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00})
p.remoteSID = binary.BigEndian.Uint32(r[8:12]) // TODO
p.sendPktLogin()
p.sendSeq = 5
// Example success auth packet: 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
// 0xe6, 0xb2, 0x7b, 0x7b, 0xbb, 0x41, 0x3f, 0x2b,
// 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x5d, 0x37, 0x12, 0x82, 0x3b, 0xde,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x46, 0x54, 0x54, 0x48, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
r = p.expect(96, []byte{0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
if bytes.Equal(r[48:52], []byte{0xff, 0xff, 0xff, 0xfe}) {
log.Fatal("invalid user/password")
}
copy(p.authID[:], r[26:32])
log.Print("auth ok")
p.sendPktReauth(true)
time.AfterFunc(time.Second*2, p.sendRequestSerialAndAudio)
var lastPingAt time.Time
var lastStatusLog time.Time
var errCount int
_, err = rand.Read(p.randIDByteForPktSeven[:])
if err != nil {
log.Fatal(err)
}
for {
r, err := p.read()
if err != nil {
errCount++
if errCount > 5 {
log.Fatal("timeout")
}
log.Error("stream break detected")
}
errCount = 0
if len(r) == 21 && bytes.Equal(r[1:6], []byte{0x00, 0x00, 0x00, 0x07, 0x00}) {
gotSeq := binary.LittleEndian.Uint16(r[6:8])
if r[16] == 0x00 { // This is a pkt7 request from the radio.
// Replying to the radio.
// Example request from radio: 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1c, 0x0e, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63, 0x00, 0x57, 0x2b, 0x12, 0x00
// Example answer from PC: 0x15, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1c, 0x0e, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72, 0x01, 0x57, 0x2b, 0x12, 0x00
p.sendPkt7(r[17:21], gotSeq)
} else {
if p.expectedPkt7ReplySeq != gotSeq { // TODO
var missingPkts int
if gotSeq > p.expectedPkt7ReplySeq {
missingPkts = int(gotSeq) - int(p.expectedPkt7ReplySeq)
} else {
missingPkts = int(gotSeq) + 65536 - int(p.expectedPkt7ReplySeq)
}
if missingPkts < 1000 {
log.Error("lost ", missingPkts, " packets ", gotSeq, " ", p.expectedPkt7ReplySeq)
}
}
}
}
if len(r) == 16 && bytes.Equal(r[:6], []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00}) {
// Replying to the radio.
// Example request from radio: 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xe4, 0x35, 0xdd, 0x72, 0xbe, 0xd9, 0xf2, 0x63
// Example answer from PC: 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xbe, 0xd9, 0xf2, 0x63, 0xe4, 0x35, 0xdd, 0x72
gotSeq := binary.LittleEndian.Uint16(r[6:8])
p.send([]byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, byte(gotSeq), byte(gotSeq >> 8),
byte(p.localSID >> 24), byte(p.localSID >> 16), byte(p.localSID >> 8), byte(p.localSID),
byte(p.remoteSID >> 24), byte(p.remoteSID >> 16), byte(p.remoteSID >> 8), byte(p.remoteSID)})
}
if len(r) == 80 && bytes.Equal(r[:6], []byte{0x50, 0x00, 0x00, 0x00, 0x00, 0x00}) && bytes.Equal(r[48:51], []byte{0xff, 0xff, 0xff}) {
// Example answer from radio: 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00,
// 0x86, 0x1f, 0x2f, 0xcc, 0x03, 0x03, 0x89, 0x29,
// 0x00, 0x00, 0x00, 0x40, 0x02, 0x03, 0x00, 0x52,
// 0x00, 0x00, 0xf8, 0xad, 0x06, 0x8d, 0xda, 0x7b,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
log.Error("reauth failed")
p.SendDisconnect()
os.Exit(1)
}
if len(r) == 144 && bytes.Equal(r[:6], []byte{0x90, 0x00, 0x00, 0x00, 0x00, 0x00}) && r[96] == 1 {
// Example answer:
// 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00,
// 0xc6, 0x5f, 0x6f, 0x0c, 0x5f, 0x8b, 0x1e, 0x89,
// 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x31, 0x30, 0x31, 0x47, 0x39, 0x07,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
// 0x80, 0x00, 0x00, 0x90, 0xc7, 0x0e, 0x86, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x49, 0x43, 0x2d, 0x37, 0x30, 0x35, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x01, 0x00, 0x00, 0x00, 0x69, 0x63, 0x6f, 0x6d,
// 0x2d, 0x70, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x03, 0x03,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
log.Print("serial and audio request success")
go portAudio.StartStream()
}
if time.Since(lastPingAt) >= 100*time.Millisecond {
p.sendPkt7(nil, p.sendSeq)
p.sendPkt3()
p.sendSeq++
lastPingAt = time.Now()
if time.Since(p.lastReauthAt) >= 60*time.Second {
p.sendPktReauth(false)
}
if time.Since(lastStatusLog) >= 10*time.Second {
log.Print("still connected")
lastStatusLog = time.Now()
}
}
}
}