From 500f3d9813f2c84b3020a44ebfafd0b5401ae11f Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Thu, 20 Jun 2019 14:30:40 +0200 Subject: [PATCH] espat: implement TCPConn using AT command set Signed-off-by: Ron Evans --- espat/net.go | 66 +++++++++++++++++++++---- espat/tcp.go | 2 +- examples/espat/tcpclient/main.go | 83 ++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 examples/espat/tcpclient/main.go diff --git a/espat/net.go b/espat/net.go index ca4bda9..cb409cd 100644 --- a/espat/net.go +++ b/espat/net.go @@ -8,7 +8,7 @@ import ( // DialUDP makes a UDP network connection. raadr is the port that the messages will // be sent to, and laddr is the port that will be listened to in order to // receive incoming messages. -func (d Device) DialUDP(network string, laddr, raddr *UDPAddr) (*SerialConn, error) { +func (d *Device) DialUDP(network string, laddr, raddr *UDPAddr) (*UDPSerialConn, error) { addr := raddr.IP.String() sendport := strconv.Itoa(raddr.Port) listenport := strconv.Itoa(laddr.Port) @@ -19,11 +19,11 @@ func (d Device) DialUDP(network string, laddr, raddr *UDPAddr) (*SerialConn, err // connect new socket d.ConnectUDPSocket(addr, sendport, listenport) - return &SerialConn{Adaptor: &d, laddr: laddr, raddr: raddr}, nil + return &UDPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr, raddr: raddr}, nil } // ListenUDP listens for UDP connections on the port listed in laddr. -func (d Device) ListenUDP(network string, laddr *UDPAddr) (*SerialConn, error) { +func (d *Device) ListenUDP(network string, laddr *UDPAddr) (*UDPSerialConn, error) { addr := "0" sendport := "0" listenport := strconv.Itoa(laddr.Port) @@ -34,15 +34,44 @@ func (d Device) ListenUDP(network string, laddr *UDPAddr) (*SerialConn, error) { // connect new socket d.ConnectUDPSocket(addr, sendport, listenport) - return &SerialConn{Adaptor: &d, laddr: laddr}, nil + return &UDPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr}, nil } -// SerialConn is a loosely net.Conn compatible intended to support -// TCP/UDP over serial. +// DialTCP makes a TCP network connection. raadr is the port that the messages will +// be sent to, and laddr is the port that will be listened to in order to +// receive incoming messages. +func (d *Device) DialTCP(network string, laddr, raddr *TCPAddr) (*TCPSerialConn, error) { + addr := raddr.IP.String() + sendport := strconv.Itoa(raddr.Port) + + // disconnect any old socket + d.DisconnectSocket() + + // connect new socket + d.ConnectTCPSocket(addr, sendport) + + return &TCPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr, raddr: raddr}, nil +} + +// SerialConn is a loosely net.Conn compatible implementation type SerialConn struct { Adaptor *Device - laddr *UDPAddr - raddr *UDPAddr +} + +// UDPSerialConn is a loosely net.Conn compatible intended to support +// UDP over serial. +type UDPSerialConn struct { + SerialConn + laddr *UDPAddr + raddr *UDPAddr +} + +// TCPSerialConn is a loosely net.Conn compatible intended to support +// TCP over serial. +type TCPSerialConn struct { + SerialConn + laddr *TCPAddr + raddr *TCPAddr } // Read reads data from the connection. @@ -73,12 +102,22 @@ func (c *SerialConn) Close() error { } // LocalAddr returns the local network address. -func (c *SerialConn) LocalAddr() UDPAddr { +func (c *UDPSerialConn) LocalAddr() UDPAddr { return *c.laddr } // RemoteAddr returns the remote network address. -func (c *SerialConn) RemoteAddr() UDPAddr { +func (c *UDPSerialConn) RemoteAddr() UDPAddr { + return *c.laddr +} + +// LocalAddr returns the local network address. +func (c *TCPSerialConn) LocalAddr() TCPAddr { + return *c.laddr +} + +// RemoteAddr returns the remote network address. +func (c *TCPSerialConn) RemoteAddr() TCPAddr { return *c.laddr } @@ -132,6 +171,13 @@ type UDPAddr struct { Zone string // IPv6 scoped addressing zone; added in Go 1.1 } +// TCPAddr here to serve as compatible type. until TinyGo can compile the net package. +type TCPAddr struct { + IP IP + Port int + Zone string // IPv6 scoped addressing zone +} + // ParseIP parses s as an IP address, returning the result. func ParseIP(s string) IP { return IP([]byte(s)) diff --git a/espat/tcp.go b/espat/tcp.go index 8a4ee78..7cc984e 100644 --- a/espat/tcp.go +++ b/espat/tcp.go @@ -19,7 +19,7 @@ func (d *Device) ConnectTCPSocket(addr, port string) error { protocol := "TCP" val := "\"" + protocol + "\",\"" + addr + "\"," + port d.Set(TCPConnect, val) - time.Sleep(100 * time.Millisecond) + time.Sleep(pause * time.Millisecond) d.Response() return nil } diff --git a/examples/espat/tcpclient/main.go b/examples/espat/tcpclient/main.go new file mode 100644 index 0000000..0724b7f --- /dev/null +++ b/examples/espat/tcpclient/main.go @@ -0,0 +1,83 @@ +// This is a sensor station that uses a ESP8266 or ESP32 running on the device UART1. +// It creates a UDP connection you can use to get info to/from your computer via the microcontroller. +// +// In other words: +// Your computer <--> UART0 <--> MCU <--> UART1 <--> ESP8266 +// +package main + +import ( + "machine" + "time" + + "tinygo.org/x/drivers/espat" +) + +// access point info +const ssid = "YOURSSID" +const pass = "YOURPASS" + +// IP address of the server aka "hub". Replace with your own info. +const serverIP = "0.0.0.0" + +// change these to connect to a different UART or pins for the ESP8266/ESP32 +var ( + uart = machine.UART1 + tx = machine.PA22 + rx = machine.PA23 + + console = machine.UART0 + + adaptor *espat.Device +) + +func main() { + uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) + + // Init esp8266/esp32 + adaptor = espat.New(uart) + adaptor.Configure() + + // first check if connected + if adaptor.Connected() { + console.Write([]byte("Connected to wifi adaptor.\r\n")) + adaptor.Echo(false) + + connectToAP() + } else { + console.Write([]byte("\r\n")) + console.Write([]byte("Unable to connect to wifi adaptor.\r\n")) + return + } + + // now make TCP connection + ip := espat.ParseIP(serverIP) + raddr := &espat.TCPAddr{IP: ip, Port: 8080} + laddr := &espat.TCPAddr{Port: 8080} + + console.Write([]byte("Dialing TCP connection...\r\n")) + conn, _ := adaptor.DialTCP("tcp", laddr, raddr) + + for { + // send data + console.Write([]byte("Sending data...\r\n")) + conn.Write([]byte("hello\r\n")) + + time.Sleep(1000 * time.Millisecond) + } + + // Right now this code is never reached. Need a way to trigger it... + console.Write([]byte("Disconnecting TCP...\r\n")) + conn.Close() + console.Write([]byte("Done.\r\n")) +} + +// connect to access point +func connectToAP() { + console.Write([]byte("Connecting to wifi network...\r\n")) + adaptor.SetWifiMode(espat.WifiModeClient) + adaptor.ConnectToAP(ssid, pass, 10) + console.Write([]byte("Connected.\r\n")) + console.Write([]byte(adaptor.GetClientIP())) + console.Write([]byte("\r\n")) +}