Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCP over Wifi for Raspberry Pi Pico W in TinyGo #1

Closed
soypat opened this issue Apr 30, 2023 · 13 comments
Closed

TCP over Wifi for Raspberry Pi Pico W in TinyGo #1

soypat opened this issue Apr 30, 2023 · 13 comments

Comments

@soypat
Copy link
Owner

soypat commented Apr 30, 2023

BOUNTY OVER. (READ COMMENT BELOW)

Scope

The aim of this project is to implement the missing functionality needed to control the Ethernet/TCP interface on the Raspberry Pi Pico W's on board CYW43439 wifi/bluetooth chip. The way this is to be done is by implementing the Netdev interface, which is really a Berkeley Socket(2) interface via software:

type Netdev interface {
	// GetHostByName returns the IP address of either a hostname or IPv4
	// address in standard dot notation
	GetHostByName(name string) (net.IP, error)
	// Berkely Sockets-like interface, Go-ified.  See man page for socket(2), etc.
	Socket(domain int, stype int, protocol int) (int, error)
	Bind(sockfd int, ip net.IP, port int) error
	Connect(sockfd int, host string, ip net.IP, port int) error
	Listen(sockfd int, backlog int) error
	Accept(sockfd int, ip net.IP, port int) (int, error)
	Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
	Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
	Close(sockfd int) error
	SetSockOpt(sockfd int, level int, opt int, value interface{}) error
}

Background

