aboutsummaryrefslogtreecommitdiff
path: root/transport/serial/serial.go
diff options
context:
space:
mode:
Diffstat (limited to 'transport/serial/serial.go')
-rw-r--r--transport/serial/serial.go269
1 files changed, 5 insertions, 264 deletions
diff --git a/transport/serial/serial.go b/transport/serial/serial.go
index 5e0cb9f..2ace0a8 100644
--- a/transport/serial/serial.go
+++ b/transport/serial/serial.go
@@ -1,279 +1,20 @@
package serial
import (
- "buf.build/gen/go/meshtastic/protobufs/protocolbuffers/go/meshtastic"
- "encoding/binary"
- "fmt"
- "github.com/charmbracelet/log"
- "github.com/crypto-smoke/meshtastic-go/transport"
"go.bug.st/serial"
- "google.golang.org/protobuf/proto"
- "io"
- "math/rand"
- "time"
)
const (
- WAIT_AFTER_WAKE = 100 * time.Millisecond
- START1 = 0x94
- START2 = 0xc3
- PACKET_MTU = 512
- PORT_SPEED = 115200 //921600
+ PORT_SPEED = 115200 //921600
)
-type HandlerFunc func(message proto.Message)
-
-// Serial connection to a node
-type Conn struct {
- serialPort string
- serialConn serial.Port
- handlers *transport.HandlerRegistry
-
- config struct {
- complete bool
- configID uint32
- *meshtastic.MyNodeInfo
- *meshtastic.DeviceMetadata
- nodes []*meshtastic.NodeInfo
- channels []*meshtastic.Channel
- config []*meshtastic.Config
- modules []*meshtastic.ModuleConfig
- }
-}
-
-func NewConn(port string, errorOnNoHandler bool) *Conn {
- var c = Conn{serialPort: port,
- handlers: transport.NewHandlerRegistry(errorOnNoHandler)}
- return &c
-}
-
-// You have to send this first to get the radio into protobuf mode and have it accept and send packets via serial
-func (c *Conn) sendGetConfig() {
- r := rand.Uint32()
- c.config.configID = r
- //log.Info("want config id", r)
- msg := &meshtastic.ToRadio{
- PayloadVariant: &meshtastic.ToRadio_WantConfigId{
- WantConfigId: r,
- },
- }
- c.SendToRadio(msg)
-}
-func (c *Conn) Handle(kind proto.Message, handler transport.MessageHandler) {
- c.handlers.RegisterHandler(kind, handler)
-}
-
-func (c *Conn) Connect() error {
- mode := &serial.Mode{
- BaudRate: PORT_SPEED,
- }
- port, err := serial.Open(c.serialPort, mode)
- if err != nil {
- return err
- }
- c.serialConn = port
- ch := make(chan *meshtastic.FromRadio)
- go c.decodeProtos(false, ch)
- go func() {
- for {
- msg := <-ch
- var variant proto.Message
- switch msg.GetPayloadVariant().(type) {
- // These pbufs all get sent upon initial connection to the node
- case *meshtastic.FromRadio_MyInfo:
- c.config.MyNodeInfo = msg.GetMyInfo()
- variant = c.config.MyNodeInfo
- case *meshtastic.FromRadio_Metadata:
- c.config.DeviceMetadata = msg.GetMetadata()
- variant = c.config.DeviceMetadata
- case *meshtastic.FromRadio_NodeInfo:
- node := msg.GetNodeInfo()
- c.config.nodes = append(c.config.nodes, node)
- variant = node
- case *meshtastic.FromRadio_Channel:
- channel := msg.GetChannel()
- c.config.channels = append(c.config.channels, channel)
- variant = channel
- case *meshtastic.FromRadio_Config:
- cfg := msg.GetConfig()
- c.config.config = append(c.config.config, cfg)
- variant = cfg
- case *meshtastic.FromRadio_ModuleConfig:
- cfg := msg.GetModuleConfig()
- c.config.modules = append(c.config.modules, cfg)
- variant = cfg
- case *meshtastic.FromRadio_ConfigCompleteId:
- // done getting config info
- //fmt.Println("config complete")
- c.config.complete = true
- /*
- out, err := json.MarshalIndent(c.config, "", " ")
- if err != nil {
- log.Error("failed marshalling", "err", err)
- continue
- }
- fmt.Println(string(out))
- out, err = json.MarshalIndent(c.config.config, "", " ")
- if err != nil {
- log.Error("failed marshalling", "err", err)
- continue
- }
- fmt.Println(string(out))
-
- */
- continue
- // below are packets not part of initial connection
-
- case *meshtastic.FromRadio_LogRecord:
- variant = msg.GetLogRecord()
- case *meshtastic.FromRadio_MqttClientProxyMessage:
- variant = msg.GetMqttClientProxyMessage()
- case *meshtastic.FromRadio_QueueStatus:
- variant = msg.GetQueueStatus()
- case *meshtastic.FromRadio_Rebooted:
- // true if radio just rebooted
- fmt.Print("rebooted", msg.GetRebooted())
- continue
- case *meshtastic.FromRadio_XmodemPacket:
- variant = msg.GetXmodemPacket()
-
- case *meshtastic.FromRadio_Packet:
- variant = msg.GetPacket()
- default:
- log.Error("unhandled protobuf from radio")
- }
- if !c.config.complete {
- continue
- }
- err = c.handlers.HandleMessage(variant)
- if err != nil {
- log.Error("error handling message", "err", err)
- }
- }
- }()
-
- c.sendGetConfig()
- return nil
-}
-func (c *Conn) ConnectOld(ch chan *meshtastic.FromRadio, ch2 chan *meshtastic.ToRadio) error {
+func Connect(port string) (serial.Port, error) {
mode := &serial.Mode{
BaudRate: PORT_SPEED,
}
- port, err := serial.Open(c.serialPort, mode)
- if err != nil {
- return err
- }
- c.serialConn = port
-
- go c.decodeProtos(false, ch)
- go func() {
- for {
- msg := <-ch2
- c.SendToRadio(msg)
- }
- }()
- c.sendGetConfig()
- return nil
-}
-
-func (c *Conn) decodeProtos(printDebug bool, ch chan *meshtastic.FromRadio) {
- for {
- data, err := readUntilProtobuf(c.serialConn, printDebug)
- if err != nil {
- log.Info("error:", err)
- continue
- }
- //log.Info("read from serial and got proto")
- var msg2 meshtastic.FromRadio
- err = proto.Unmarshal(data, &msg2)
- if err != nil {
- log.Fatal(err)
- }
- ch <- &msg2
- }
-}
-func readUntilProtobuf(reader io.Reader, printDebug bool) ([]byte, error) {
- buf := make([]byte, 4)
- for {
- // Read the first byte, looking for START1.
- _, err := io.ReadFull(reader, buf[:1])
- if err != nil {
- return nil, err
- }
-
- // Check for START1.
- if buf[0] != 0x94 {
- if printDebug {
- fmt.Print(string(buf[0]))
- }
- continue
- }
-
- // Read the second byte, looking for START2.
- _, err = io.ReadFull(reader, buf[1:2])
- if err != nil {
- return nil, err
- }
-
- // Check for START2.
- if buf[1] != 0xc3 {
- continue
- }
-
- // The next two bytes should be the length of the protobuf message.
- _, err = io.ReadFull(reader, buf[2:])
- if err != nil {
- return nil, err
- }
-
- length := int(binary.BigEndian.Uint16(buf[2:]))
- if length > PACKET_MTU {
- //packet corrupt, start over
- continue
- }
- //fmt.Println("got packet from node with length", length)
- data := make([]byte, length)
-
- // Read the protobuf data.
- _, err = io.ReadFull(reader, data)
- if err != nil {
- return nil, err
- }
-
- return data, nil
- }
-}
-
-func (c *Conn) flushPort() error {
- flush := make([]byte, 32)
- for j := 0; j < len(flush); j++ {
- flush[j] = START2
- }
- _, err := c.serialConn.Write(flush)
- if err != nil {
- return err
- }
- return nil
-}
-func (c *Conn) SendToRadio(msg *meshtastic.ToRadio) error {
- err := c.flushPort()
- if err != nil {
- return err
- }
- //fmt.Printf("Sent %v bytes\n", n)
- data, err := proto.Marshal(msg)
- if err != nil {
- panic(err)
- }
- time.Sleep(WAIT_AFTER_WAKE)
-
- datalen := len(data)
- header := []byte{START1, START2, byte(datalen >> 8), byte(datalen)}
- data = append(header, data...)
- _, err = c.serialConn.Write(data)
+ p, err := serial.Open(port, mode)
if err != nil {
- log.Fatal(err)
+ return nil, err
}
- //fmt.Printf("Sent %v bytes\n", n)
- return nil
+ return p, nil
}