diff --git a/examples/wifinina/ntpclient/main.go b/examples/wifinina/ntpclient/main.go index 7bbd5a2..261094b 100644 --- a/examples/wifinina/ntpclient/main.go +++ b/examples/wifinina/ntpclient/main.go @@ -23,33 +23,46 @@ const ntpHost = "129.6.15.29" const NTP_PACKET_SIZE = 48 +// these are the default pins for the Arduino Nano33 IoT. +// change these to connect to a different UART or pins for the ESP8266/ESP32 var ( + + // these are the default pins for the Arduino Nano33 IoT. + uart = machine.UART2 + tx = machine.NINA_TX + rx = machine.NINA_RX + spi = machine.NINA_SPI + // this is the ESP chip that has the WIFININA firmware flashed on it adaptor *wifinina.Device b = make([]byte, NTP_PACKET_SIZE) ) -func main() { +func setup() { + uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) - // Init esp32 // Configure SPI for 8Mhz, Mode 0, MSB First - machine.NINA_SPI.Configure(machine.SPIConfig{ + spi.Configure(machine.SPIConfig{ Frequency: 8 * 1e6, SDO: machine.NINA_SDO, SDI: machine.NINA_SDI, SCK: machine.NINA_SCK, }) - // these are the default pins for the Arduino Nano33 IoT. - adaptor = wifinina.New(machine.NINA_SPI, + adaptor = wifinina.New(spi, machine.NINA_CS, machine.NINA_ACK, machine.NINA_GPIO0, machine.NINA_RESETN) - adaptor.Configure() +} + +func main() { + + setup() + + waitSerial() - // connect to access point connectToAP() // now make UDP connection @@ -80,10 +93,13 @@ func main() { } } - // Right now this code is never reached. Need a way to trigger it... - println("Disconnecting UDP...") - conn.Close() - println("Done.") +} + +// Wait for user to open serial console +func waitSerial() { + for !machine.UART0.DTR() { + time.Sleep(100 * time.Millisecond) + } } func getCurrentTime(conn *net.UDPSerialConn) (time.Time, error) { @@ -140,6 +156,12 @@ func clearBuffer() { // connect to access point func connectToAP() { + if len(ssid) == 0 || len(pass) == 0 { + for { + println("Connection failed: Either ssid or password not set") + time.Sleep(10 * time.Second) + } + } time.Sleep(2 * time.Second) message("Connecting to " + ssid) adaptor.SetPassphrase(ssid, pass) diff --git a/examples/wifinina/tlsclient/main.go b/examples/wifinina/tlsclient/main.go new file mode 100644 index 0000000..f9d0a5d --- /dev/null +++ b/examples/wifinina/tlsclient/main.go @@ -0,0 +1,156 @@ +// This example opens a TCP connection using a device with WiFiNINA firmware +// and sends a HTTPS request to retrieve a webpage +// +// You shall see "strict-transport-security" header in the response, +// this confirms communication is indeed over HTTPS +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security +// +package main + +import ( + "fmt" + "machine" + "strings" + "time" + + "tinygo.org/x/drivers/net" + "tinygo.org/x/drivers/net/tls" + "tinygo.org/x/drivers/wifinina" +) + +// access point info +const ssid = "" +const pass = "" + +// IP address of the server aka "hub". Replace with your own info. +const server = "tinygo.org" + +// these are the default pins for the Arduino Nano33 IoT. +// change these to connect to a different UART or pins for the ESP8266/ESP32 +var ( + + // these are the default pins for the Arduino Nano33 IoT. + uart = machine.UART2 + tx = machine.NINA_TX + rx = machine.NINA_RX + spi = machine.NINA_SPI + + // this is the ESP chip that has the WIFININA firmware flashed on it + adaptor *wifinina.Device +) + +var buf [256]byte + +var lastRequestTime time.Time +var conn net.Conn + +func setup() { + uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) + + // Configure SPI for 8Mhz, Mode 0, MSB First + spi.Configure(machine.SPIConfig{ + Frequency: 8 * 1e6, + SDO: machine.NINA_SDO, + SDI: machine.NINA_SDI, + SCK: machine.NINA_SCK, + }) + + adaptor = wifinina.New(spi, + machine.NINA_CS, + machine.NINA_ACK, + machine.NINA_GPIO0, + machine.NINA_RESETN) + adaptor.Configure() +} + +func main() { + + setup() + + waitSerial() + + connectToAP() + + for { + readConnection() + if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 { + makeHTTPSRequest() + } + } + +} + +// Wait for user to open serial console +func waitSerial() { + for !machine.UART0.DTR() { + time.Sleep(100 * time.Millisecond) + } +} + +func readConnection() { + if conn != nil { + for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) { + if err != nil { + println("Read error: " + err.Error()) + } else { + print(string(buf[0:n])) + } + } + } +} + +func makeHTTPSRequest() { + + var err error + if conn != nil { + conn.Close() + } + + message("\r\n---------------\r\nDialing TCP connection") + conn, err = tls.Dial("tcp", server, nil) + for ; err != nil; conn, err = tls.Dial("tcp", server, nil) { + message("Connection failed: " + err.Error()) + time.Sleep(5 * time.Second) + } + println("Connected!\r") + + print("Sending HTTPS request...") + fmt.Fprintln(conn, "GET / HTTP/1.1") + fmt.Fprintln(conn, "Host:", strings.Split(server, ":")[0]) + fmt.Fprintln(conn, "User-Agent: TinyGo") + fmt.Fprintln(conn, "Connection: close") + fmt.Fprintln(conn) + println("Sent!\r\n\r") + + lastRequestTime = time.Now() +} + +// connect to access point +func connectToAP() { + if len(ssid) == 0 || len(pass) == 0 { + for { + println("Connection failed: Either ssid or password not set") + time.Sleep(10 * time.Second) + } + } + time.Sleep(2 * time.Second) + message("Connecting to " + ssid) + adaptor.SetPassphrase(ssid, pass) + for st, _ := adaptor.GetConnectionStatus(); st != wifinina.StatusConnected; { + message("Connection status: " + st.String()) + time.Sleep(1 * time.Second) + st, _ = adaptor.GetConnectionStatus() + } + message("Connected.") + time.Sleep(2 * time.Second) + ip, _, _, err := adaptor.GetIP() + for ; err != nil; ip, _, _, err = adaptor.GetIP() { + message(err.Error()) + time.Sleep(1 * time.Second) + } + message(ip.String()) +} + +func message(msg string) { + println(msg, "\r") +} diff --git a/examples/wifinina/webclient/main.go b/examples/wifinina/webclient/main.go index afdc879..9c40098 100644 --- a/examples/wifinina/webclient/main.go +++ b/examples/wifinina/webclient/main.go @@ -41,8 +41,7 @@ var buf [256]byte var lastRequestTime time.Time var conn net.Conn -func main() { - +func setup() { uart.Configure(machine.UARTConfig{TX: tx, RX: rx}) // Configure SPI for 8Mhz, Mode 0, MSB First @@ -59,16 +58,33 @@ func main() { machine.NINA_GPIO0, machine.NINA_RESETN) adaptor.Configure() +} + +func main() { + + setup() + + waitSerial() connectToAP() for { - loop() + readConnection() + if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 { + makeHTTPRequest() + } } - println("Done.") + } -func loop() { +// Wait for user to open serial console +func waitSerial() { + for !machine.UART0.DTR() { + time.Sleep(100 * time.Millisecond) + } +} + +func readConnection() { if conn != nil { for n, err := conn.Read(buf[:]); n > 0; n, err = conn.Read(buf[:]) { if err != nil { @@ -78,9 +94,6 @@ func loop() { } } } - if time.Now().Sub(lastRequestTime).Milliseconds() >= 10000 { - makeHTTPRequest() - } } func makeHTTPRequest() { @@ -98,7 +111,7 @@ func makeHTTPRequest() { message("\r\n---------------\r\nDialing TCP connection") conn, err = net.DialTCP("tcp", laddr, raddr) for ; err != nil; conn, err = net.DialTCP("tcp", laddr, raddr) { - message("connection failed: " + err.Error()) + message("Connection failed: " + err.Error()) time.Sleep(5 * time.Second) } println("Connected!\r") @@ -106,7 +119,7 @@ func makeHTTPRequest() { print("Sending HTTP request...") fmt.Fprintln(conn, "GET / HTTP/1.1") fmt.Fprintln(conn, "Host:", server) - fmt.Fprintln(conn, "User-Agent: TinyGo/0.10.0") + fmt.Fprintln(conn, "User-Agent: TinyGo") fmt.Fprintln(conn, "Connection: close") fmt.Fprintln(conn) println("Sent!\r\n\r") @@ -114,19 +127,14 @@ func makeHTTPRequest() { lastRequestTime = time.Now() } -func readLine(conn *net.TCPSerialConn) string { - println("Attempting to read...\r") - b := buf[:] - for expiry := time.Now().Unix() + 10; time.Now().Unix() > expiry; { - if n, err := conn.Read(b); n > 0 && err == nil { - return string(b[0:n]) - } - } - return "" -} - // connect to access point func connectToAP() { + if len(ssid) == 0 || len(pass) == 0 { + for { + println("Connection failed: Either ssid or password not set") + time.Sleep(10 * time.Second) + } + } time.Sleep(2 * time.Second) message("Connecting to " + ssid) adaptor.SetPassphrase(ssid, pass) diff --git a/net/tls/tls.go b/net/tls/tls.go index 5e5460c..12ba037 100644 --- a/net/tls/tls.go +++ b/net/tls/tls.go @@ -4,6 +4,7 @@ package tls import ( "strconv" + "strings" "tinygo.org/x/drivers/net" ) @@ -17,14 +18,17 @@ func Dial(network, address string, config *Config) (*net.TCPSerialConn, error) { return nil, err } - addr := raddr.IP.String() + hostname := strings.Split(address, ":")[0] sendport := strconv.Itoa(raddr.Port) + if sendport == "0" { + sendport = "443" + } // disconnect any old socket net.ActiveDevice.DisconnectSocket() // connect new socket - err = net.ActiveDevice.ConnectSSLSocket(addr, sendport) + err = net.ActiveDevice.ConnectSSLSocket(hostname, sendport) if err != nil { return nil, err } diff --git a/wifinina/tcp.go b/wifinina/tcp.go index d5c0c06..0ae2ea7 100644 --- a/wifinina/tcp.go +++ b/wifinina/tcp.go @@ -50,19 +50,24 @@ func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error { drv.proto, drv.ip, drv.port = mode, 0, 0 // convert port to uint16 - p64, err := strconv.ParseUint(portStr, 10, 16) - if err != nil { - return fmt.Errorf("could not convert port to uint16: %s", err.Error()) - } - port := uint16(p64) - - // look up the hostname if necessary; if an IP address was specified, the - // same will be returned. Otherwise, an IPv4 for the hostname is returned. - ipAddr, err := drv.dev.GetHostByName(addr) + port, err := convertPort(portStr) if err != nil { return err } - ip := ipAddr.AsUint32() + + hostname := addr + ip := uint32(0) + + if mode != ProtoModeTLS { + // look up the hostname if necessary; if an IP address was specified, the + // same will be returned. Otherwise, an IPv4 for the hostname is returned. + ipAddr, err := drv.dev.GetHostByName(addr) + if err != nil { + return err + } + hostname = "" + ip = ipAddr.AsUint32() + } // check to see if socket is already set; if so, stop it if drv.sock != NoSocketAvail { @@ -77,7 +82,7 @@ func (drv *Driver) connectSocket(addr, portStr string, mode uint8) error { } // attempt to start the client - if err := drv.dev.StartClient(ip, port, drv.sock, mode); err != nil { + if err := drv.dev.StartClient(hostname, ip, port, drv.sock, mode); err != nil { return err } @@ -169,7 +174,7 @@ func (drv *Driver) Write(b []byte) (n int, err error) { return 0, ErrNoData } if drv.proto == ProtoModeUDP { - if err := drv.dev.StartClient(drv.ip, drv.port, drv.sock, drv.proto); err != nil { + if err := drv.dev.StartClient("", drv.ip, drv.port, drv.sock, drv.proto); err != nil { return 0, fmt.Errorf("error in startClient: %w", err) } if _, err := drv.dev.InsertDataBuf(b, drv.sock); err != nil { diff --git a/wifinina/wifinina.go b/wifinina/wifinina.go index c2aee9e..ed572a6 100644 --- a/wifinina/wifinina.go +++ b/wifinina/wifinina.go @@ -303,22 +303,30 @@ func (d *Device) Configure() { // ----------- client methods (should this be a separate struct?) ------------ -func (d *Device) StartClient(addr uint32, port uint16, sock uint8, mode uint8) error { +func (d *Device) StartClient(hostname string, addr uint32, port uint16, sock uint8, mode uint8) error { if _debug { - println("[StartClient] called StartClient()\r") - fmt.Printf("[StartClient] addr: % 02X, port: %d, sock: %d\r\n", addr, port, sock) + fmt.Printf("[StartClient] hostname: %s addr: % 02X, port: %d, sock: %d\r\n", hostname, addr, port, sock) } if err := d.waitForChipSelect(); err != nil { d.spiChipDeselect() return err } - d.sendCmd(CmdStartClientTCP, 4) + if len(hostname) > 0 { + d.sendCmd(CmdStartClientTCP, 5) + d.sendParamStr(hostname, false) + } else { + d.sendCmd(CmdStartClientTCP, 4) + } d.sendParam32(addr, false) d.sendParam16(port, false) d.sendParam8(sock, false) d.sendParam8(mode, true) + if len(hostname) > 0 { + d.padTo4(17 + len(hostname)) + } + d.spiChipDeselect() _, err := d.waitRspCmd1(CmdStartClientTCP) @@ -818,7 +826,7 @@ func (d *Device) sendCmdStr(cmd uint8, p1 string) (err error) { } l := d.sendCmd(cmd, 1) l += d.sendParamStr(p1, true) - d.addPadding(l) + d.padTo4(5 + len(p1)) return nil } @@ -1144,7 +1152,7 @@ func (d *Device) addPadding(l int) { func (d *Device) padTo4(l int) { if _debug { - println("addPadding", l, "\r") + println("padTo4", l, "\r") } for l%4 != 0 {