tinygo-org / drivers

TinyGo drivers for sensors, displays, wireless adaptors, and other devices that use I2C, SPI, GPIO, ADC, and UART interfaces.
https://tinygo.org
BSD 3-Clause "New" or "Revised" License
604 stars 188 forks source link

wifinina: Can't complete read from net.Conn #411

Open jasonmf opened 2 years ago

jasonmf commented 2 years ago
$ tinygo version
tinygo version 0.23.0 linux/amd64 (using go version go1.17.7 and LLVM version 14.0.0)
$ tinygo flash -target=arduino-nano33 main.go
...
$ cat go.mod
module blarg

go 1.17

require tinygo.org/x/drivers v0.20.0

require (
        golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
        golang.org/x/text v0.3.6 // indirect
)

I'm using an arduino-nano33 (IoT) to connect to an HTTPS server I control. It's not clear how to retrieve data. I've tried a few different approaches:

Using a conn based on tls.Dial() and breaking the loop if no data is retrieved, as in the tlsclient example:

    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")

    conn.SetReadDeadline(time.Now().Add(time.Second * 10))
    for n, err := conn.Read(socketBuf[:]); n > 0; n, err = conn.Read(socketBuf[:]) {
        if err != nil {
            println("Read error: " + err.Error())
            break
        } else {
            print(string(socketBuf[0:n]))
        }
    }

It connects, the request is sent, and it immediately falls out of the loop with no error and no output.

Using a conn based on tls.Dial() and breaking the loop only on error with read timeout:

    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")

    conn.SetReadDeadline(time.Now().Add(time.Second * 10))
    for {
        n, err := conn.Read(socketBuf[:])
        if n > 0 {
            print(string(socketBuf[:n]))
        }
        if err != nil {
            println("read error: ", err.Error())
            break
        }
    }
    println("read done")

The HTTP response is printed but it never breaks out of the loop.

Trying the drivers/net/http package:

    println("Sending request")
    resp, err := http.Get("https://myserver:443/")
    if err != nil {
        return fmt.Errorf("getting: %w", err)
    }

    println("hanlding response")
    fmt.Printf("%s %s\r\n", resp.Proto, resp.Status)
    for k, v := range resp.Header {
        fmt.Printf("%s: %s\r\n", k, strings.Join(v, " "))
    }
    fmt.Printf("\r\n")

    println("scanning")
    scanner := bufio.NewScanner(resp.Body)
    for scanner.Scan() {
        fmt.Printf("%s\r\n", scanner.Text())
    }
    resp.Body.Close()
    println("done")
    return nil

It never gets passed Sending request.

The docs for net.Conn.Read say:

Read can be made to time out and return an Error with Timeout() == true

Which I can't make sense of searching the net and wifinina sources.

damongolding commented 1 year ago

Hey @jasonmf 👋

I have managed to get the request to go through on my nano33 if you are still having issues.

I used the drivers/net/http package but added a buffer

var buf [0x500]byte
http.SetBuf(buf[:])