Git Product home page Git Product logo

cyw43439's Introduction

"but do you, like, *need* that dependency?"
    - anonymous

cyw43439's People

Contributors

scottfeldman avatar soypat avatar ukd1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

cl0wder ukd1

cyw43439's Issues

JoinWPA2 does not check for succesful connection

The issue is with wait_for_join which currently blocks for 10 seconds and does not really do anything else.

Connection state should be added to Device and it should be modified on receiving AsyncEvent packets. This would mean JoinWPA2 could return early on a succesful connection and an error if connection fails.

invalid csum error, server stops

Running examples/tcpserver, hit this:

sfeldma@nuc:~/work/cyw43439$ tinygo flash -monitor -target pico -stack-size=32kb -size short ./examples/tcpserver/
   code    data     bss |   flash     ram
 428520   17084    3824 |  445604   20908
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
starting program
time=1970-01-01T00:00:02.002Z level=INFO msg=Init:start
time=1970-01-01T00:00:03.556Z level=INFO msg=Init:done took=1.552879s
time=1970-01-01T00:00:03.557Z level=INFO msg=joinWpa2 ssid=test len(pass)=8
time=1970-01-01T00:00:07.002Z level=INFO msg=rxEvent event=AUTH status=0 reason=0 flags=0 dev.linkstate=1
time=1970-01-01T00:00:07.003Z level=INFO msg=rxEvent event=SET_SSID status=0 reason=0 flags=0 dev.linkstate=2



MAC: 28:cd:c1:01:13:7c
dhcp ongoing...
time=1970-01-01T00:00:07.009Z level=INFO msg=DHCP:tx msg=Discover
time=1970-01-01T00:00:07.059Z level=INFO msg=DHCP:rx msg=Offer
time=1970-01-01T00:00:07.060Z level=INFO msg=DHCP:tx msg=Request
time=1970-01-01T00:00:07.110Z level=INFO msg=DHCP:rx msg=Ack
DHCP complete IP: 10.0.0.122
start listening on: 10.0.0.122:1234
time=1970-01-01T00:00:08.028Z level=INFO msg=TCP:rx-statechange port=1234 old=SynSent new=SynRcvd rxflags=[SYN]
time=1970-01-01T00:00:08.079Z level=INFO msg=TCP:rx-statechange port=1234 old=SynRcvd new=Established rxflags=[ACK]
time=1970-01-01T00:10:31.560Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:31.561Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:31.818Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:31.818Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:32.432Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:32.433Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:33.557Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:33.558Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:35.908Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:35.909Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:40.505Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:40.506Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:10:49.391Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:10:49.392Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:11:07.315Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:11:07.316Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum
time=1970-01-01T00:11:44.285Z level=ERROR msg=Stack.RecvEth err="invalid TCP/UDP checksum"
time=1970-01-01T00:11:44.286Z level=ERROR msg=tryPoll:rx plen=0 err="invalid TCP/UDP checksum"
poll error: invalid TCP/UDP checksum

SetSSID seems to race the async event polling

Thank you for all the hard work you put into this library. Using it, and getting started with it, was super straight forward and a pleasure ๐Ÿ™‡.

When I attempt to join my WiFi network I noticed that the setSSID call seemed to race the subsequent async status poll. Join events would repeatedly fail in state linkStateUpWaitForSSID.

As a test/hack/workaround: adding a 100ms delay after the setSSID call made the WiFi join work reliably.

TCP over Wifi for Raspberry Pi Pico W in TinyGo

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. โ†ฉ

OOM after running tcpserver test for awhile

Ran into out-of-memory panic when running tcpserver example. Just noticed it when I saw the debug output from a run last night. Here's the debug output I captured:

It's going fine here:

sfeldma@nuc:~/work/cyw43439$ tinygo flash -target=pico -opt=1 -stack-size=32kb -size=short -monitor  ./examples/tcpserver/
   code    data     bss |   flash     ram
 564264   15676    3916 |  579940   19592
Connected to /dev/ttyACM1. Press Ctrl-C to exit.
starting program
time=1970-01-01T00:00:02.001Z level=DEBUG msg="starting program"
wifi join failed: SET_SSID failed



MAC: 28:cd:c1:01:13:7c
dhcp ongoing...
time=1970-01-01T00:00:15.714Z level=DEBUG msg=UDP:send plen=590
time=1970-01-01T00:00:15.764Z level=DEBUG msg=UDP:recv plen=298
time=1970-01-01T00:00:15.765Z level=DEBUG msg=dhcp-rx msgtype=2
time=1970-01-01T00:00:15.766Z level=DEBUG msg=UDP:send plen=590
time=1970-01-01T00:00:15.866Z level=DEBUG msg=UDP:recv plen=298
time=1970-01-01T00:00:15.867Z level=DEBUG msg=dhcp-rx msgtype=5
DHCP complete IP: 192.168.1.69
start listening on: 192.168.1.69:1234
time=1970-01-01T00:00:25.862Z level=DEBUG msg=TCP:recv opt=20 ipopt=0 payload=0
time=1970-01-01T00:00:25.863Z level=INFO msg=TCP:rx-statechange port=1234 old=SynSent new=SynRcvd rxflags=[SYN]
time=1970-01-01T00:00:25.864Z level=DEBUG msg=TCP:send plen=54
time=1970-01-01T00:00:25.917Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:00:25.917Z level=INFO msg=TCP:rx-statechange port=1234 old=SynRcvd new=Established rxflags=[ACK]
time=1970-01-01T00:00:26.887Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=5
time=1970-01-01T00:00:26.888Z level=DEBUG msg=TCP:send plen=54
hello
time=1970-01-01T00:00:26.890Z level=DEBUG msg=TCP:send plen=59
time=1970-01-01T00:00:26.943Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:00:26.944Z level=DEBUG msg=TCP:send plen=54
time=1970-01-01T00:00:27.916Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=5
time=1970-01-01T00:00:27.917Z level=DEBUG msg=TCP:send plen=54
hello

And then later (around 7 mins from start), I see:

hello
time=1970-01-01T00:06:51.198Z level=DEBUG msg=TCP:send plen=59
time=1970-01-01T00:06:51.251Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:06:51.252Z level=DEBUG msg=TCP:send plen=54
time=1970-01-01T00:06:52.224Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=5
time=1970-01-01T00:06:52.225Z level=DEBUG msg=TCP:send plen=54
hello
time=1970-01-01T00:06:52.226Z level=DEBUG msg=TCP:send plen=59
time=1970-01-01T00:06:52.279Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:06:52.280Z level=DEBUG msg=TCP:send plen=54
time=1970-01-01T00:06:53.048Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:06:53.049Z level=DEBUG msg=TCP:send plen=54
time=1970-01-01T00:06:53.101Z level=DEBUG msg=TCP:recv opt=0 ipopt=0 payload=0
time=1970-01-01T00:06:53.103Z level=ERROR msg=HandleEth err="invalid out segment: seq not in send window"
stack error n(should be 0)= 0 err= invalid out segment: seq not in send window
panic: runtime error at 0x1003e2fd: out of memory
[tinygo: panic at /home/sfeldma/go/pkg/mod/github.com/soypat/[email protected]/stacks/portstack.go:335:45]

Not getting DHCP IP address from TP-Link AC1750 wifi router

I tried the tcpserver example with my test router and my Starlink router. The example connects fine with my Starlink router but fails to wifi connect to the TP-Link router, model AC1750.

Will need to sniff wireshark traffic on router side to troubleshoot. May need to install openWRT on the TP-Link to get a wireshark trace.

Might be user error...

Thanks for all the work on this. I'm trying to get my pico w to blink via tinygo.

However, going into the blinky directory and running
tinygo flash -target=pico main.go

followed by tinygo monitor gives me the following output

Connected to /dev/cu.usbmodem142401. Press Ctrl-C to exit.
panic: runtime error at 0x10006709: nil pointer dereference

I suspect user error, and was hoping for some insight in how to make the blink work.

NTP example always times out while attempting to resolve DNS queries

As I'm testing the driver using the provided examples, I'm always running into timeout issues with the NTP sample.
`
$ tinygo flash -target=pico -stack-size=8kb -monitor ./examples/ntp
go: downloading github.com/soypat/seqs v0.0.0-20240109050728-0ac18cb38dd9
go: downloading github.com/tinygo-org/pio v0.0.0-20231216154340-cd888eb58899
go: downloading golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
time=1970-01-01T00:00:01.632Z level=INFO msg="joining WPA secure network" ssid=Shroom passlen=23
time=1970-01-01T00:00:05.078Z level=INFO msg="wifi join success!" mac=28:cd:c1:0e:48:e7
time=1970-01-01T00:00:05.080Z level=INFO msg="DHCP ongoing..."
time=1970-01-01T00:00:05.081Z level=INFO msg=DHCP:tx msg=Discover
time=1970-01-01T00:00:05.082Z level=DEBUG msg=UDP:send plen=324
time=1970-01-01T00:00:05.132Z level=DEBUG msg=UDP:recv plen=301
time=1970-01-01T00:00:05.132Z level=DEBUG msg=DHCP:rx opt=MessageType data=2
time=1970-01-01T00:00:05.133Z level=DEBUG msg=DHCP:rx opt=ServerIdentification data=192,168,0,1
time=1970-01-01T00:00:05.134Z level=DEBUG msg=DHCP:rx opt=IPAddressLeaseTime data=0,9,58,128
time=1970-01-01T00:00:05.134Z level=DEBUG msg=DHCP:rx opt=RenewTimeValue data=0,4,157,64
time=1970-01-01T00:00:05.134Z level=DEBUG msg=DHCP:rx opt=RebindingTimeValue data=0,8,19,48
time=1970-01-01T00:00:05.135Z level=DEBUG msg=DHCP:rx opt=SubnetMask data=255,255,255,0
time=1970-01-01T00:00:05.135Z level=DEBUG msg=DHCP:rx opt=BroadcastAddress data=192,168,0,255
time=1970-01-01T00:00:05.136Z level=DEBUG msg=DHCP:rx opt=Router data=192,168,0,1
time=1970-01-01T00:00:05.136Z level=DEBUG msg=DHCP:rx opt=DNSServers data=192,168,0,1
time=1970-01-01T00:00:05.137Z level=DEBUG msg=DHCP:rx opt=DomainName data=104,116,46,104,111,109,101
time=1970-01-01T00:00:05.137Z level=INFO msg=DHCP:rx msg=Offer
time=1970-01-01T00:00:05.138Z level=INFO msg=DHCP:tx msg=Request
time=1970-01-01T00:00:05.139Z level=DEBUG msg=UDP:send plen=308
time=1970-01-01T00:00:05.183Z level=DEBUG msg=UDP:recv plen=311
time=1970-01-01T00:00:05.183Z level=DEBUG msg=DHCP:rx opt=MessageType data=5
time=1970-01-01T00:00:05.184Z level=DEBUG msg=DHCP:rx opt=ServerIdentification data=192,168,0,1
time=1970-01-01T00:00:05.184Z level=DEBUG msg=DHCP:rx opt=IPAddressLeaseTime data=0,9,58,128
time=1970-01-01T00:00:05.185Z level=DEBUG msg=DHCP:rx opt=RenewTimeValue data=0,4,157,64
time=1970-01-01T00:00:05.185Z level=DEBUG msg=DHCP:rx opt=RebindingTimeValue data=0,8,19,48
time=1970-01-01T00:00:05.186Z level=DEBUG msg=DHCP:rx opt=SubnetMask data=255,255,255,0
time=1970-01-01T00:00:05.186Z level=DEBUG msg=DHCP:rx opt=BroadcastAddress data=192,168,0,255
time=1970-01-01T00:00:05.187Z level=DEBUG msg=DHCP:rx opt=Router data=192,168,0,1
time=1970-01-01T00:00:05.187Z level=DEBUG msg=DHCP:rx opt=DNSServers data=192,168,0,1
time=1970-01-01T00:00:05.188Z level=DEBUG msg=DHCP:rx opt=DomainName data=104,116,46,104,111,109,101
time=1970-01-01T00:00:05.188Z level=DEBUG msg=DHCP:rx opt=HostName data=110,116,112,45,112,105,99,111
time=1970-01-01T00:00:05.189Z level=INFO msg=DHCP:rx msg=Ack
time=1970-01-01T00:00:05.581Z level=INFO msg="DHCP complete" cidrbits=24 ourIP=192.168.0.78 dns=192.168.0.1 broadcast=192.168.0.255 gateway="invalid IP" router=192.168.0.1 dhcp=192.168.0.1 hostname=ntp-pico lease=168h0m0s renewal=84h0m0s rebinding=147h0m0s
time=1970-01-01T00:00:05.591Z level=DEBUG msg=ARP:send isReply=false
time=1970-01-01T00:00:05.641Z level=DEBUG msg=ARP:recv op=2
time=1970-01-01T00:00:05.692Z level=DEBUG msg=ARP:send isReply=false
time=1970-01-01T00:00:05.743Z level=DEBUG msg=ARP:recv op=2
time=1970-01-01T00:00:05.795Z level=DEBUG msg=UDP:send plen=72
panic: DNS lookup failed:dns lookup timed out

`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.