espat: refactor net and tls interface compatible code into separate sub-packages

Signed-off-by: Ron Evans <ron@hybridgroup.com>
This commit is contained in:
Ron Evans
2019-07-03 13:27:19 +02:00
parent 7e78e2c998
commit 50633f3e86
8 changed files with 135 additions and 115 deletions
+4
View File
@@ -36,6 +36,9 @@ type Device struct {
socketdata []byte
}
// ActiveDevice is the currently configured Device in use. There can only be one.
var ActiveDevice *Device
// New returns a new espat driver. Pass in a fully configured UART bus.
func New(b machine.UART) *Device {
return &Device{bus: b, response: make([]byte, 512), socketdata: make([]byte, 0, 1024)}
@@ -43,6 +46,7 @@ func New(b machine.UART) *Device {
// Configure sets up the device for communication.
func (d Device) Configure() {
ActiveDevice = &d
}
// Connected checks if there is communication with the ESP8266/ESP32.
+5 -3
View File
@@ -7,6 +7,8 @@ import (
"github.com/eclipse/paho.mqtt.golang/packets"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/espat/net"
"tinygo.org/x/drivers/espat/tls"
)
// NewClient will create an MQTT v3.1.1 client with all of the options specified
@@ -20,7 +22,7 @@ func NewClient(o *ClientOptions) Client {
type mqttclient struct {
adaptor *espat.Device
conn espat.Conn
conn net.Conn
connected bool
opts *ClientOptions
mid uint16
@@ -52,13 +54,13 @@ func (c *mqttclient) Connect() Token {
// make connection
if strings.Contains(c.opts.Servers, "ssl://") {
url := strings.TrimPrefix(c.opts.Servers, "ssl://")
c.conn, err = c.adaptor.DialTLS("tcp", url, nil)
c.conn, err = tls.Dial("tcp", url, nil)
if err != nil {
return &mqtttoken{err: err}
}
} else if strings.Contains(c.opts.Servers, "tcp://") {
url := strings.TrimPrefix(c.opts.Servers, "tcp://")
c.conn, err = c.adaptor.Dial("tcp", url)
c.conn, err = net.Dial("tcp", url)
if err != nil {
return &mqtttoken{err: err}
}
+39 -52
View File
@@ -1,113 +1,93 @@
package espat
// package net is intended to provide compatible interfaces with the
// Go standard library's net package.
package net
import (
"errors"
"strconv"
"strings"
"time"
"tinygo.org/x/drivers/espat"
)
// 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) (*UDPSerialConn, error) {
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPSerialConn, error) {
addr := raddr.IP.String()
sendport := strconv.Itoa(raddr.Port)
listenport := strconv.Itoa(laddr.Port)
// disconnect any old socket
d.DisconnectSocket()
espat.ActiveDevice.DisconnectSocket()
// connect new socket
d.ConnectUDPSocket(addr, sendport, listenport)
espat.ActiveDevice.ConnectUDPSocket(addr, sendport, listenport)
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr, raddr: raddr}, nil
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: espat.ActiveDevice}, laddr: laddr, raddr: raddr}, nil
}
// ListenUDP listens for UDP connections on the port listed in laddr.
func (d *Device) ListenUDP(network string, laddr *UDPAddr) (*UDPSerialConn, error) {
func ListenUDP(network string, laddr *UDPAddr) (*UDPSerialConn, error) {
addr := "0"
sendport := "0"
listenport := strconv.Itoa(laddr.Port)
// disconnect any old socket
d.DisconnectSocket()
espat.ActiveDevice.DisconnectSocket()
// connect new socket
d.ConnectUDPSocket(addr, sendport, listenport)
espat.ActiveDevice.ConnectUDPSocket(addr, sendport, listenport)
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr}, nil
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: espat.ActiveDevice}, laddr: laddr}, nil
}
// 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) {
func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPSerialConn, error) {
addr := raddr.IP.String()
sendport := strconv.Itoa(raddr.Port)
// disconnect any old socket
d.DisconnectSocket()
espat.ActiveDevice.DisconnectSocket()
// connect new socket
d.ConnectTCPSocket(addr, sendport)
espat.ActiveDevice.ConnectTCPSocket(addr, sendport)
return &TCPSerialConn{SerialConn: SerialConn{Adaptor: d}, laddr: laddr, raddr: raddr}, nil
return &TCPSerialConn{SerialConn: SerialConn{Adaptor: espat.ActiveDevice}, laddr: laddr, raddr: raddr}, nil
}
// Dial connects to the address on the named network.
// It tries to provide a mostly compatible interface
// to net.Dial().
func (d *Device) Dial(network, address string) (Conn, error) {
func Dial(network, address string) (Conn, error) {
switch network {
case "tcp":
raddr, err := d.ResolveTCPAddr(network, address)
raddr, err := ResolveTCPAddr(network, address)
if err != nil {
return nil, err
}
c, e := d.DialTCP(network, &TCPAddr{}, raddr)
c, e := DialTCP(network, &TCPAddr{}, raddr)
return c.opConn(), e
case "udp":
raddr, err := d.ResolveUDPAddr(network, address)
raddr, err := ResolveUDPAddr(network, address)
if err != nil {
return nil, err
}
c, e := d.DialUDP(network, &UDPAddr{}, raddr)
c, e := DialUDP(network, &UDPAddr{}, raddr)
return c.opConn(), e
default:
return nil, errors.New("invalid network for dial")
}
}
// DialTLS makes a TLS network connection. It tries to provide a mostly compatible interface
// to tls.Dial().
// DialTLS connects to the given network address.
func (d *Device) DialTLS(network, address string, config *TLSConfig) (*TCPSerialConn, error) {
raddr, err := d.ResolveTCPAddr(network, address)
if err != nil {
return nil, err
}
addr := raddr.IP.String()
sendport := strconv.Itoa(raddr.Port)
// disconnect any old socket
d.DisconnectSocket()
// connect new socket
err = d.ConnectSSLSocket(addr, sendport)
if err != nil {
return nil, err
}
return &TCPSerialConn{SerialConn: SerialConn{Adaptor: d}, raddr: raddr}, nil
}
// SerialConn is a loosely net.Conn compatible implementation
type SerialConn struct {
Adaptor *Device
Adaptor *espat.Device
}
// UDPSerialConn is a loosely net.Conn compatible intended to support
@@ -118,6 +98,11 @@ type UDPSerialConn struct {
raddr *UDPAddr
}
// NewUDPSerialConn returns a new UDPSerialConn/
func NewUDPSerialConn(c SerialConn, laddr, raddr *UDPAddr) *UDPSerialConn {
return &UDPSerialConn{SerialConn: c, raddr: raddr}
}
// TCPSerialConn is a loosely net.Conn compatible intended to support
// TCP over serial.
type TCPSerialConn struct {
@@ -126,6 +111,11 @@ type TCPSerialConn struct {
raddr *TCPAddr
}
// NewTCPSerialConn returns a new TCPSerialConn/
func NewTCPSerialConn(c SerialConn, laddr, raddr *TCPAddr) *TCPSerialConn {
return &TCPSerialConn{SerialConn: c, raddr: raddr}
}
// Read reads data from the connection.
// TODO: implement the full method functionality:
// Read can be made to time out and return an Error with Timeout() == true
@@ -226,14 +216,15 @@ func (c *SerialConn) SetWriteDeadline(t time.Time) error {
//
// The network must be a TCP network name.
//
func (d *Device) ResolveTCPAddr(network, address string) (*TCPAddr, error) {
func ResolveTCPAddr(network, address string) (*TCPAddr, error) {
// TODO: make sure network is 'tcp'
// separate domain from port, if any
r := strings.Split(address, ":")
ip, err := d.GetDNS(r[0])
addr, err := espat.ActiveDevice.GetDNS(r[0])
if err != nil {
return nil, err
}
ip := IP(addr)
if len(r) > 1 {
port, e := strconv.Atoi(r[1])
if e != nil {
@@ -248,14 +239,15 @@ func (d *Device) ResolveTCPAddr(network, address string) (*TCPAddr, error) {
//
// The network must be a UDP network name.
//
func (d *Device) ResolveUDPAddr(network, address string) (*UDPAddr, error) {
func ResolveUDPAddr(network, address string) (*UDPAddr, error) {
// TODO: make sure network is 'udp'
// separate domain from port, if any
r := strings.Split(address, ":")
ip, err := d.GetDNS(r[0])
addr, err := espat.ActiveDevice.GetDNS(r[0])
if err != nil {
return nil, err
}
ip := IP(addr)
if len(r) > 1 {
port, e := strconv.Atoi(r[1])
if e != nil {
@@ -339,11 +331,6 @@ func (ip IP) String() string {
return string(ip)
}
// TLSConfig is a placeholder for future compatibility with
// tls.Config.
type TLSConfig struct {
}
// Conn is a generic stream-oriented network connection.
// This interface is from the Go standard library.
type Conn interface {
+3 -3
View File
@@ -15,14 +15,14 @@ const (
)
// GetDNS returns the IP address for a domain name.
func (d *Device) GetDNS(domain string) (IP, error) {
func (d *Device) GetDNS(domain string) (string, error) {
d.Set(TCPDNSLookup, "\""+domain+"\"")
r := strings.Split(string(d.Response(1000)), ":")
if len(r) != 2 {
return nil, errors.New("Invalid domain lookup result")
return "", errors.New("Invalid domain lookup result")
}
res := strings.Split(r[1], "\r\n")
return IP(res[0]), nil
return res[0], nil
}
// ConnectTCPSocket creates a new TCP socket connection for the ESP8266/ESP32.
+39
View File
@@ -0,0 +1,39 @@
// Package tls is intended to provide a minimal set of compatible interfaces with the
// Go standard library's tls package.
package tls
import (
"strconv"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/espat/net"
)
// Dial makes a TLS network connection. It tries to provide a mostly compatible interface
// to tls.Dial().
// Dial connects to the given network address.
func Dial(network, address string, config *Config) (*net.TCPSerialConn, error) {
raddr, err := net.ResolveTCPAddr(network, address)
if err != nil {
return nil, err
}
addr := raddr.IP.String()
sendport := strconv.Itoa(raddr.Port)
// disconnect any old socket
espat.ActiveDevice.DisconnectSocket()
// connect new socket
err = espat.ActiveDevice.ConnectSSLSocket(addr, sendport)
if err != nil {
return nil, err
}
return net.NewTCPSerialConn(net.SerialConn{Adaptor: espat.ActiveDevice}, nil, raddr), nil
}
// Config is a placeholder for future compatibility with
// tls.Config.
type Config struct {
}
+17 -23
View File
@@ -11,6 +11,7 @@ import (
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/espat/net"
)
// change actAsAP to true to act as an access point instead of connecting to one.
@@ -26,8 +27,6 @@ var (
tx = machine.D10
rx = machine.D11
console = machine.UART0
adaptor *espat.Device
)
@@ -44,7 +43,7 @@ func main() {
// first check if connected
if adaptor.Connected() {
console.Write([]byte("Connected to wifi adaptor.\r\n"))
println("Connected to wifi adaptor.")
adaptor.Echo(false)
if actAsAP {
@@ -53,24 +52,22 @@ func main() {
connectToAP()
}
} else {
console.Write([]byte("\r\n"))
console.Write([]byte("Unable to connect to wifi adaptor.\r\n"))
println("Unable to connect to wifi adaptor.")
return
}
// now make UDP connection
laddr := &espat.UDPAddr{Port: 2222}
console.Write([]byte("Loading UDP listener...\r\n"))
conn, _ := adaptor.ListenUDP("UDP", laddr)
laddr := &net.UDPAddr{Port: 2222}
println("Loading UDP listener...")
conn, _ := net.ListenUDP("UDP", laddr)
console.Write([]byte("Waiting for data...\r\n"))
println("Waiting for data...")
data := make([]byte, 50)
blink := true
for {
n, _ := conn.Read(data)
if n > 0 {
console.Write(data[:n])
console.Write([]byte("\r\n"))
println(string(data[:n]))
conn.Write([]byte("hello back\r\n"))
}
blink = !blink
@@ -83,29 +80,26 @@ func main() {
}
// Right now this code is never reached. Need a way to trigger it...
console.Write([]byte("Disconnecting UDP...\r\n"))
println("Disconnecting UDP...")
conn.Close()
console.Write([]byte("Done.\r\n"))
println("Done.")
}
// connect to access point
func connectToAP() {
console.Write([]byte("Connecting to wifi network...\r\n"))
println("Connecting to wifi network...")
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"))
println("Connected.")
println(adaptor.GetClientIP())
}
// provide access point
func provideAP() {
console.Write([]byte("Starting wifi network as access point '"))
console.Write([]byte(ssid))
console.Write([]byte("'...\r\n"))
println("Starting wifi network as access point:")
println(ssid)
adaptor.SetWifiMode(espat.WifiModeAP)
adaptor.SetAPConfig(ssid, pass, 7, espat.WifiAPSecurityWPA2_PSK)
console.Write([]byte("Ready.\r\n"))
console.Write([]byte(adaptor.GetAPIP()))
console.Write([]byte("\r\n"))
println("Ready.")
println(adaptor.GetAPIP())
}
+14 -17
View File
@@ -11,6 +11,7 @@ import (
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/espat/net"
)
// access point info
@@ -26,8 +27,6 @@ var (
tx = machine.D10
rx = machine.D11
console = machine.UART0
adaptor *espat.Device
)
@@ -40,44 +39,42 @@ func main() {
// first check if connected
if adaptor.Connected() {
console.Write([]byte("Connected to wifi adaptor.\r\n"))
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
console.Write([]byte("\r\n"))
console.Write([]byte("Unable to connect to wifi adaptor.\r\n"))
println("Unable to connect to wifi adaptor.")
return
}
// now make UDP connection
ip := espat.ParseIP(hubIP)
raddr := &espat.UDPAddr{IP: ip, Port: 2222}
laddr := &espat.UDPAddr{Port: 2222}
ip := net.ParseIP(hubIP)
raddr := &net.UDPAddr{IP: ip, Port: 2222}
laddr := &net.UDPAddr{Port: 2222}
console.Write([]byte("Dialing UDP connection...\r\n"))
conn, _ := adaptor.DialUDP("udp", laddr, raddr)
println("Dialing UDP connection...")
conn, _ := net.DialUDP("udp", laddr, raddr)
for {
// send data
console.Write([]byte("Sending data...\r\n"))
println("Sending data...")
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 UDP...\r\n"))
println("Disconnecting UDP...")
conn.Close()
console.Write([]byte("Done.\r\n"))
println("Done.")
}
// connect to access point
func connectToAP() {
console.Write([]byte("Connecting to wifi network...\r\n"))
println("Connecting to wifi network...")
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"))
println("Connected.")
println(adaptor.GetClientIP())
}
+14 -17
View File
@@ -11,6 +11,7 @@ import (
"time"
"tinygo.org/x/drivers/espat"
"tinygo.org/x/drivers/espat/net"
)
// access point info
@@ -26,8 +27,6 @@ var (
tx = machine.PA22
rx = machine.PA23
console = machine.UART0
adaptor *espat.Device
)
@@ -40,44 +39,42 @@ func main() {
// first check if connected
if adaptor.Connected() {
console.Write([]byte("Connected to wifi adaptor.\r\n"))
println("Connected to wifi adaptor.")
adaptor.Echo(false)
connectToAP()
} else {
console.Write([]byte("\r\n"))
console.Write([]byte("Unable to connect to wifi adaptor.\r\n"))
println("Unable to connect to wifi adaptor.")
return
}
// now make TCP connection
ip := espat.ParseIP(serverIP)
raddr := &espat.TCPAddr{IP: ip, Port: 8080}
laddr := &espat.TCPAddr{Port: 8080}
ip := net.ParseIP(serverIP)
raddr := &net.TCPAddr{IP: ip, Port: 8080}
laddr := &net.TCPAddr{Port: 8080}
console.Write([]byte("Dialing TCP connection...\r\n"))
conn, _ := adaptor.DialTCP("tcp", laddr, raddr)
println("Dialing TCP connection...")
conn, _ := net.DialTCP("tcp", laddr, raddr)
for {
// send data
console.Write([]byte("Sending data...\r\n"))
println("Sending data...")
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"))
println("Disconnecting TCP...")
conn.Close()
console.Write([]byte("Done.\r\n"))
println("Done.")
}
// connect to access point
func connectToAP() {
console.Write([]byte("Connecting to wifi network...\r\n"))
println("Connecting to wifi network...")
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"))
println("Connected.")
println(adaptor.GetClientIP())
}