The development target is the RP2040 microcontroller using the Go programming language that comes in the Pico W board package. TinyGo is the compiler which lets us compile Go code to the RP2040. The CYW43439 is connected to the RP2040 (Raspberry Pi's microcontroller) via SPI where SDO and SDI are shared on the same pin. The communication today in TinyGo happens via software (bitbang) SPI.

The work done so far has been achieved by porting over the C version of the driver: georgerobotics/cyw43-driver. This driver is used by the SDK maintained by the Raspberry Pi foundation in raspberrypi/pico-sdk. Some functionality may also be needed from the pico-sdk repository.

Work done so far

Requirements

RFC2119 language will be used throughout this document and MUST be interpreted accordingly1, source that does not conform to this specification may be rejected as a solution to this issue. The Programmer or just Programmer is the entity which submits the pull request seeking to resolve this issue. Source is the source code submitted by the Programmer seeking to resolve this issue. The Maintainer is Patricio Whittingslow- github alias @soypat.

It is important to note that the Source will not be held to higher standards than the already existing code in this repository, so looking at existing code is a good way to get up to speed on expectations.

Code Style

  1. Source SHOULD adhere to google's code style.
  2. Source RECOMMENDED to abide by CodeReviewComments.
  3. Source SHOULD leverage Go's type system as has been done so far in this repository. See cyw43439.go

The programmer may be requested to make changes based on style. To avoid sweeping changes it is recommended the programmer show regular initial progress updates so maintainer and programmer quickly agree on the scope of code style requirements.

Source constraints

Since this project will run on a constrained system some considerations must be taken:

  1. Source functions SHOULD have a directly corresponding C function from cy43-driver unless doing so would make code more complex or less performant. The corresponding C function should be marked as has been done so far, with a comment line in the format of: // reference: cy43_function_name
  2. Source MUST NOT use Go's native goroutines
  3. Source MUST NOT use Go's native channels
  4. Source SHOULD NOT use Go's defer keyword unless there is a simplicity, performance or security reason for doing so.
  5. Source MAY have Debug() calls to aid in debugging
  6. Source MUST NOT allocate memory via make calls (or large array creation) unless reference implementation allocates memory in ported section of code situation. By extension allocation packages such as fmt must be avoided.
  7. Source MUST be compileable by TinyGo latest release or latest dev branch.
  8. Source MUST NOT use third party packages except in the case of using an lwip like library for marshalling and unmarshalling of ethernet, IP, ARP, and TCP frames. In the case of using a third party package the Programmer MUST consult with the Maintainer on the viability of the thrid party package being included. See this comment for more information and alternatives.

Documentation

  1. Source MAY be documented according to Code Style section.

Final product requirements

The Source MUST permit the compilation of the following program and said program
MUST work as detailed below in the explanation section.

package main

import (
	"net"
	"net/netip"
	"syscall"
	"time"

	cyw43439 "github.com/soypat/cyw43439"
)

func main() {
	var (
		fd     int
		err    error
		buffer [256]byte
		n      int
	)
	// Start with general device initialization. This is already implemented.
	spi, cs, WL_REG_ON, irq := cyw43439.PicoWSpi(0)
	dev := cyw43439.NewDev(spi, cs, WL_REG_ON, irq, irq)
	err = dev.Init(cyw43439.DefaultConfig(false))
	if err != nil {
		panic(err.Error())
	}
	// Everything beyond this point must be implemented!
	err = dev.ConnectWifi(cyw43439.DefaultWifiConfig())
	if err != nil {
		panic(err.Error())
	}

	// Create a file descriptor for the TCP socket.
	fd, err = dev.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
	if err != nil {
		panic(err)
	}

	// Define the TCP listener IP address and port. This would be your PC's
	// IP address and the port on which you are running a test server that will
	// receive the Pico W's TCP communications.
	listener := net.TCPAddrFromAddrPort(netip.MustParseAddrPort("192.168.1.1:8080"))
	// Performs TCP connection to server.
	err = dev.Connect(fd, "", listener.IP, listener.Port)
	if err != nil {
		dev.Close(fd)
		panic(err)
	}

	// We loop forever printing out what we receive from the server and
	// sending our own message. This should run forever as long as the server
	// remains up and keeps the connection open.
	for {
		deadline := time.Now().Add(time.Second)
		_, err = dev.Send(fd, []byte("Hello from the Pico W!\n"), 0, deadline)
		if err != nil {
			println("error:", err.Error())
		}
		n, err = dev.Recv(fd, buffer[:], 0, deadline)
		if err == nil {
			println("received message:", string(buffer[:n]))
		}
		time.Sleep(200 * time.Millisecond)
	}
}
Explanation

The program above makes use of existing functions that initialize the CYW43439 device
up to the ConnectWifi method call, which must itself be implemented along with all
the following method calls of the cyw43439.Device type. The Source MUST perform the
following actions when the above program is run:

  1. Initializes the device via the Init method.
  2. Initializes the device's wifi interface via ConnectWifi and connects to
    a wifi endpoint. The SSID and password are not provided directly but can be left as
    hardcoded variables by the programmer to be easily modified later.
  3. Socket call acquires a TCP connection handle and returns an error if it is unable to acquire a functional TCP handle.
  4. Connect attempts to connect to the IP and TCP port specified (192.168.1.1:8080). It returns an error
    if the connection fails or if there is no answer back.
  5. After the Connect call the TCP connection SHOULD be established and ready for communications.
    The for loop demonstrates the correct functioning of the connection by first using Send
    to send bytes to the listener and Recv to receive bytes from the listener.

Most of the above program can be summarized as follows:

The Source should seek to implement the Linux Socket(2) interface for the CYW43439 using TinyGo.

Caveat: It is possible that the Source will include use of a lwip like library for
marshalling Ethernet, ARP, IP and TCP packets received. The Source can choose
to use an external library for this matter but MUST first consult with the Maintainer. See relevant comment.

Aid

The Maintainer can provide facilities to help the Programmer debug, these include
but are not limited to:

  • Code review
  • Analyzing SPI transactions result of the Source via 500MHz logic analyzer

Footnotes

  1. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

@ghost
Copy link

ghost commented May 23, 2023

@soypat
Copy link
Owner Author

soypat commented May 23, 2023

@abebeos Thank you for notifying us of this! Knowing bounty-source has an issue with payments I'd suggest no more payments be added to the link above until the issue be solved. Also fair warning to anyone who tries to solve this bounty that bounty-source may delay or omit payment.

@scottfeldman
Copy link
Collaborator

Just a brief note on driver status: it now connects to Wifi AP and receives Eth pkts. Link status isn't working, send Eth pkt is incomplete, and knowing when there is async work to do isn't working. Lots more work to do, including a small thing called the tcpip stack (lwip replacement). Thanks @soypat for the help and support.

@Evilran
Copy link

Evilran commented Aug 1, 2023

@soypat @scottfeldman Hi. What's the progress so far? It would be great if it worked!

@scottfeldman
Copy link
Collaborator

@Evilran, not working yet. Progress has been slow for a couple weeks, but now continuing...

@scottfeldman
Copy link
Collaborator

scottfeldman commented Sep 14, 2023

The Bounty Source links are down; seems they spent the bounty $$.

@ghost
Copy link

ghost commented Sep 14, 2023

The Bounty Source links are down; seems they spent the bounty $$.

Criminal liability: https://twitter.com/abebeos/status/1701925706526085243

@soypat soypat removed the Bounty label Sep 15, 2023
@soypat soypat changed the title Bounty: TCP over Wifi for Raspberry Pi Pico W in TinyGo TCP over Wifi for Raspberry Pi Pico W in TinyGo Sep 15, 2023
@scottfeldman
Copy link
Collaborator

Current status is cwy43 driver is working (sending/recv eth frames). @soypat is working on TCP/IP stack that sits on top of cwy43 driver. He's working out of this repo for the TCP/IP work: https://github.com/soypat/seqs. I'm working on porting cyrpto/tls package over from Go to TinyGo so we can use TLS sockets with cyw43.

@shreeve
Copy link

shreeve commented Dec 2, 2023

@scottfeldman - Fantastic updates! Thank you.

@scottfeldman
Copy link
Collaborator

You're welcome. The cyw43 driver is actually working really good. We used the Rust cyw43 driver for reference. Very clean implementation to copy from. rp2040 has PIO programming where you can offload your hot-loop to hardware, so all the bit-banging across the SPI bus happens from hardware (PIO), not from the software (driver). Performance should be on-par with Rust driver. I'm anxious to get some real TCP/IP perf numbers; need to find an iperf port we can run from TinyGo.

Bluetooth support is still missing in our TinyGo driver, but it uses a lot of the core work already in place for the wifi driver, so if someone has time to port bluetooth from the Rust ref driver, that would be great!

@scottfeldman
Copy link
Collaborator

Oh, and we haven't ported over the Wifi scanning code, if someone wants to work on that. That one should be pretty easy to port and test. Just need a pico-w...

If someone is interested in porting bluetooth or wifi scanning, we can help get your env set up.

@soypat
Copy link
Owner Author

soypat commented Dec 8, 2023

Fixed by #24. We now have a working TCP stack. What is left is to fix bugs. Let's get to testing it! Instructions on how to run it have been posted in the related tinygo issue

@soypat soypat closed this as completed Dec 8, 2023
@shreeve
Copy link

shreeve commented Dec 11, 2023

This is huge... awesome work on it @soypat and others!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants