mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-05 23:43:41 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5405842815 | |||
| 09b7b249fe | |||
| 4bd873a82d | |||
| 8642886f73 | |||
| 1a96fc4547 |
@@ -0,0 +1,231 @@
|
|||||||
|
package apds9930
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInvalidParam = errors.New("apds9930: invalid param")
|
||||||
|
|
||||||
|
type Dev struct {
|
||||||
|
bus drivers.I2C
|
||||||
|
_txerr error
|
||||||
|
addr uint16
|
||||||
|
buf [3]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(bus drivers.I2C, addr uint8) Dev {
|
||||||
|
return Dev{bus: bus, addr: uint16(addr)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status contains info on:
|
||||||
|
//
|
||||||
|
// AVALID: Indicates that the ALS Ch0/Ch1 channels have completed an integration cycle.
|
||||||
|
// PSValid. Indicates that the PS has completed an integration cycle.
|
||||||
|
// AINTL ALS Interrupt. Indicates that the device is asserting an ALS interrupt
|
||||||
|
// PINT: Proximity Interrupt. Indicates that the device is asserting a proximity interrupt.
|
||||||
|
// PSAT: Proximity Saturation. Indicates that the proximity measurement is saturated
|
||||||
|
type Status uint8
|
||||||
|
|
||||||
|
func (s Status) ALSAvailable() bool { return s&(1<<0) != 0 } // AVALID
|
||||||
|
func (s Status) ProximityAvailable() bool { return s&(1<<1) != 0 } // PVALID
|
||||||
|
func (s Status) HasALSInterrupt() bool { return s&(1<<4) != 0 } // AINT
|
||||||
|
func (s Status) HasProxInterrupt() bool { return s&(1<<5) != 0 } // PINT
|
||||||
|
func (s Status) IsProximitySaturated() bool { return s&(1<<6) != 0 } // PSAT
|
||||||
|
|
||||||
|
type Enable uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
EnPower Enable = 1 << iota
|
||||||
|
EnALS
|
||||||
|
EnProx
|
||||||
|
EnWait
|
||||||
|
EnALSInt
|
||||||
|
EnProxInt
|
||||||
|
EnSleepAfterInt
|
||||||
|
)
|
||||||
|
|
||||||
|
// Luminic control gain.
|
||||||
|
type ALSGain uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
AGain1 ALSGain = iota
|
||||||
|
AGain8
|
||||||
|
AGain16
|
||||||
|
AGain120
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProxGain uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
PGain1 ProxGain = iota
|
||||||
|
PGain2
|
||||||
|
PGain4
|
||||||
|
PGain8
|
||||||
|
)
|
||||||
|
|
||||||
|
type Drive uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
Drive100mA Drive = iota
|
||||||
|
Drive50mA
|
||||||
|
Drive25mA
|
||||||
|
Drive12_5mA
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
ProxGain ProxGain
|
||||||
|
ALSGain ALSGain
|
||||||
|
LEDDrive Drive
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) Init(cfg Config) error {
|
||||||
|
if cfg.LEDDrive > Drive100mA {
|
||||||
|
return errInvalidParam
|
||||||
|
}
|
||||||
|
d.txNew()
|
||||||
|
d.txWrite8(regENABLE, 0x00) // disable all features.
|
||||||
|
d.txWrite8(regATIME, 0xee) // set default integration time.
|
||||||
|
d.txWrite8(regPPULSE, 0x04)
|
||||||
|
d.txWrite8(regWTIME, 0xee) // set default wait time.
|
||||||
|
d.txWrite8(regPTIME, 0xff) // set default pulse count.
|
||||||
|
|
||||||
|
var ctlval uint8 = 0b10 << 4 // Use Channel 1 diode.
|
||||||
|
ctlval |= uint8(cfg.LEDDrive&0b11) << 6
|
||||||
|
ctlval |= uint8(cfg.ProxGain&0b11) << 2
|
||||||
|
ctlval |= uint8(cfg.ALSGain & 0b11)
|
||||||
|
d.txWrite8(regCONTROL, ctlval)
|
||||||
|
return d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) Status() (Status, error) {
|
||||||
|
d.txNew()
|
||||||
|
v := d.txRead8(regSTATUS)
|
||||||
|
return Status(v), d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable sets the ENABLE register used primarily to
|
||||||
|
// power the APDS-9930 device on/off, enable functions, and interrupts.
|
||||||
|
// Arguments must be ORed, i.e: d.Enable(EnPower|EnProx); to enable proximity.
|
||||||
|
func (d *Dev) Enable(en Enable) error {
|
||||||
|
en &= 0b01111111 // Seventh bit reserved.
|
||||||
|
d.txNew()
|
||||||
|
d.txWrite8(regENABLE, uint8(en))
|
||||||
|
return d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) enableLightSensor(withInterrupts bool) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) setAmbientLightGain() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) EnableProximity() error {
|
||||||
|
return d.Enable(EnPower | EnALS | EnProx | EnWait)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) proxIntLowThresh() (uint16, error) {
|
||||||
|
d.txNew()
|
||||||
|
return d.txRead16(regPILTL), d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) setProxIntLowThresh(loThresh uint16) error {
|
||||||
|
d.txNew()
|
||||||
|
d.txWrite16(regPILTL, loThresh)
|
||||||
|
return d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) proxIntHighThresh() (uint16, error) {
|
||||||
|
d.txNew()
|
||||||
|
val := d.txRead16(regPIHTL)
|
||||||
|
return val, d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) setProxIntHighThresh(hiThresh uint16) error {
|
||||||
|
d.txNew()
|
||||||
|
d.txWrite16(regPIHTL, hiThresh)
|
||||||
|
return d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) LEDDrive() (Drive, error) {
|
||||||
|
d.txNew()
|
||||||
|
val := (d.txRead8(regCONTROL) >> 6) & 0b11
|
||||||
|
return Drive(val), d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLEDDrive drive strength for proximity and ALS
|
||||||
|
//
|
||||||
|
// Value LED Current
|
||||||
|
// 3 100 mA
|
||||||
|
// 2 50 mA
|
||||||
|
// 1 25 mA
|
||||||
|
// 0 12.5 mA
|
||||||
|
func (d *Dev) SetLEDDrive(drive Drive) error {
|
||||||
|
if drive > 3 {
|
||||||
|
return errInvalidParam
|
||||||
|
}
|
||||||
|
current, err := d.LEDDrive()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Replace LED bits in Control register.
|
||||||
|
current &= 0b00111111
|
||||||
|
current |= drive << 6
|
||||||
|
d.txNew()
|
||||||
|
d.txWrite8(regCONTROL, uint8(current))
|
||||||
|
return d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) proxGain() (uint8, error) {
|
||||||
|
val := d.txRead8(regCONTROL)
|
||||||
|
return (val >> 2) & 0b11, d.txErr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadProximity returns a 10-bit value (0..1023), the higher the value the closer the object
|
||||||
|
func (d *Dev) ReadProximity() uint16 {
|
||||||
|
d.txNew()
|
||||||
|
v := d.txRead16(regPDATAL)
|
||||||
|
if d.txErr() != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) txRead16(addr uint8) uint16 {
|
||||||
|
if d.txErr() != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
d.buf[0] = addr | protoAutoInc
|
||||||
|
d._txerr = d.bus.Tx(d.addr, d.buf[:1], d.buf[1:3])
|
||||||
|
return uint16(d.buf[1]) | uint16(d.buf[2])<<8
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) txRead8(addr uint8) uint8 {
|
||||||
|
if d.txErr() != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
d.buf[0] = addr | protoAutoInc
|
||||||
|
d._txerr = d.bus.Tx(d.addr, d.buf[:1], d.buf[1:2])
|
||||||
|
return d.buf[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) txWrite16(addr uint8, val uint16) {
|
||||||
|
d.txWrite8(addr, uint8(val))
|
||||||
|
d.txWrite8(addr+1, uint8(val>>8))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) txWrite8(reg uint8, val uint8) {
|
||||||
|
if d.txErr() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.buf[0] = reg | 0x80
|
||||||
|
d.buf[1] = val
|
||||||
|
d._txerr = d.bus.Tx(d.addr, d.buf[:2], nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dev) txNew() { d._txerr = nil }
|
||||||
|
|
||||||
|
func (d *Dev) txErr() error { return d._txerr }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package apds9930
|
||||||
|
|
||||||
|
const (
|
||||||
|
protoAutoInc = 0xA0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
regENABLE = 0x00
|
||||||
|
regATIME = 0x01
|
||||||
|
regPTIME = 0x02
|
||||||
|
regWTIME = 0x03
|
||||||
|
regPILTL = 0x08
|
||||||
|
regPILTH = 0x09
|
||||||
|
regPIHTL = 0x0A
|
||||||
|
regPIHTH = 0x0B
|
||||||
|
regCONFIG = 0x0D
|
||||||
|
regPPULSE = 0x0E
|
||||||
|
regCONTROL = 0x0F
|
||||||
|
regSTATUS = 0x13
|
||||||
|
regPDATAL = 0x18
|
||||||
|
regPDATAH = 0x19
|
||||||
|
regPOFFSET = 0x1E
|
||||||
|
)
|
||||||
+2
-2
@@ -218,8 +218,8 @@ func (d *Device) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
func (d *Device) Accept(sockfd int) (int, netip.AddrPort, error) {
|
||||||
return -1, netdev.ErrNotSupported
|
return -1, netip.AddrPort{}, netdev.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
|
func (d *Device) sendChunk(sockfd int, buf []byte, deadline time.Time) (int, error) {
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/apds9930"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Sleep to catch any errors through the serial monitor.
|
||||||
|
time.Sleep(1000 * time.Millisecond)
|
||||||
|
bus := machine.I2C0
|
||||||
|
// use Nano 33 BLE Sense's internal I2C bus
|
||||||
|
err := bus.Configure(machine.I2CConfig{
|
||||||
|
SCL: machine.GP1,
|
||||||
|
SDA: machine.GP0,
|
||||||
|
Frequency: 100 * machine.KHz,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
}
|
||||||
|
sensor := apds9930.New(bus, 0x39)
|
||||||
|
|
||||||
|
err = sensor.Init(apds9930.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = sensor.EnableProximity()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
println("proximity enabled!")
|
||||||
|
for {
|
||||||
|
stat, _ := sensor.Status()
|
||||||
|
if !stat.ProximityAvailable() {
|
||||||
|
time.Sleep(5 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prox := sensor.ReadProximity()
|
||||||
|
println("proximity:", prox)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,16 +30,18 @@ var (
|
|||||||
var buf [1024]byte
|
var buf [1024]byte
|
||||||
|
|
||||||
func echo(conn net.Conn) {
|
func echo(conn net.Conn) {
|
||||||
|
println("Client", conn.RemoteAddr(), "connected")
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
_, err := io.CopyBuffer(conn, conn, buf[:])
|
_, err := io.CopyBuffer(conn, conn, buf[:])
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
println("Client", conn.RemoteAddr(), "closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
link, _ := probe.Probe()
|
link, _ := probe.Probe()
|
||||||
|
|
||||||
@@ -51,6 +53,7 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("Starting TCP server listening on", port)
|
||||||
l, err := net.Listen("tcp", port)
|
l, err := net.Listen("tcp", port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
|||||||
+112
-1
@@ -236,16 +236,83 @@ func (d *Device) getMode() (byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Device) configRate(speed, clock byte) error {
|
func (d *Device) configRate(speed, clock byte) error {
|
||||||
// TODO: add another baudrate
|
|
||||||
var cfg1, cfg2, cfg3 byte
|
var cfg1, cfg2, cfg3 byte
|
||||||
set := true
|
set := true
|
||||||
switch clock {
|
switch clock {
|
||||||
case Clock16MHz:
|
case Clock16MHz:
|
||||||
switch speed {
|
switch speed {
|
||||||
|
case CAN5kBps:
|
||||||
|
cfg1 = mcp16mHz5kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz5kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz5kBpsCfg3
|
||||||
|
case CAN10kBps:
|
||||||
|
cfg1 = mcp16mHz10kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz10kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz10kBpsCfg3
|
||||||
|
case CAN20kBps:
|
||||||
|
cfg1 = mcp16mHz20kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz20kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz20kBpsCfg3
|
||||||
|
case CAN25kBps:
|
||||||
|
cfg1 = mcp16mHz25kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz25kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz25kBpsCfg3
|
||||||
|
case CAN31k25Bps:
|
||||||
|
cfg1 = mcp16mHz31k25BpsCfg1
|
||||||
|
cfg2 = mcp16mHz31k25BpsCfg2
|
||||||
|
cfg3 = mcp16mHz31k25BpsCfg3
|
||||||
|
case CAN33kBps:
|
||||||
|
cfg1 = mcp16mHz33kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz33kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz33kBpsCfg3
|
||||||
|
case CAN40kBps:
|
||||||
|
cfg1 = mcp16mHz40kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz40kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz40kBpsCfg3
|
||||||
|
case CAN47kBps:
|
||||||
|
cfg1 = mcp16mHz47kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz47kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz47kBpsCfg3
|
||||||
|
case CAN50kBps:
|
||||||
|
cfg1 = mcp16mHz50kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz50kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz50kBpsCfg3
|
||||||
|
case CAN80kBps:
|
||||||
|
cfg1 = mcp16mHz80kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz80kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz80kBpsCfg3
|
||||||
|
case CAN83k3Bps:
|
||||||
|
cfg1 = mcp16mHz83k3BpsCfg1
|
||||||
|
cfg2 = mcp16mHz83k3BpsCfg2
|
||||||
|
cfg3 = mcp16mHz83k3BpsCfg3
|
||||||
|
case CAN95kBps:
|
||||||
|
cfg1 = mcp16mHz95kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz95kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz95kBpsCfg3
|
||||||
|
case CAN100kBps:
|
||||||
|
cfg1 = mcp16mHz100kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz100kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz100kBpsCfg3
|
||||||
|
case CAN125kBps:
|
||||||
|
cfg1 = mcp16mHz125kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz125kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz125kBpsCfg3
|
||||||
|
case CAN200kBps:
|
||||||
|
cfg1 = mcp16mHz200kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz200kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz200kBpsCfg3
|
||||||
|
case CAN250kBps:
|
||||||
|
cfg1 = mcp16mHz250kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz250kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz250kBpsCfg3
|
||||||
case CAN500kBps:
|
case CAN500kBps:
|
||||||
cfg1 = mcp16mHz500kBpsCfg1
|
cfg1 = mcp16mHz500kBpsCfg1
|
||||||
cfg2 = mcp16mHz500kBpsCfg2
|
cfg2 = mcp16mHz500kBpsCfg2
|
||||||
cfg3 = mcp16mHz500kBpsCfg3
|
cfg3 = mcp16mHz500kBpsCfg3
|
||||||
|
case CAN666kBps:
|
||||||
|
cfg1 = mcp16mHz666kBpsCfg1
|
||||||
|
cfg2 = mcp16mHz666kBpsCfg2
|
||||||
|
cfg3 = mcp16mHz666kBpsCfg3
|
||||||
case CAN1000kBps:
|
case CAN1000kBps:
|
||||||
cfg1 = mcp16mHz1000kBpsCfg1
|
cfg1 = mcp16mHz1000kBpsCfg1
|
||||||
cfg2 = mcp16mHz1000kBpsCfg2
|
cfg2 = mcp16mHz1000kBpsCfg2
|
||||||
@@ -255,6 +322,50 @@ func (d *Device) configRate(speed, clock byte) error {
|
|||||||
}
|
}
|
||||||
case Clock8MHz:
|
case Clock8MHz:
|
||||||
switch speed {
|
switch speed {
|
||||||
|
case CAN5kBps:
|
||||||
|
cfg1 = mcp8mHz5kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz5kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz5kBpsCfg3
|
||||||
|
case CAN10kBps:
|
||||||
|
cfg1 = mcp8mHz10kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz10kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz10kBpsCfg3
|
||||||
|
case CAN20kBps:
|
||||||
|
cfg1 = mcp8mHz20kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz20kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz20kBpsCfg3
|
||||||
|
case CAN31k25Bps:
|
||||||
|
cfg1 = mcp8mHz31k25BpsCfg1
|
||||||
|
cfg2 = mcp8mHz31k25BpsCfg2
|
||||||
|
cfg3 = mcp8mHz31k25BpsCfg3
|
||||||
|
case CAN40kBps:
|
||||||
|
cfg1 = mcp8mHz40kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz40kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz40kBpsCfg3
|
||||||
|
case CAN50kBps:
|
||||||
|
cfg1 = mcp8mHz50kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz50kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz50kBpsCfg3
|
||||||
|
case CAN80kBps:
|
||||||
|
cfg1 = mcp8mHz80kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz80kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz80kBpsCfg3
|
||||||
|
case CAN100kBps:
|
||||||
|
cfg1 = mcp8mHz100kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz100kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz100kBpsCfg3
|
||||||
|
case CAN125kBps:
|
||||||
|
cfg1 = mcp8mHz125kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz125kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz125kBpsCfg3
|
||||||
|
case CAN200kBps:
|
||||||
|
cfg1 = mcp8mHz200kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz200kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz200kBpsCfg3
|
||||||
|
case CAN250kBps:
|
||||||
|
cfg1 = mcp8mHz250kBpsCfg1
|
||||||
|
cfg2 = mcp8mHz250kBpsCfg2
|
||||||
|
cfg3 = mcp8mHz250kBpsCfg3
|
||||||
case CAN500kBps:
|
case CAN500kBps:
|
||||||
cfg1 = mcp8mHz500kBpsCfg1
|
cfg1 = mcp8mHz500kBpsCfg1
|
||||||
cfg2 = mcp8mHz500kBpsCfg2
|
cfg2 = mcp8mHz500kBpsCfg2
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ type Netdever interface {
|
|||||||
Bind(sockfd int, ip netip.AddrPort) error
|
Bind(sockfd int, ip netip.AddrPort) error
|
||||||
Connect(sockfd int, host string, ip netip.AddrPort) error
|
Connect(sockfd int, host string, ip netip.AddrPort) error
|
||||||
Listen(sockfd int, backlog int) error
|
Listen(sockfd int, backlog int) error
|
||||||
Accept(sockfd int, ip netip.AddrPort) (int, error)
|
Accept(sockfd int) (int, netip.AddrPort, error)
|
||||||
Send(sockfd int, buf []byte, flags int, deadline time.Time) (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)
|
Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
|
||||||
Close(sockfd int) error
|
Close(sockfd int) error
|
||||||
|
|||||||
@@ -70,54 +70,6 @@ func (img Image[T]) LimitHeight(height int) Image[T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the buffer into two buffers that can be used independently.
|
|
||||||
// The top half is split just like LimitHeight. The bottom half is made out of
|
|
||||||
// the remaining buffer area and can be zero. The topHeight parameter must not
|
|
||||||
// be larger than the height of the buffer.
|
|
||||||
//
|
|
||||||
// Always check the height of the bottom half: it may be zero due to alignment
|
|
||||||
// issues.
|
|
||||||
func (img Image[T]) Split(topHeight int) (top, bottom Image[T]) {
|
|
||||||
if topHeight < 0 || topHeight > int(img.height) {
|
|
||||||
panic("Image.Split: out of bounds")
|
|
||||||
}
|
|
||||||
|
|
||||||
// The top half of the buffer, the same as LimitHeight.
|
|
||||||
top = Image[T]{
|
|
||||||
width: img.width,
|
|
||||||
height: int16(topHeight),
|
|
||||||
data: img.data,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the bottom half of the buffer.
|
|
||||||
// This is a bit more complicated since it's possible that the bottom half
|
|
||||||
// can't have all the other bytes: the top half pixels might cross a byte
|
|
||||||
// boundary (for example with RGB444). So instead we calculate the size of
|
|
||||||
// the buffer we have, the size of the buffer that the top half will use
|
|
||||||
// (which is rounded up to a byte boundary), and then calculate the
|
|
||||||
// remaining bytes at the bottom.
|
|
||||||
// In practice, I expect it's unlikely that the top half will cross a byte
|
|
||||||
// boundary since a typical split buffer will have a width that's a nice
|
|
||||||
// round number, but it's possible so we have to avoid this edge case.
|
|
||||||
var zeroColor T
|
|
||||||
dataBytes := (int(img.width)*int(img.height)*zeroColor.BitsPerPixel() + 7) / 8
|
|
||||||
topDataBytes := (int(img.width)*int(topHeight)*zeroColor.BitsPerPixel() + 7) / 8
|
|
||||||
bottomDataBytes := dataBytes - topDataBytes
|
|
||||||
if bottomDataBytes < 0 {
|
|
||||||
// No buffer remaining (not sure whether this is possible in practice
|
|
||||||
// but guarding just in case).
|
|
||||||
bottomDataBytes = 0
|
|
||||||
}
|
|
||||||
bottomHeight := (bottomDataBytes * 8 / zeroColor.BitsPerPixel()) / int(img.width)
|
|
||||||
bottom = Image[T]{
|
|
||||||
width: img.width,
|
|
||||||
height: int16(bottomHeight),
|
|
||||||
data: unsafe.Add(img.data, topDataBytes),
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of pixels in this image buffer.
|
// Len returns the number of pixels in this image buffer.
|
||||||
func (img Image[T]) Len() int {
|
func (img Image[T]) Len() int {
|
||||||
return int(img.width) * int(img.height)
|
return int(img.width) * int(img.height)
|
||||||
|
|||||||
+20
-6
@@ -437,6 +437,12 @@ func ipToName(ip netip.AddrPort) []byte {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nameToIp(name []byte) netip.AddrPort {
|
||||||
|
port := uint16(name[2])<<8 | uint16(name[3])
|
||||||
|
addr, _ := netip.AddrFromSlice(name[4:8])
|
||||||
|
return netip.AddrPortFrom(addr, port)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *rtl8720dn) Bind(sockfd int, ip netip.AddrPort) error {
|
func (r *rtl8720dn) Bind(sockfd int, ip netip.AddrPort) error {
|
||||||
|
|
||||||
if debugging(debugNetdev) {
|
if debugging(debugNetdev) {
|
||||||
@@ -534,10 +540,10 @@ func (r *rtl8720dn) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rtl8720dn) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
func (r *rtl8720dn) Accept(sockfd int) (int, netip.AddrPort, error) {
|
||||||
|
|
||||||
if debugging(debugNetdev) {
|
if debugging(debugNetdev) {
|
||||||
fmt.Printf("[Accept] sockfd: %d, peer: %s\r\n", sockfd, ip)
|
fmt.Printf("[Accept] sockfd: %d\r\n", sockfd)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.mu.Lock()
|
r.mu.Lock()
|
||||||
@@ -546,12 +552,12 @@ func (r *rtl8720dn) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
var newSock int32
|
var newSock int32
|
||||||
var lsock = sock(sockfd)
|
var lsock = sock(sockfd)
|
||||||
var socket = r.sockets[lsock]
|
var socket = r.sockets[lsock]
|
||||||
var name = ipToName(ip)
|
var name = ipToName(netip.AddrPort{})
|
||||||
|
|
||||||
switch socket.protocol {
|
switch socket.protocol {
|
||||||
case netdev.IPPROTO_TCP:
|
case netdev.IPPROTO_TCP:
|
||||||
default:
|
default:
|
||||||
return -1, netdev.ErrProtocolNotSupported
|
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -570,6 +576,14 @@ func (r *rtl8720dn) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get remote peer ip:port
|
||||||
|
namelen = uint32(len(name))
|
||||||
|
result := r.rpc_lwip_getpeername(int32(newSock), name, &namelen)
|
||||||
|
if result == -1 {
|
||||||
|
return -1, netip.AddrPort{}, fmt.Errorf("Getpeername failed")
|
||||||
|
}
|
||||||
|
raddr := nameToIp(name)
|
||||||
|
|
||||||
// If we've already seen this socket, we can re-use
|
// If we've already seen this socket, we can re-use
|
||||||
// the socket and return it. But, only if the socket
|
// the socket and return it. But, only if the socket
|
||||||
// is closed. If it's not closed, we'll just come back
|
// is closed. If it's not closed, we'll just come back
|
||||||
@@ -582,12 +596,12 @@ func (r *rtl8720dn) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Reuse client socket
|
// Reuse client socket
|
||||||
return int(newSock), nil
|
return int(newSock), raddr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new socket for client and return fd
|
// Create new socket for client and return fd
|
||||||
r.sockets[sock(newSock)] = newSocket(socket.protocol)
|
r.sockets[sock(newSock)] = newSocket(socket.protocol)
|
||||||
return int(newSock), nil
|
return int(newSock), raddr, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,12 +11,3 @@ type SPI interface {
|
|||||||
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
// If you want to transfer multiple bytes, it is more efficient to use Tx instead.
|
||||||
Transfer(b byte) (byte, error)
|
Transfer(b byte) (byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsyncSPI is a SPI bus that also implements async operations (using DMA,
|
|
||||||
// probably).
|
|
||||||
type AsyncSPI interface {
|
|
||||||
SPI
|
|
||||||
IsAsync() bool
|
|
||||||
StartTx(tx, rx []byte) error
|
|
||||||
Wait() error
|
|
||||||
}
|
|
||||||
|
|||||||
+3
-48
@@ -45,7 +45,7 @@ type Device = DeviceOf[pixel.RGB565BE]
|
|||||||
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
// DeviceOf is a generic version of Device. It supports multiple different pixel
|
||||||
// formats.
|
// formats.
|
||||||
type DeviceOf[T Color] struct {
|
type DeviceOf[T Color] struct {
|
||||||
bus drivers.AsyncSPI
|
bus drivers.SPI
|
||||||
dcPin machine.Pin
|
dcPin machine.Pin
|
||||||
resetPin machine.Pin
|
resetPin machine.Pin
|
||||||
csPin machine.Pin
|
csPin machine.Pin
|
||||||
@@ -83,13 +83,13 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
// New creates a new ST7789 connection. The SPI wire must already be configured.
|
||||||
func New(bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
func New(bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) Device {
|
||||||
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
return NewOf[pixel.RGB565BE](bus, resetPin, dcPin, csPin, blPin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
// NewOf creates a new ST7789 connection with a particular pixel format. The SPI
|
||||||
// wire must already be configured.
|
// wire must already be configured.
|
||||||
func NewOf[T Color](bus drivers.AsyncSPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
func NewOf[T Color](bus drivers.SPI, resetPin, dcPin, csPin, blPin machine.Pin) DeviceOf[T] {
|
||||||
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
dcPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
resetPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
csPin.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
@@ -404,51 +404,6 @@ func (d *DeviceOf[T]) DrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
|||||||
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
return d.DrawRGBBitmap8(x, y, bitmap.RawBuffer(), int16(width), int16(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAsync returns whether the underlying SPI bus supports async operations.
|
|
||||||
func (d *DeviceOf[T]) IsAsync() bool {
|
|
||||||
return d.bus.IsAsync()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartDrawBitmap starts sending the given bitmap to the screen.
|
|
||||||
// After calling StartDrawBitmap, you can only call Wait() or another
|
|
||||||
// StartDrawBitmap. Calling any other method may result in incorrect behavior.
|
|
||||||
// The bitmap passed to StartDrawBitmap may not be written to until Wait() has
|
|
||||||
// been called.
|
|
||||||
func (d *DeviceOf[T]) StartDrawBitmap(x, y int16, bitmap pixel.Image[T]) error {
|
|
||||||
// Check that the provided buffer is drawn entirely inside the image.
|
|
||||||
width, height := bitmap.Size()
|
|
||||||
displayWidth, displayHeight := d.Size()
|
|
||||||
if uint(int(x)+width) > uint(int(displayWidth)) || uint(int(y)+height) > uint(int(displayHeight)) {
|
|
||||||
return errOutOfBounds
|
|
||||||
}
|
|
||||||
if width <= 0 || height <= 0 {
|
|
||||||
return nil // no bitmap to send
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the previous buffer has been fully sent.
|
|
||||||
err := d.bus.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the next buffer.
|
|
||||||
d.startWrite()
|
|
||||||
d.setWindow(x, y, int16(width), int16(height))
|
|
||||||
d.bus.StartTx(bitmap.RawBuffer(), nil)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until all previous transfers have completed. After this call, the bitmap
|
|
||||||
// passed to StartDrawBitmap can be reused.
|
|
||||||
func (d *DeviceOf[T]) Wait() error {
|
|
||||||
err := d.bus.Wait()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.endWrite()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
// FillRectangleWithBuffer fills buffer with a rectangle at a given coordinates.
|
||||||
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
func (d *DeviceOf[T]) FillRectangleWithBuffer(x, y, width, height int16, buffer []color.RGBA) error {
|
||||||
i, j := d.Size()
|
i, j := d.Size()
|
||||||
|
|||||||
+25
-6
@@ -676,10 +676,10 @@ func (w *wifinina) Listen(sockfd int, backlog int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
func (w *wifinina) Accept(sockfd int) (int, netip.AddrPort, error) {
|
||||||
|
|
||||||
if debugging(debugNetdev) {
|
if debugging(debugNetdev) {
|
||||||
fmt.Printf("[Accept] sockfd: %d, peer: %s\r\n", sockfd, ip)
|
fmt.Printf("[Accept] sockfd: %d\r\n", sockfd)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
@@ -692,7 +692,7 @@ func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
switch socket.protocol {
|
switch socket.protocol {
|
||||||
case netdev.IPPROTO_TCP:
|
case netdev.IPPROTO_TCP:
|
||||||
default:
|
default:
|
||||||
return -1, netdev.ErrProtocolNotSupported
|
return -1, netip.AddrPort{}, netdev.ErrProtocolNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
@@ -704,7 +704,7 @@ func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
|
|
||||||
// Check if we've faulted
|
// Check if we've faulted
|
||||||
if w.fault != nil {
|
if w.fault != nil {
|
||||||
return -1, w.fault
|
return -1, netip.AddrPort{}, w.fault
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: BUG: Currently, a sock that is 100% busy will always be
|
// TODO: BUG: Currently, a sock that is 100% busy will always be
|
||||||
@@ -720,6 +720,8 @@ func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raddr := w.getRemoteData(client)
|
||||||
|
|
||||||
// If we've already seen this socket, we can reuse
|
// If we've already seen this socket, we can reuse
|
||||||
// the socket and return it. But, only if the socket
|
// the socket and return it. But, only if the socket
|
||||||
// is closed. If it's not closed, we'll just come back
|
// is closed. If it's not closed, we'll just come back
|
||||||
@@ -732,12 +734,12 @@ func (w *wifinina) Accept(sockfd int, ip netip.AddrPort) (int, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Reuse client socket
|
// Reuse client socket
|
||||||
return int(client), nil
|
return int(client), raddr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new socket for client and return fd
|
// Create new socket for client and return fd
|
||||||
w.sockets[client] = newSocket(socket.protocol)
|
w.sockets[client] = newSocket(socket.protocol)
|
||||||
return int(client), nil
|
return int(client), raddr, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1123,6 +1125,23 @@ func (w *wifinina) accept(s sock) sock {
|
|||||||
return newsock
|
return newsock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *wifinina) getRemoteData(s sock) netip.AddrPort {
|
||||||
|
|
||||||
|
if debugging(debugCmd) {
|
||||||
|
fmt.Printf(" [cmdGetRemoteData] sock: %d\r\n", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
sl := make([]string, 2)
|
||||||
|
l := w.reqRspStr1(cmdGetRemoteData, uint8(s), sl)
|
||||||
|
if l != 2 {
|
||||||
|
w.faultf("getRemoteData wanted l=2, got l=%d", l)
|
||||||
|
return netip.AddrPort{}
|
||||||
|
}
|
||||||
|
ip, _ := netip.AddrFromSlice([]byte(sl[0])[:4])
|
||||||
|
port := binary.BigEndian.Uint16([]byte(sl[1]))
|
||||||
|
return netip.AddrPortFrom(ip, port)
|
||||||
|
}
|
||||||
|
|
||||||
// insertDataBuf adds data to the buffer used for sending UDP data
|
// insertDataBuf adds data to the buffer used for sending UDP data
|
||||||
func (w *wifinina) insertDataBuf(sock sock, buf []byte) bool {
|
func (w *wifinina) insertDataBuf(sock sock, buf []byte) bool {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user