joycon-terminal/devices/serial.go

164 lines
3.7 KiB
Go

package devices
import (
"errors"
"log"
"sync"
"time"
"github.com/go-vgo/robotgo"
"go.bug.st/serial"
)
var conf = &serial.Mode{
BaudRate: 4800,
DataBits: 8,
Parity: serial.NoParity,
StopBits: serial.OneStopBit,
}
var Conn serial.Port
var EnableRead bool
var EnableReadMtx sync.Mutex
var onlineStatus [9]int8
// GetPortList returns a list of available serial ports
func GetPortList() ([]string, error) {
list, err := serial.GetPortsList()
log.Printf("Available ports: %v", list)
if err != nil {
log.Printf("Get port list failed: %v", err)
}
return list, err
}
// ConnectSerial connects to the serial port
func ConnectSerial(path string) error {
conn, err := serial.Open(path, conf)
Conn = conn
log.Printf("Connected to port %s", path)
if err != nil {
log.Print(err.Error())
}
return err
}
func read(sleepTime time.Duration) ([]byte, int) {
time.Sleep(sleepTime) // wait 500 ms to read into system buffer
buf := make([]byte, 8)
num, err := Conn.Read(buf)
log.Printf("Data received: %v, %d bytes in total\n", buf[:num], num)
if err != nil {
log.Println(err)
return nil, -1
}
return buf, num
}
func read8bits(sleepTime time.Duration) ([]byte, int) {
var num, numTemp int
var buf, bufTemp []byte
for num = 0; num < 8; {
bufTemp, numTemp = read(sleepTime)
if numTemp == -1 {
continue
}
buf = append(buf, bufTemp[:numTemp]...)
num += numTemp
}
log.Printf("Merged 8-bit message: %v", buf)
return buf[:num], num
}
// write writes data to the serial port
func write(buffer []byte) int {
num, err := Conn.Write(buffer)
log.Printf("Data sent: %v, %d bytes in total\n", buffer[:num], num)
if err != nil {
log.Println(err)
return -1
}
return num
}
// TestConnection test read and write function
func TestConnection() error {
log.Printf("Test connection")
Conn.ResetInputBuffer()
var err error
write(TestConnectionSend)
buf, num := read8bits(500 * time.Millisecond)
if num == -1 {
err = errors.New("读取失败,请查看控制台日志")
} else if num != 8 ||
buf[0] != ProtocolHead ||
buf[1] != DeviceSpecialProtocol ||
buf[2] != KeyTestConnection ||
buf[3] != KeyActionConnectionOk {
err = errors.New("握手失败 - 是否连接了正确的设备?")
}
if err != nil {
Conn.Close()
} else {
onlineStatus[1] = ((int8)(buf[4]) >> 0) & 0x01
onlineStatus[2] = ((int8)(buf[4]) >> 1) & 0x01
onlineStatus[3] = ((int8)(buf[4]) >> 2) & 0x01
onlineStatus[4] = ((int8)(buf[4]) >> 3) & 0x01
onlineStatus[5] = ((int8)(buf[4]) >> 4) & 0x01
onlineStatus[6] = ((int8)(buf[4]) >> 5) & 0x01
onlineStatus[7] = ((int8)(buf[4]) >> 6) & 0x01
onlineStatus[8] = ((int8)(buf[4]) >> 7) & 0x01
log.Printf("Online devices: %v", onlineStatus)
}
return err
}
func RealtimeRead() {
log.Printf("Start listening")
for {
EnableReadMtx.Lock()
if !EnableRead {
EnableReadMtx.Unlock()
return
}
EnableReadMtx.Unlock()
buf, num := read8bits(50 * time.Millisecond)
if num <= 0 || buf[0] != ProtocolHead {
continue
}
if buf[1] == DeviceSpecialProtocol { // special protocol
} else { // device key
device := (int)(buf[1])
key := (int)(buf[2])
action := (int)(buf[3])
switch action {
case KeyActionPress:
robotgo.KeyDown(keymap[device][key])
log.Printf("Key %s pressed", keymap[device][key])
case KeyActionRelease:
robotgo.KeyUp(keymap[device][key])
log.Printf("Key %s released", keymap[device][key])
}
}
}
}
// GetDevices 获取在线设备列表
func GetDevices() []int {
var devices []int
for i := 1; i < 9; i++ {
if onlineStatus[i] == 1 {
devices = append(devices, i)
}
}
return devices
}
func SetKey(device, key int, target string) {
log.Printf("Set key %d of device %d to %s", key, device, target)
keymap[device][key] = target
}